diff --git a/applications/blackhole/src/blackhole.hrl b/applications/blackhole/src/blackhole.hrl
index 2808f0a8517..d56cc3e1797 100644
--- a/applications/blackhole/src/blackhole.hrl
+++ b/applications/blackhole/src/blackhole.hrl
@@ -23,8 +23,6 @@
,'bh_authz_subscribe'
]).
--define(VERSION_SUPPORTED, [<<"v1">>]).
-
-type bh_subscribe_result() :: {'ok', bh_context:context()} | {'error', kz_term:ne_binary()}.
-record(bh_context, {auth_token = <<>> :: kz_term:api_binary() | '_'
diff --git a/applications/cccp/doc/usage.md b/applications/cccp/doc/usage.md
index 902a71fc84c..e5e7991e077 100644
--- a/applications/cccp/doc/usage.md
+++ b/applications/cccp/doc/usage.md
@@ -23,17 +23,17 @@
####Add PIN
- curl -X PUT -H X-Auth-Token:{AUTH_TOKEN} https://{SERVER}:8443/v1/accounts/{ACCOUNT_ID}/cccps -d '{"data":{"pin":"150674729083", "user_id":"e6da57c768533ebf0d349845394ccf26", "active":true, "cid_retain": false}}'
+ curl -X PUT -H X-Auth-Token:{AUTH_TOKEN} https://{SERVER}:8443/v2/accounts/{ACCOUNT_ID}/cccps -d '{"data":{"pin":"150674729083", "user_id":"e6da57c768533ebf0d349845394ccf26", "active":true, "cid_retain": false}}'
####Add CID
- curl -X PUT -H X-Auth-Token:{AUTH_TOKEN} https://{SERVER}:8443/v1/accounts/{ACCOUNT_ID}/cccps -d '{"data":{"cid":"78121234567", "user_id":"e6da57c768533ebf0d349845394ccf26", "active":true, "cid_retain": true}}'
+ curl -X PUT -H X-Auth-Token:{AUTH_TOKEN} https://{SERVER}:8443/v2/accounts/{ACCOUNT_ID}/cccps -d '{"data":{"cid":"78121234567", "user_id":"e6da57c768533ebf0d349845394ccf26", "active":true, "cid_retain": true}}'
####Delete CID/PIN
- curl -X DELETE -H X-Auth-Token:{AUTH_TOKEN} https://{SERVER}:8443/v1/accounts/{ACCOUNT_ID}/cccps/{DOC_ID}
+ curl -X DELETE -H X-Auth-Token:{AUTH_TOKEN} https://{SERVER}:8443/v2/accounts/{ACCOUNT_ID}/cccps/{DOC_ID}
####Call initiation over API:
- curl -X PUT -H X-Auth-Token:{AUTH_TOKEN} https://{SERVER}:8443/v1/accounts/{ACCOUNT_ID}/cccps/autodial -d '{"data": { "a_leg_number": "1234567", "b_leg_number": "5579", "callback_delay": 10, "cid_retain": true, "media_id": "74c3e22b5dd9ff473de4ba2aea4e4183"}}'
- curl -X PUT -H X-Auth-Token:{AUTH_TOKEN} https://{SERVER}:8443/v1/accounts/{ACCOUNT_ID}/cccps/autodial -d '{"data": { "a_leg_number": "1234567", "b_leg_number": "{CONFERENCE_ID}", "media_id": "74c3e22b5dd9ff473de4ba2aea4e4183"}}'
+ curl -X PUT -H X-Auth-Token:{AUTH_TOKEN} https://{SERVER}:8443/v2/accounts/{ACCOUNT_ID}/cccps/autodial -d '{"data": { "a_leg_number": "1234567", "b_leg_number": "5579", "callback_delay": 10, "cid_retain": true, "media_id": "74c3e22b5dd9ff473de4ba2aea4e4183"}}'
+ curl -X PUT -H X-Auth-Token:{AUTH_TOKEN} https://{SERVER}:8443/v2/accounts/{ACCOUNT_ID}/cccps/autodial -d '{"data": { "a_leg_number": "1234567", "b_leg_number": "{CONFERENCE_ID}", "media_id": "74c3e22b5dd9ff473de4ba2aea4e4183"}}'
diff --git a/applications/crossbar/doc/basics.md b/applications/crossbar/doc/basics.md
index 68f8ebb4b79..eadb4dcfff5 100644
--- a/applications/crossbar/doc/basics.md
+++ b/applications/crossbar/doc/basics.md
@@ -14,9 +14,7 @@ Requests Crossbar follows this structure:
Here the explanation:
-* `{VERSION}` - The version of the API you are calling.
- * `v1` - Most APIs respond on the `v1`
- * `v2` - A select number of APIs have newer behaviour. If you used the its `v1` version, it will work as before.
+* `{VERSION}` - The version of the API you are calling. Currently the only support value is `v2`.
* `{ACCOUNT_ID}` - Most requests operate against a specific account and thus require the `account_id` to route the request properly
* `{RESOURCE_ID}` - When accessing a specific resource, like a device, user, or callflow, this is the `{RESOURCE_ID}` points to the specific instance you're accessing.
@@ -151,7 +149,7 @@ When receiving JSON responses, clients will receive the response in an envelope.
## Pagination
-All listing APIs in `v2` will be paginated by default (`v1` will operate as before without pagination).
+All listing APIs will be paginated by default.
Let's take a look at the CDRs API to see how to interpret pagination.
diff --git a/applications/crossbar/doc/bulk.md b/applications/crossbar/doc/bulk.md
deleted file mode 100644
index 5dec4914ecb..00000000000
--- a/applications/crossbar/doc/bulk.md
+++ /dev/null
@@ -1,31 +0,0 @@
-### Bulk
-
-#### About Bulk
-
-#### Schema
-
-
-
-#### Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/bulk
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- -d '{"data": {"ids": ["{ID1}", "{ID2}", "{ID3}"]}}' \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/bulk
-```
-
-```json
-{
- "auth_token": "{AUTH_TOKEN}",
- "data": [
- ...
- ],
- "page_size": 0,
- "request_id": "{REQUEST_ID}",
- "revision": "{REVISION}",
- "status": "success"
-}
-```
diff --git a/applications/crossbar/doc/configuration.md b/applications/crossbar/doc/configuration.md
index bb3ef2c1a36..b3fc84770e3 100644
--- a/applications/crossbar/doc/configuration.md
+++ b/applications/crossbar/doc/configuration.md
@@ -49,14 +49,10 @@ Some modules use the `crossbar` namespace to create a specific `system_config` d
##### `crossbar.cdrs`
##### `crossbar.devices`
##### `crossbar.fax`
-##### `crossbar.freeswitch`
-##### `crossbar.local_resources`
##### `crossbar.media`
##### `crossbar.notifications`
-##### `crossbar.onboard`
##### `crossbar.port_requests`
##### `crossbar.presence`
-##### `crossbar.provisioner_templates`
##### `crossbar.queues`
##### `crossbar.resource_selectors`
##### `crossbar.resource_templates`
diff --git a/applications/crossbar/doc/freeswitch.md b/applications/crossbar/doc/freeswitch.md
deleted file mode 100644
index de880495a33..00000000000
--- a/applications/crossbar/doc/freeswitch.md
+++ /dev/null
@@ -1,10 +0,0 @@
-### Freeswitch
-
-#### About Freeswitch
-
-#### Schema
-
-
-
-#### Fetch
-
diff --git a/applications/crossbar/doc/global_provisioner_templates.md b/applications/crossbar/doc/global_provisioner_templates.md
deleted file mode 100644
index 11dc1ddf259..00000000000
--- a/applications/crossbar/doc/global_provisioner_templates.md
+++ /dev/null
@@ -1,87 +0,0 @@
-### Global Provisioner Templates
-
-#### About Global Provisioner Templates
-
-#### Schema
-
-
-
-#### Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
-```
-
-#### Create
-
-> PUT /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
-```
-
-#### Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-```
-
-#### Change
-
-> POST /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-```
-
-#### Remove
-
-> DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-```
-
-#### Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-```
-
-#### Change
-
-> POST /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-```
-
-#### Remove
-
-> DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-```
diff --git a/applications/crossbar/doc/limits.md b/applications/crossbar/doc/limits.md
index bb114b50989..ca67a31b5bd 100644
--- a/applications/crossbar/doc/limits.md
+++ b/applications/crossbar/doc/limits.md
@@ -51,36 +51,6 @@ curl -v -X GET \
> POST /v2/accounts/{ACCOUNT_ID}/limits
-First using API v1 (simplest):
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- -d '{"data": {
- "twoway_trunks": 0,
- "inbound_trunks": 11,
- "id": "limits",
- "allow_prepay": true,
- "outbound_trunks": 5
- }}' \
- http://{SERVER}:8000/v1/accounts/{ACCOUNT_ID}/limits
-```
-
-```json
-{
- "data": {
- "twoway_trunks": 0,
- "inbound_trunks": 11,
- "id": "limits",
- "allow_prepay": true,
- "outbound_trunks": 5
- },
- "status": "success",
-}
-```
-
-Now with API v2:
-
```shell
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
diff --git a/applications/crossbar/doc/lists.md b/applications/crossbar/doc/lists.md
index 4d8ecebebee..768d3633d4f 100644
--- a/applications/crossbar/doc/lists.md
+++ b/applications/crossbar/doc/lists.md
@@ -186,30 +186,3 @@ curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}/vcard
```
-
-
-#### v1 examples.
-
-##### Get lists and their entries
- curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists
-
-##### Create new list
- curl -v -X PUT -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists -d '{"data": {"name": "List name"}}'
-
-##### Get list with LIST_ID
- curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
-
-##### Add new entry to list
- curl -v -X PUT -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID} -d '{"data": {"pattern": "345"}}'
-
-##### Delete list
- curl -v -X DELETE -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
-
-##### Get entry {LIST_ENTRY_ID} from list {LIST_ID}
- curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/{LIST_ENTRY_ID}
-
-##### Rewrite entry {LIST_ENTRY_ID} in list {LIST_ID}
- curl -v -X POST -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/{LIST_ENTRY_ID} -d "{"data": {"132", "321"}}"
-
-##### Delete entry from list
- curl -v -X DELETE -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}
diff --git a/applications/crossbar/doc/local_provisioner_templates.md b/applications/crossbar/doc/local_provisioner_templates.md
deleted file mode 100644
index 77058d49a0f..00000000000
--- a/applications/crossbar/doc/local_provisioner_templates.md
+++ /dev/null
@@ -1,87 +0,0 @@
-### Local Provisioner Templates
-
-#### About Local Provisioner Templates
-
-#### Schema
-
-
-
-#### Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
-```
-
-#### Create
-
-> PUT /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
-```
-
-#### Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-```
-
-#### Change
-
-> POST /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-```
-
-#### Remove
-
-> DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-```
-
-#### Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-```
-
-#### Change
-
-> POST /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-```
-
-#### Remove
-
-> DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-```
diff --git a/applications/crossbar/doc/onboard.md b/applications/crossbar/doc/onboard.md
deleted file mode 100644
index b49411b2705..00000000000
--- a/applications/crossbar/doc/onboard.md
+++ /dev/null
@@ -1,10 +0,0 @@
-### Onboard
-
-#### About Onboard
-
-#### Schema
-
-
-
-#### Create
-
diff --git a/applications/crossbar/doc/onboarding.md b/applications/crossbar/doc/onboarding.md
deleted file mode 100644
index a3da26c7592..00000000000
--- a/applications/crossbar/doc/onboarding.md
+++ /dev/null
@@ -1,160 +0,0 @@
-### Onboarding
-
-Used to create new accounts without being signed in.
-
-#### NOTICE
-
-This API has been deprecated and is no longer maintained by the 2600Hz core team. The preferred method would be to code your own middleware to create accounts using an appropriate parent account API key or auth-token. The PHP SDK is an excellent starting point or you can roll your own!
-
-#### An example request
-
-Taken from https://2600hz.atlassian.net/browse/KAZOO-63
-
-PUT to `/v1/onboard`
-
-```
-{
- "data": {
- "account": {
- "available_apps": [
- "voip",
- "cluster",
- "userportal",
- "accounts",
- "developer",
- "numbers",
- "pbxs"
- ],
- "caller_id": {
- "default": {
- "number": "{COMPANY_PRIMARY_CALLERID}"
- },
- "emergency": {
- "number": "{COMPANY_EMERGENCY_CALLERID}"
- }
- },
- "default_api_url": "http://{SERVER}/v1",
- "name": "{COMPANY_NAME}",
- "role": "{ACCOUNT_TYPE}"
- },
- "braintree": {
- "company": "{COMPANY_NAME}",
- "credit_card": {
- "billing_address": {
- "country": "{COMPANY_COUNTRY}",
- "extended_address": "{COMPANY_EXTENDED_ADDRESS}",
- "first_name": "{BILLING_CONTACT_FIRST_NAME}",
- "last_name": "{BILLING_CONTACT_LAST_NAME}",
- "locality": "{COMPANY_CITY}",
- "postal_code": "{COMPANY_ZIP_CODE}",
- "region": "{COMPANY_STATE}",
- "street_address": "{COMPANY_ADDRESS}"
- },
- "cardholder_name": "{CREDIT_CARD_HOLDER_NAME}",
- "cvv": "{CREDIT_CARD_SECURITY_CODE}",
- "expiration_date": "{CREDIT_CARD_EXPIRATION}",
- "make_default": true,
- "number": "{CREDIT_CARD_NUMBER}"
- },
- "email": "{ADMIN_EMAIL}",
- "first_name": "{ADMIN_FIRST_NAME}",
- "last_name": "{ADMIN_LAST_NAME}"
- },
- "extensions": [
- {
- "callflow": {
- "numbers": [
- "{ADMIN_DID}",
- "{ADMIN_EXTENSION_NUMBER}"
- ]
- },
- "user": {
- "apps": {
- "accounts": {
- "api_url": "http://{SERVER}:8000/v1",
- "icon": "account",
- "label": "Accounts"
- },
- "numbers": {
- "api_url": "http://{SERVER}:8000/v1",
- "icon": "menu",
- "label": "Number Manager"
- },
- "voip": {
- "api_url": "http://{SERVER}:8000/v1",
- "icon": "phone",
- "label": "Hosted PBX"
- }
- },
- "credentials": "a9e4685a973f0ed2844ee9f36e211736",
- "email": "{ADMIN_EMAIL}",
- "first_name": "{ADMIN_FIRST_NAME}",
- "last_name": "{ADMIN_LAST_NAME}",
- "priv_level": "admin"
- }
- },
- {
- "callflow": {
- "numbers": [
- "{USER1_EXTENSION_NUMBER}"
- ]
- },
- "user": {
- "first_name": "{USER1_FIRST_NAME}",
- "last_name": "{USER1_LAST_NAME}",
- "priv_level": "user"
- }
- },
- {
- "callflow": {
- "numbers": [
- "{USER2_EXTENSION_NUMBER}"
- ]
- },
- "user": {
- "first_name": "{USER2_FIRST_NAME}",
- "last_name": "{USER2_LAST_NAME}",
- "priv_level": "user"
- }
- },
- {
- "callflow": {
- "numbers": [
- "{USER3_EXTENSION_NUMBER}"
- ]
- },
- "user": {
- "first_name": "{USER3_FIRST_NAME}",
- "last_name": "{USER4_LAST_NAME}",
- "priv_level": "user"
- }
- },
- {
- "callflow": {
- "numbers": [
- "{USER4_EXTENSION_NUMBER}"
- ]
- },
- "user": {
- "first_name": "{USER4_FIRST_NAME}",
- "last_name": "{USER4_LAST_NAME}",
- "priv_level": "user"
- }
- }
- ],
- "invite_code": "9351b14aa94b9d580dea57b8deefff0c",
- "phone_numbers": {
- "{ADMIN_EXTENSION_NUMBER}": {
- "e911": {
- "extended_address": "{ADMIN_EXTENDED_ADDRESS}",
- "locality": "{ADMIN_CITY}",
- "postal_code": "{ADMIN_ZIP_CODE}",
- "region": "{ADMIN_STATE}",
- "street_address": "{ADMIN_ADDRESS}"
- }
- }
- }
- },
- "verb": "PUT"
-}
-```
diff --git a/applications/crossbar/doc/queues.md b/applications/crossbar/doc/queues.md
index 26ea9578945..5854d2fcd8e 100644
--- a/applications/crossbar/doc/queues.md
+++ b/applications/crossbar/doc/queues.md
@@ -270,4 +270,4 @@ curl -v -X GET \
##### Set the queue roster
- curl -v -X POST -H "X-Auth-Token: {AUTH_TOKEN}" -H "Content-Type: application/json" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster -d '{"data": ["f3ced8ea7bccc352a2124e8a34351e81", "e154a97ec2942599865a1591a477fd19"]}'
+ curl -v -X POST -H "X-Auth-Token: {AUTH_TOKEN}" -H "Content-Type: application/json" http://server.com:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster -d '{"data": ["f3ced8ea7bccc352a2124e8a34351e81", "e154a97ec2942599865a1591a477fd19"]}'
diff --git a/applications/crossbar/doc/ref/bulk.md b/applications/crossbar/doc/ref/bulk.md
deleted file mode 100644
index 5b59435867b..00000000000
--- a/applications/crossbar/doc/ref/bulk.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# Bulk
-
-## About Bulk
-
-## Schema
-
-
-
-## Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/bulk
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/bulk
-```
-
-## Change
-
-> POST /v2/accounts/{ACCOUNT_ID}/bulk
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/bulk
-```
-
-## Remove
-
-> DELETE /v2/accounts/{ACCOUNT_ID}/bulk
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/bulk
-```
-
diff --git a/applications/crossbar/doc/ref/freeswitch.md b/applications/crossbar/doc/ref/freeswitch.md
deleted file mode 100644
index 0ae8323b815..00000000000
--- a/applications/crossbar/doc/ref/freeswitch.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Freeswitch
-
-## About Freeswitch
-
-## Schema
-
-
-
-## Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/freeswitch
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/freeswitch
-```
-
diff --git a/applications/crossbar/doc/ref/global_provisioner_templates.md b/applications/crossbar/doc/ref/global_provisioner_templates.md
deleted file mode 100644
index b1dfc152dd9..00000000000
--- a/applications/crossbar/doc/ref/global_provisioner_templates.md
+++ /dev/null
@@ -1,88 +0,0 @@
-# Global Provisioner Templates
-
-## About Global Provisioner Templates
-
-## Schema
-
-
-
-## Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
-```
-
-## Create
-
-> PUT /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
-```
-
-## Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-```
-
-## Change
-
-> POST /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-```
-
-## Remove
-
-> DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
-```
-
-## Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-```
-
-## Change
-
-> POST /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-```
-
-## Remove
-
-> DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
-```
-
diff --git a/applications/crossbar/doc/ref/local_provisioner_templates.md b/applications/crossbar/doc/ref/local_provisioner_templates.md
deleted file mode 100644
index 62a1ccb1bb6..00000000000
--- a/applications/crossbar/doc/ref/local_provisioner_templates.md
+++ /dev/null
@@ -1,88 +0,0 @@
-# Local Provisioner Templates
-
-## About Local Provisioner Templates
-
-## Schema
-
-
-
-## Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
-```
-
-## Create
-
-> PUT /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
-```
-
-## Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-```
-
-## Change
-
-> POST /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-```
-
-## Remove
-
-> DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
-```
-
-## Fetch
-
-> GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-```
-
-## Change
-
-> POST /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-```
-
-## Remove
-
-> DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
-```
-
diff --git a/applications/crossbar/doc/ref/onboard.md b/applications/crossbar/doc/ref/onboard.md
deleted file mode 100644
index 8209632cb68..00000000000
--- a/applications/crossbar/doc/ref/onboard.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Onboard
-
-## About Onboard
-
-## Schema
-
-
-
-## Create
-
-> PUT /v2/accounts/{ACCOUNT_ID}/onboard
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/onboard
-```
-
diff --git a/applications/crossbar/doc/ref/shared_auth.md b/applications/crossbar/doc/ref/shared_auth.md
deleted file mode 100644
index f2c56a8ada3..00000000000
--- a/applications/crossbar/doc/ref/shared_auth.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# Shared Authentication
-
-## About Shared Authentication
-
-#### Schema
-
-Provides a local auth-token via a shared auth-token
-
-
-
-Key | Description | Type | Default | Required | Support Level
---- | ----------- | ---- | ------- | -------- | -------------
-`shared_auth` | The shared token | `string(64)` | | `true` |
-
-
-
-## Fetch
-
-> GET /v2/shared_auth
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/shared_auth
-```
-
-## Create
-
-> PUT /v2/shared_auth
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/shared_auth
-```
-
diff --git a/applications/crossbar/doc/ref/signup.md b/applications/crossbar/doc/ref/signup.md
deleted file mode 100644
index 047bf376f7e..00000000000
--- a/applications/crossbar/doc/ref/signup.md
+++ /dev/null
@@ -1,28 +0,0 @@
-### Signup
-
-#### About Signup
-
-#### Schema
-
-
-
-#### Create
-
-> PUT /v2/accounts/{ACCOUNT_ID}/signup
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/signup
-```
-
-#### Change
-
-> POST /v2/accounts/{ACCOUNT_ID}/signup/{THING}
-
-```shell
-curl -v -X POST \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/signup/{THING}
-```
-
diff --git a/applications/crossbar/doc/ref/templates.md b/applications/crossbar/doc/ref/templates.md
deleted file mode 100644
index 97f25f7b3d5..00000000000
--- a/applications/crossbar/doc/ref/templates.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# Templates
-
-## About Templates
-
-## Schema
-
-
-
-## Fetch
-
-> GET /v2/templates
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/templates
-```
-
-## Create
-
-> PUT /v2/templates/{TEMPLATE_NAME}
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/templates/{TEMPLATE_NAME}
-```
-
-## Remove
-
-> DELETE /v2/templates/{TEMPLATE_NAME}
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/templates/{TEMPLATE_NAME}
-```
-
diff --git a/applications/crossbar/doc/ref/ubiquiti_auth.md b/applications/crossbar/doc/ref/ubiquiti_auth.md
deleted file mode 100644
index 97bf845abb0..00000000000
--- a/applications/crossbar/doc/ref/ubiquiti_auth.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Ubiquiti Authentication
-
-## About Ubiquiti Authentication
-
-#### Schema
-
-Provides an auth-token via Ubiquiti's SSO
-
-
-
-Key | Description | Type | Default | Required | Support Level
---- | ----------- | ---- | ------- | -------- | -------------
-`password` | Ubiquiti SSO Password | `string(1..64)` | | `true` |
-`username` | Ubiquiti SSO Username | `string(1..64)` | | `true` |
-
-
-
-## Create
-
-> PUT /v2/ubiquiti_auth
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/ubiquiti_auth
-```
-
diff --git a/applications/crossbar/doc/resources.md b/applications/crossbar/doc/resources.md
index 537c6a72d8a..7339f76500e 100644
--- a/applications/crossbar/doc/resources.md
+++ b/applications/crossbar/doc/resources.md
@@ -10,8 +10,6 @@ When interacting with an account's resources, the URL structure is as one would
To perform bulk resource operations use the collections endpoints.
-There are two deprecated API endpoints, `global_resources` and `local_resources`. These should continue to work as before, but it is recommended to use `resources` instead, using the presence of an account id to toggle whether the resource is global or not.
-
### About Adding Bulk Numbers
It is possible to add numbers, in bulk, to an account using the Jobs API below. If a job fails to run, there is a recovery process that runs periodically to attempt to resume stalled jobs.
diff --git a/applications/crossbar/doc/schemas.md b/applications/crossbar/doc/schemas.md
index 2d3b33a9442..860a2c4ea6e 100644
--- a/applications/crossbar/doc/schemas.md
+++ b/applications/crossbar/doc/schemas.md
@@ -80,13 +80,11 @@ curl -v -X GET \
"rates",
"resource_jobs",
"resources",
- "shared_auth",
"sms",
"temporal_rules",
"temporal_rules_sets",
"token_restrictions",
"trunkstore",
- "ubiquiti_auth",
"user_auth",
"user_auth_recovery",
"users",
diff --git a/applications/crossbar/doc/securing_crossbar.md b/applications/crossbar/doc/securing_crossbar.md
index 329c226e267..482cd6cd976 100644
--- a/applications/crossbar/doc/securing_crossbar.md
+++ b/applications/crossbar/doc/securing_crossbar.md
@@ -110,7 +110,7 @@ Getting Private key
You can now test your new SSL-enabled APIs via:
```shell
-$ curl -v --cacert crossbar.crt https://api.2600hz.com:8443/v1/accounts
+$ curl -v --cacert crossbar.crt https://api.2600hz.com:8443/v2/accounts
* About to connect() to api.2600hz.com port 8443 (#0)
* Trying 127.0.0.1... connected
* successfully set certificate verify locations:
@@ -134,7 +134,7 @@ CApath: /etc/ssl/certs
* common name: api.2600hz.com (matched)
* issuer: C=US; ST=California; L=San Francisco; O=2600Hz; CN=api.2600hz.com
* SSL certificate verify ok.
-> GET /v1/accounts HTTP/1.1
+> GET /v2/accounts HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: api.2600hz.com:8443
> Accept: */*
diff --git a/applications/crossbar/doc/security.md b/applications/crossbar/doc/security.md
index c6af04a9ece..477cec09b34 100644
--- a/applications/crossbar/doc/security.md
+++ b/applications/crossbar/doc/security.md
@@ -36,9 +36,8 @@ Key | Description | Type | Default | Required | Support Level
`auth_modules.cb_api_auth` | crossbar authenticator module configuration | [#/definitions/auth_module_config](#auth_module_config) | | `false` |
`auth_modules.cb_auth` | crossbar authenticator module configuration | [#/definitions/auth_module_config](#auth_module_config) | | `false` |
`auth_modules.cb_ip_auth` | crossbar authenticator module configuration | [#/definitions/auth_module_config](#auth_module_config) | | `false` |
-`auth_modules.cb_ubiquiti_auth` | crossbar authenticator module configuration | [#/definitions/auth_module_config](#auth_module_config) | | `false` |
`auth_modules.cb_user_auth` | crossbar authenticator module configuration | [#/definitions/auth_module_config](#auth_module_config) | | `false` |
-`auth_modules` | Default crossbar authentication modules configuration | `object()` | `{"cb_user_auth":{"token_auth_expiry_s":3600,"log_successful_attempts":true,"log_failed_attempts":true,"enabled":true},"cb_ubiquiti_auth":{"token_auth_expiry_s":3600,"log_successful_attempts":false,"log_failed_attempts":true,"enabled":true},"cb_ip_auth":{"token_auth_expiry_s":3600,"log_successful_attempts":false,"log_failed_attempts":true,"enabled":true},"cb_auth":{"token_auth_expiry_s":3600,"log_successful_attempts":false,"log_failed_attempts":true,"enabled":true},"cb_api_auth":{"token_auth_expiry_s":3600,"log_successful_attempts":false,"log_failed_attempts":true,"enabled":true}}` | `true` |
+`auth_modules` | Default crossbar authentication modules configuration | `object()` | `{"cb_user_auth":{"token_auth_expiry_s":3600,"log_successful_attempts":true,"log_failed_attempts":true,"enabled":true},"cb_ip_auth":{"token_auth_expiry_s":3600,"log_successful_attempts":false,"log_failed_attempts":true,"enabled":true},"cb_auth":{"token_auth_expiry_s":3600,"log_successful_attempts":false,"log_failed_attempts":true,"enabled":true},"cb_api_auth":{"token_auth_expiry_s":3600,"log_successful_attempts":false,"log_failed_attempts":true,"enabled":true}}` | `true` |
### auth_module_config
@@ -80,7 +79,6 @@ curl -v -X GET \
"cb_api_auth",
"cb_auth",
"cb_ip_auth",
- "cb_ubiquiti_auth",
"cb_user_auth"
]
},
@@ -143,12 +141,6 @@ curl -v -X GET \
"token_auth_expiry_s": 3600,
"log_failed_attempts": true,
"log_successful_attempts": true
- },
- "cb_ubiquiti_auth": {
- "enabled": true,
- "token_auth_expiry_s": 3600,
- "log_failed_attempts": true,
- "log_successful_attempts": true
}
}
}
diff --git a/applications/crossbar/doc/shared_auth.md b/applications/crossbar/doc/shared_auth.md
deleted file mode 100644
index 8aeb0a6c747..00000000000
--- a/applications/crossbar/doc/shared_auth.md
+++ /dev/null
@@ -1,35 +0,0 @@
-### Shared Authentication
-
-#### About Shared Authentication
-
-#### Schema
-
-Provides a local auth-token via a shared auth-token
-
-
-
-Key | Description | Type | Default | Required | Support Level
---- | ----------- | ---- | ------- | -------- | -------------
-`shared_auth` | The shared token | `string(64)` | | `true` |
-
-
-
-#### Fetch
-
-> GET /v2/shared_auth
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/shared_auth
-```
-
-#### Create
-
-> PUT /v2/shared_auth
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/shared_auth
-```
diff --git a/applications/crossbar/doc/signup.md b/applications/crossbar/doc/signup.md
deleted file mode 100644
index c61dca20788..00000000000
--- a/applications/crossbar/doc/signup.md
+++ /dev/null
@@ -1,10 +0,0 @@
-### Signup
-
-#### About Signup
-
-#### Schema
-
-
-
-#### Create
-
diff --git a/applications/crossbar/doc/sup.md b/applications/crossbar/doc/sup.md
index 46509ab8e7e..7da0417a0d7 100644
--- a/applications/crossbar/doc/sup.md
+++ b/applications/crossbar/doc/sup.md
@@ -28,7 +28,7 @@ sup module_maintenance function [arg1, arg2,...]
The Crossbar URL is similarly constructed:
```
-/v1/sup/module/[function[/arg1/arg2/...]]
+/v2/sup/module/[function[/arg1/arg2/...]]
```
The important differences are:
@@ -40,7 +40,7 @@ The important differences are:
| Command line | Crossbar |
|--------------------------------------------|-----------------------------------------|
-| `sup kazoo_maintenance syslog_level debug` | `curl /v1/sup/kazoo/syslog_level/debug` |
+| `sup kazoo_maintenance syslog_level debug` | `curl /v2/sup/kazoo/syslog_level/debug` |
## Execute Maintenance Status Command
diff --git a/applications/crossbar/doc/system_configs.md b/applications/crossbar/doc/system_configs.md
index 1cf3e15c499..dc7c0485a88 100644
--- a/applications/crossbar/doc/system_configs.md
+++ b/applications/crossbar/doc/system_configs.md
@@ -106,7 +106,6 @@ curl -v -X GET \
"datamgr",
"crossbar.resources",
"crossbar.media",
- "crossbar.local_resources",
"crossbar.callflows",
"crossbar.auth",
"crossbar.accounts",
diff --git a/applications/crossbar/doc/templates.md b/applications/crossbar/doc/templates.md
deleted file mode 100644
index 202cc227942..00000000000
--- a/applications/crossbar/doc/templates.md
+++ /dev/null
@@ -1,37 +0,0 @@
-### Templates
-
-#### About Templates
-
-#### Schema
-
-
-
-#### Fetch
-
-> GET /v2/templates
-
-```shell
-curl -v -X GET \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/templates
-```
-
-#### Create
-
-> PUT /v2/templates/{TEMPLATE_NAME}
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/templates/{TEMPLATE_NAME}
-```
-
-#### Remove
-
-> DELETE /v2/templates/{TEMPLATE_NAME}
-
-```shell
-curl -v -X DELETE \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- http://{SERVER}:8000/v2/templates/{TEMPLATE_NAME}
-```
diff --git a/applications/crossbar/doc/ubiquiti_auth.md b/applications/crossbar/doc/ubiquiti_auth.md
deleted file mode 100644
index 6cba3f49eab..00000000000
--- a/applications/crossbar/doc/ubiquiti_auth.md
+++ /dev/null
@@ -1,61 +0,0 @@
-### Ubiquiti Authentication
-
-#### About Ubiquiti Authentication
-
-Ubiquiti Single Sign On.
-
-#### Schema
-
-Provides an auth-token via Ubiquiti's SSO
-
-
-
-Key | Description | Type | Default | Required | Support Level
---- | ----------- | ---- | ------- | -------- | -------------
-`password` | Ubiquiti SSO Password | `string(1..64)` | | `true` |
-`username` | Ubiquiti SSO Username | `string(1..64)` | | `true` |
-
-
-
-#### Create
-
-> PUT /v2/ubiquiti_auth
-
-```shell
-curl -v -X PUT \
- -H "X-Auth-Token: {AUTH_TOKEN}" \
- -d '{"data": {"username":"{USERNAME}", "password":"{PASSWORD}"} }' \
- http://{SERVER}:8000/v2/ubiquiti_auth
-```
-
-```json
-{
- "auth_token": "{AUTH_TOKEN}",
- "data": {
- "sso": {
- "accounts": {
- "{UBIQUITI_ACCOUNT_NAME}": "{UBIQUITI_ACCOUNT_ID}",
- "{UBIQUITI_ACCOUNT_NAME}": "{UBIQUITI_ACCOUNT_ID}"
- },
- "auth_token": "{UBIQUITI_AUTH_TOKEN}",
- "curr_privacy_rev": "REV2013-01-18",
- "curr_terms_rev": "REV2013-01-18",
- "email": "{EMAIL_ADDRESS}",
- "fields_missing": [
- "security_question",
- "security_answer"
- ],
- "first_name": "{FIRST_NAME}",
- "is_verified": true,
- "last_name": "{LAST_NAME}",
- "provider": "ubiquiti",
- "time_created": "2014-02-01T22:16:54Z",
- "username": "{USER_NAME}",
- "uuid": "{UBIQUITI_UUID}"
- }
- },
- "request_id": "{REQUEST_ID}",
- "revision": "{REVISION}",
- "status": "success"
-}
-```
diff --git a/applications/crossbar/priv/api/descriptions.system_config.json b/applications/crossbar/priv/api/descriptions.system_config.json
index 71866025fc4..9c09d6b35e1 100644
--- a/applications/crossbar/priv/api/descriptions.system_config.json
+++ b/applications/crossbar/priv/api/descriptions.system_config.json
@@ -165,14 +165,7 @@
"crossbar.devices.provisioning_url": "crossbar.devices provisioning url",
"crossbar.ensure_valid_schema": "crossbar ensure valid schema",
"crossbar.expiry_percentage": "crossbar expiry percentage",
- "crossbar.freeswitch.files_to_include": "crossbar.freeswitch files to include",
- "crossbar.freeswitch.offline_configuration_key": "crossbar.freeswitch offline configuration key",
- "crossbar.freeswitch.realm_templates_to_process": "crossbar.freeswitch realm templates to process",
- "crossbar.freeswitch.templates_to_process": "crossbar.freeswitch templates to process",
- "crossbar.freeswitch.work_dir": "crossbar.freeswitch work dir",
- "crossbar.freeswitch.{Module}": "crossbar.freeswitch {Module}",
"crossbar.ip": "crossbar ip",
- "crossbar.local_resources.allow_peers": "crossbar.local_resources allow peers",
"crossbar.magic_path_patterns": "crossbar magic path patterns",
"crossbar.max_upload_size": "crossbar maximum upload size",
"crossbar.maximum_range": "crossbar maximum range",
@@ -180,11 +173,6 @@
"crossbar.media.normalize_media": "crossbar.media normalize media",
"crossbar.notifications.inherit_default_values": "crossbar.notifications use parent notifications doc as default values, to be overridden by request data (prior to validation)",
"crossbar.notifications.notification_timeout_ms": "crossbar.notifications notification timeout in milliseconds",
- "crossbar.onboard.default_callflow_start_exten": "crossbar.onboard default callflow start exten",
- "crossbar.onboard.default_extension_callflow": "crossbar.onboard default extension callflow",
- "crossbar.onboard.default_vm_start_exten": "crossbar.onboard default vm start exten",
- "crossbar.onboard.device_pwd_strength": "crossbar.onboard device pwd strength",
- "crossbar.onboard.device_username_strength": "crossbar.onboard device username strength",
"crossbar.pagination_page_size": "crossbar pagination page size",
"crossbar.phone_numbers.default_country": "crossbar.phone_numbers default country",
"crossbar.phone_numbers.phonebook_url": "crossbar.phone_numbers phonebook url",
@@ -196,12 +184,12 @@
"crossbar.reset_id_size": "crossbar reset id size",
"crossbar.resource_selectors.csv_config": "crossbar.resource_selectors csv config",
"crossbar.resource_selectors.suppress_selectors_change_notice": "crossbar.resource_selectors suppress selectors change notice",
+ "crossbar.resources.allow_peers": "crossbar.resources allow peers",
"crossbar.resources.job_recovery_threshold_s": "crossbar.resources job recovery threshold in seconds",
"crossbar.resources.job_recovery_timeout_s": "crossbar.resources job recovery timeout in seconds",
"crossbar.reverse_proxies": "List of allowed Crossbar reverse proxies",
"crossbar.schema_strict_validation": "crossbar schema strict validation",
"crossbar.services.maximum_range": "crossbar.services maximum range",
- "crossbar.shared_auth.authoritative_crossbar": "crossbar.shared_auth authoritative crossbar",
"crossbar.sms.api_e164_convert_from": "crossbar.sms api e164 convert from",
"crossbar.sms.api_e164_convert_to": "crossbar.sms api e164 convert to",
"crossbar.ssl_ca_cert": "crossbar ssl ca cert",
@@ -214,13 +202,6 @@
"crossbar.token_restrictions._": "crossbar.token_restrictions ",
"crossbar.token_restrictions.default_priv_level": "crossbar.token_restrictions default priv level",
"crossbar.trace_path": "crossbar trace path",
- "crossbar.ubiquiti.api_secret": "crossbar.ubiquiti api secret",
- "crossbar.ubiquiti.api_token_expires_s": "crossbar.ubiquiti api token expires in seconds",
- "crossbar.ubiquiti.salt_length": "crossbar.ubiquiti salt length",
- "crossbar.ubiquiti.sso_environment": "crossbar.ubiquiti sso environment",
- "crossbar.ubiquiti.sso_provider_id": "crossbar.ubiquiti sso provider id",
- "crossbar.ubiquiti.sso_url": "crossbar.ubiquiti sso url",
- "crossbar.ubiquiti.tokens_per_request": "crossbar.ubiquiti tokens per request",
"crossbar.use_plaintext": "crossbar use plaintext",
"crossbar.use_ssl": "crossbar use ssl",
"crossbar.user_auth_tokens": "crossbar user auth tokens",
diff --git a/applications/crossbar/priv/api/swagger.json b/applications/crossbar/priv/api/swagger.json
index f1eb56d1c7d..1d108da1444 100644
--- a/applications/crossbar/priv/api/swagger.json
+++ b/applications/crossbar/priv/api/swagger.json
@@ -169,12 +169,6 @@
"log_successful_attempts": false,
"token_auth_expiry_s": 3600
},
- "cb_ubiquiti_auth": {
- "enabled": true,
- "log_failed_attempts": true,
- "log_successful_attempts": false,
- "token_auth_expiry_s": 3600
- },
"cb_user_auth": {
"enabled": true,
"log_failed_attempts": true,
@@ -193,9 +187,6 @@
"cb_ip_auth": {
"$ref": "#/definitions/auth_module_config"
},
- "cb_ubiquiti_auth": {
- "$ref": "#/definitions/auth_module_config"
- },
"cb_user_auth": {
"$ref": "#/definitions/auth_module_config"
}
@@ -28653,21 +28644,6 @@
},
"type": "object"
},
- "shared_auth": {
- "description": "Provides a local auth-token via a shared auth-token",
- "properties": {
- "shared_auth": {
- "description": "The shared token",
- "maxLength": 64,
- "minLength": 64,
- "type": "string"
- }
- },
- "required": [
- "shared_auth"
- ],
- "type": "object"
- },
"skels": {
"description": "Skeleton JSON schema",
"properties": {},
@@ -30703,12 +30679,6 @@
"log_successful_attempts": false,
"token_auth_expiry_s": 3600
},
- "cb_ubiquiti_auth": {
- "enabled": true,
- "log_failed_attempts": true,
- "log_successful_attempts": false,
- "token_auth_expiry_s": 3600
- },
"cb_user_auth": {
"enabled": true,
"log_failed_attempts": true,
@@ -30727,9 +30697,6 @@
"cb_ip_auth": {
"$ref": "#/definitions/auth_module_config"
},
- "cb_ubiquiti_auth": {
- "$ref": "#/definitions/auth_module_config"
- },
"cb_user_auth": {
"$ref": "#/definitions/auth_module_config"
}
@@ -30741,8 +30708,7 @@
"cb_user_auth",
"cb_api_auth",
"cb_auth",
- "cb_ip_auth",
- "cb_ubiquiti_auth"
+ "cb_ip_auth"
],
"description": "List of crossbar auth configurable modules",
"items": {
@@ -30899,63 +30865,6 @@
},
"type": "object"
},
- "system_config.crossbar.freeswitch": {
- "description": "Schema for crossbar.freeswitch system_config",
- "properties": {
- "files_to_include": {
- "default": [
- "freeswitch_dialplan",
- "freeswitch_chatplan"
- ],
- "description": "crossbar.freeswitch files to include",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "offline_configuration_key": {
- "description": "crossbar.freeswitch offline configuration key",
- "type": "string"
- },
- "realm_templates_to_process": {
- "default": [
- "freeswitch_directory_realm"
- ],
- "description": "crossbar.freeswitch realm templates to process",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "templates_to_process": {
- "default": [
- "freeswitch_directory"
- ],
- "description": "crossbar.freeswitch templates to process",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "work_dir": {
- "default": "/tmp/",
- "description": "crossbar.freeswitch work dir",
- "type": "string"
- }
- },
- "type": "object"
- },
- "system_config.crossbar.local_resources": {
- "description": "Schema for crossbar.local_resources system_config",
- "properties": {
- "allow_peers": {
- "default": false,
- "description": "crossbar.local_resources allow peers",
- "type": "boolean"
- }
- },
- "type": "object"
- },
"system_config.crossbar.media": {
"description": "Schema for crossbar.media system_config",
"properties": {
@@ -30988,37 +30897,6 @@
},
"type": "object"
},
- "system_config.crossbar.onboard": {
- "description": "Schema for crossbar.onboard system_config",
- "properties": {
- "default_callflow_start_exten": {
- "default": 2000,
- "description": "crossbar.onboard default callflow start exten",
- "type": "integer"
- },
- "default_extension_callflow": {
- "default": "{\"data\": { \"id\": \"~s\" }, \"module\": \"user\", \"children\": { \"_\": { \"data\": { \"id\": \"~s\" }, \"module\": \"voicemail\", \"children\": {}}}}",
- "description": "crossbar.onboard default extension callflow",
- "type": "string"
- },
- "default_vm_start_exten": {
- "default": 3000,
- "description": "crossbar.onboard default vm start exten",
- "type": "integer"
- },
- "device_pwd_strength": {
- "default": 6,
- "description": "crossbar.onboard device pwd strength",
- "type": "integer"
- },
- "device_username_strength": {
- "default": 3,
- "description": "crossbar.onboard device username strength",
- "type": "integer"
- }
- },
- "type": "object"
- },
"system_config.crossbar.phone_numbers": {
"description": "Schema for crossbar.phone_numbers system_config",
"properties": {
@@ -31052,6 +30930,11 @@
"system_config.crossbar.resources": {
"description": "Schema for crossbar.resources system_config",
"properties": {
+ "allow_peers": {
+ "default": false,
+ "description": "crossbar.resources allow peers",
+ "type": "boolean"
+ },
"job_recovery_threshold_s": {
"default": 3600,
"description": "crossbar.resources job recovery threshold in seconds",
@@ -31065,16 +30948,6 @@
},
"type": "object"
},
- "system_config.crossbar.shared_auth": {
- "description": "Schema for crossbar.shared_auth system_config",
- "properties": {
- "authoritative_crossbar": {
- "description": "crossbar.shared_auth authoritative crossbar",
- "type": "string"
- }
- },
- "type": "object"
- },
"system_config.crossbar.sms": {
"description": "Schema for crossbar.sms system_config",
"properties": {
@@ -31106,58 +30979,6 @@
},
"type": "object"
},
- "system_config.crossbar.ubiquiti": {
- "description": "Schema for crossbar.ubiquiti system_config",
- "properties": {
- "api_secret": {
- "description": "crossbar.ubiquiti api secret",
- "type": "string"
- },
- "api_token_expires_s": {
- "default": 1800,
- "description": "crossbar.ubiquiti api token expires in seconds",
- "type": "integer"
- },
- "production": {
- "properties": {
- "sso_url": {
- "default": "https://sso.ubnt.com/api/sso/v1/",
- "description": "crossbar.ubiquiti sso url",
- "type": "string"
- }
- }
- },
- "salt_length": {
- "default": 20,
- "description": "crossbar.ubiquiti salt length",
- "type": "integer"
- },
- "sso_environment": {
- "default": "staging",
- "description": "crossbar.ubiquiti sso environment",
- "type": "string"
- },
- "sso_provider_id": {
- "description": "crossbar.ubiquiti sso provider id",
- "type": "string"
- },
- "staging": {
- "properties": {
- "sso_url": {
- "default": "https://sso-stage.ubnt.com/api/sso/v1/",
- "description": "crossbar.ubiquiti sso url",
- "type": "string"
- }
- }
- },
- "tokens_per_request": {
- "default": 35,
- "description": "crossbar.ubiquiti tokens per request",
- "type": "integer"
- }
- },
- "type": "object"
- },
"system_config.crossbar.users": {
"description": "Schema for crossbar.users system_config",
"properties": {
@@ -36369,28 +36190,6 @@
"type"
]
},
- "ubiquiti_auth": {
- "description": "Provides an auth-token via Ubiquiti's SSO",
- "properties": {
- "password": {
- "description": "Ubiquiti SSO Password",
- "maxLength": 64,
- "minLength": 1,
- "type": "string"
- },
- "username": {
- "description": "Ubiquiti SSO Username",
- "maxLength": 64,
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "password",
- "username"
- ],
- "type": "object"
- },
"user_auth": {
"description": "Provides an auth-token via user credentials",
"properties": {
@@ -37981,23 +37780,6 @@
"required": true,
"type": "string"
},
- "TEMPLATE_ID": {
- "description": "request TEMPLATE_ID parameter",
- "in": "path",
- "maxLength": 32,
- "minLength": 32,
- "name": "TEMPLATE_ID",
- "pattern": "^[0-9a-f]+$",
- "required": true,
- "type": "string"
- },
- "TEMPLATE_NAME": {
- "description": "request TEMPLATE_NAME parameter",
- "in": "path",
- "name": "TEMPLATE_NAME",
- "required": true,
- "type": "string"
- },
"TEMPORAL_RULE_ID": {
"description": "request TEMPORAL_RULE_ID parameter",
"in": "path",
@@ -39018,8 +38800,8 @@
}
}
},
- "/accounts/{ACCOUNT_ID}/bulk": {
- "delete": {
+ "/accounts/{ACCOUNT_ID}/call_inspector": {
+ "get": {
"parameters": [
{
"$ref": "#/parameters/auth_token_header"
@@ -39033,7 +38815,29 @@
"description": "request succeeded"
}
}
- },
+ }
+ },
+ "/accounts/{ACCOUNT_ID}/call_inspector/{CALL_ID}": {
+ "get": {
+ "parameters": [
+ {
+ "$ref": "#/parameters/auth_token_header"
+ },
+ {
+ "$ref": "#/parameters/ACCOUNT_ID"
+ },
+ {
+ "$ref": "#/parameters/CALL_ID"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "request succeeded"
+ }
+ }
+ }
+ },
+ "/accounts/{ACCOUNT_ID}/callflows": {
"get": {
"parameters": [
{
@@ -39049,8 +38853,16 @@
}
}
},
- "post": {
+ "put": {
"parameters": [
+ {
+ "in": "body",
+ "name": "callflows",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/callflows"
+ }
+ },
{
"$ref": "#/parameters/auth_token_header"
},
@@ -39065,14 +38877,17 @@
}
}
},
- "/accounts/{ACCOUNT_ID}/call_inspector": {
- "get": {
+ "/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}": {
+ "delete": {
"parameters": [
{
"$ref": "#/parameters/auth_token_header"
},
{
"$ref": "#/parameters/ACCOUNT_ID"
+ },
+ {
+ "$ref": "#/parameters/CALLFLOW_ID"
}
],
"responses": {
@@ -39080,9 +38895,7 @@
"description": "request succeeded"
}
}
- }
- },
- "/accounts/{ACCOUNT_ID}/call_inspector/{CALL_ID}": {
+ },
"get": {
"parameters": [
{
@@ -39092,7 +38905,7 @@
"$ref": "#/parameters/ACCOUNT_ID"
},
{
- "$ref": "#/parameters/CALL_ID"
+ "$ref": "#/parameters/CALLFLOW_ID"
}
],
"responses": {
@@ -39100,16 +38913,17 @@
"description": "request succeeded"
}
}
- }
- },
- "/accounts/{ACCOUNT_ID}/callflows": {
- "get": {
+ },
+ "patch": {
"parameters": [
{
"$ref": "#/parameters/auth_token_header"
},
{
"$ref": "#/parameters/ACCOUNT_ID"
+ },
+ {
+ "$ref": "#/parameters/CALLFLOW_ID"
}
],
"responses": {
@@ -39118,7 +38932,7 @@
}
}
},
- "put": {
+ "post": {
"parameters": [
{
"in": "body",
@@ -39133,6 +38947,9 @@
},
{
"$ref": "#/parameters/ACCOUNT_ID"
+ },
+ {
+ "$ref": "#/parameters/CALLFLOW_ID"
}
],
"responses": {
@@ -39142,17 +38959,14 @@
}
}
},
- "/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}": {
- "delete": {
+ "/accounts/{ACCOUNT_ID}/cccps": {
+ "get": {
"parameters": [
{
"$ref": "#/parameters/auth_token_header"
},
{
"$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/CALLFLOW_ID"
}
],
"responses": {
@@ -39161,16 +38975,21 @@
}
}
},
- "get": {
+ "put": {
"parameters": [
{
- "$ref": "#/parameters/auth_token_header"
+ "in": "body",
+ "name": "cccps",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/cccps"
+ }
},
{
- "$ref": "#/parameters/ACCOUNT_ID"
+ "$ref": "#/parameters/auth_token_header"
},
{
- "$ref": "#/parameters/CALLFLOW_ID"
+ "$ref": "#/parameters/ACCOUNT_ID"
}
],
"responses": {
@@ -39178,8 +38997,10 @@
"description": "request succeeded"
}
}
- },
- "patch": {
+ }
+ },
+ "/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID}": {
+ "delete": {
"parameters": [
{
"$ref": "#/parameters/auth_token_header"
@@ -39188,7 +39009,7 @@
"$ref": "#/parameters/ACCOUNT_ID"
},
{
- "$ref": "#/parameters/CALLFLOW_ID"
+ "$ref": "#/parameters/CCCP_ID"
}
],
"responses": {
@@ -39197,16 +39018,8 @@
}
}
},
- "post": {
+ "get": {
"parameters": [
- {
- "in": "body",
- "name": "callflows",
- "required": true,
- "schema": {
- "$ref": "#/definitions/callflows"
- }
- },
{
"$ref": "#/parameters/auth_token_header"
},
@@ -39214,7 +39027,7 @@
"$ref": "#/parameters/ACCOUNT_ID"
},
{
- "$ref": "#/parameters/CALLFLOW_ID"
+ "$ref": "#/parameters/CCCP_ID"
}
],
"responses": {
@@ -39222,103 +39035,25 @@
"description": "request succeeded"
}
}
- }
- },
- "/accounts/{ACCOUNT_ID}/cccps": {
- "get": {
+ },
+ "post": {
"parameters": [
+ {
+ "in": "body",
+ "name": "cccps",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/cccps"
+ }
+ },
{
"$ref": "#/parameters/auth_token_header"
},
{
"$ref": "#/parameters/ACCOUNT_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "put": {
- "parameters": [
- {
- "in": "body",
- "name": "cccps",
- "required": true,
- "schema": {
- "$ref": "#/definitions/cccps"
- }
- },
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
- "/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID}": {
- "delete": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/CCCP_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "get": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/CCCP_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "post": {
- "parameters": [
- {
- "in": "body",
- "name": "cccps",
- "required": true,
- "schema": {
- "$ref": "#/definitions/cccps"
- }
- },
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/CCCP_ID"
+ },
+ {
+ "$ref": "#/parameters/CCCP_ID"
}
],
"responses": {
@@ -41186,23 +40921,6 @@
}
}
},
- "/accounts/{ACCOUNT_ID}/freeswitch": {
- "get": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
"/accounts/{ACCOUNT_ID}/functions": {
"get": {
"parameters": [
@@ -41342,150 +41060,6 @@
}
}
},
- "/accounts/{ACCOUNT_ID}/global_provisioner_templates": {
- "get": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "put": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
- "/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}": {
- "delete": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "get": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "post": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
- "/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image": {
- "delete": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "get": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "post": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
"/accounts/{ACCOUNT_ID}/groups": {
"get": {
"parameters": [
@@ -42356,150 +41930,6 @@
}
}
},
- "/accounts/{ACCOUNT_ID}/local_provisioner_templates": {
- "get": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "put": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
- "/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}": {
- "delete": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "get": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "post": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
- "/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image": {
- "delete": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "get": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "post": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- },
- {
- "$ref": "#/parameters/TEMPLATE_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
"/accounts/{ACCOUNT_ID}/media": {
"get": {
"parameters": [
@@ -43333,23 +42763,6 @@
}
}
},
- "/accounts/{ACCOUNT_ID}/onboard": {
- "put": {
- "parameters": [
- {
- "$ref": "#/parameters/auth_token_header"
- },
- {
- "$ref": "#/parameters/ACCOUNT_ID"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
"/accounts/{ACCOUNT_ID}/parents": {
"get": {
"parameters": [
@@ -48575,32 +47988,6 @@
}
}
},
- "/shared_auth": {
- "get": {
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "put": {
- "parameters": [
- {
- "in": "body",
- "name": "shared_auth",
- "required": true,
- "schema": {
- "$ref": "#/definitions/shared_auth"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
"/sup/{MODULE}": {
"get": {
"parameters": [
@@ -48818,41 +48205,6 @@
}
}
},
- "/templates": {
- "get": {
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
- "/templates/{TEMPLATE_NAME}": {
- "delete": {
- "parameters": [
- {
- "$ref": "#/parameters/TEMPLATE_NAME"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- },
- "put": {
- "parameters": [
- {
- "$ref": "#/parameters/TEMPLATE_NAME"
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
"/token_auth": {
"delete": {
"responses": {
@@ -48869,25 +48221,6 @@
}
}
},
- "/ubiquiti_auth": {
- "put": {
- "parameters": [
- {
- "in": "body",
- "name": "ubiquiti_auth",
- "required": true,
- "schema": {
- "$ref": "#/definitions/ubiquiti_auth"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "request succeeded"
- }
- }
- }
- },
"/user_auth": {
"put": {
"parameters": [
diff --git a/applications/crossbar/priv/couchdb/schemas/account_config.crossbar.auth.json b/applications/crossbar/priv/couchdb/schemas/account_config.crossbar.auth.json
index e341ed70267..ed9cc9488be 100644
--- a/applications/crossbar/priv/couchdb/schemas/account_config.crossbar.auth.json
+++ b/applications/crossbar/priv/couchdb/schemas/account_config.crossbar.auth.json
@@ -24,12 +24,6 @@
"log_successful_attempts": false,
"token_auth_expiry_s": 3600
},
- "cb_ubiquiti_auth": {
- "enabled": true,
- "log_failed_attempts": true,
- "log_successful_attempts": false,
- "token_auth_expiry_s": 3600
- },
"cb_user_auth": {
"enabled": true,
"log_failed_attempts": true,
@@ -48,9 +42,6 @@
"cb_ip_auth": {
"$ref": "auth_module_config"
},
- "cb_ubiquiti_auth": {
- "$ref": "auth_module_config"
- },
"cb_user_auth": {
"$ref": "auth_module_config"
}
diff --git a/applications/crossbar/priv/couchdb/schemas/shared_auth.json b/applications/crossbar/priv/couchdb/schemas/shared_auth.json
deleted file mode 100644
index 1e4dfecf558..00000000000
--- a/applications/crossbar/priv/couchdb/schemas/shared_auth.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "_id": "shared_auth",
- "additionalProperties": false,
- "description": "Provides a local auth-token via a shared auth-token",
- "properties": {
- "shared_auth": {
- "description": "The shared token",
- "maxLength": 64,
- "minLength": 64,
- "type": "string"
- }
- },
- "required": [
- "shared_auth"
- ],
- "type": "object"
-}
diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.auth.json b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.auth.json
index 06b87109acb..71bb29f46b7 100644
--- a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.auth.json
+++ b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.auth.json
@@ -24,12 +24,6 @@
"log_successful_attempts": false,
"token_auth_expiry_s": 3600
},
- "cb_ubiquiti_auth": {
- "enabled": true,
- "log_failed_attempts": true,
- "log_successful_attempts": false,
- "token_auth_expiry_s": 3600
- },
"cb_user_auth": {
"enabled": true,
"log_failed_attempts": true,
@@ -48,9 +42,6 @@
"cb_ip_auth": {
"$ref": "auth_module_config"
},
- "cb_ubiquiti_auth": {
- "$ref": "auth_module_config"
- },
"cb_user_auth": {
"$ref": "auth_module_config"
}
@@ -62,8 +53,7 @@
"cb_user_auth",
"cb_api_auth",
"cb_auth",
- "cb_ip_auth",
- "cb_ubiquiti_auth"
+ "cb_ip_auth"
],
"description": "List of crossbar auth configurable modules",
"items": {
diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.freeswitch.json b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.freeswitch.json
deleted file mode 100644
index 9ec957a54fd..00000000000
--- a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.freeswitch.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "_id": "system_config.crossbar.freeswitch",
- "description": "Schema for crossbar.freeswitch system_config",
- "properties": {
- "files_to_include": {
- "default": [
- "freeswitch_dialplan",
- "freeswitch_chatplan"
- ],
- "description": "crossbar.freeswitch files to include",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "offline_configuration_key": {
- "description": "crossbar.freeswitch offline configuration key",
- "type": "string"
- },
- "realm_templates_to_process": {
- "default": [
- "freeswitch_directory_realm"
- ],
- "description": "crossbar.freeswitch realm templates to process",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "templates_to_process": {
- "default": [
- "freeswitch_directory"
- ],
- "description": "crossbar.freeswitch templates to process",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "work_dir": {
- "default": "/tmp/",
- "description": "crossbar.freeswitch work dir",
- "type": "string"
- }
- },
- "type": "object"
-}
diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.local_resources.json b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.local_resources.json
deleted file mode 100644
index 613291e1d18..00000000000
--- a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.local_resources.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "_id": "system_config.crossbar.local_resources",
- "description": "Schema for crossbar.local_resources system_config",
- "properties": {
- "allow_peers": {
- "default": false,
- "description": "crossbar.local_resources allow peers",
- "type": "boolean"
- }
- },
- "type": "object"
-}
diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.onboard.json b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.onboard.json
deleted file mode 100644
index f06c6b02e68..00000000000
--- a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.onboard.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "_id": "system_config.crossbar.onboard",
- "description": "Schema for crossbar.onboard system_config",
- "properties": {
- "default_callflow_start_exten": {
- "default": 2000,
- "description": "crossbar.onboard default callflow start exten",
- "type": "integer"
- },
- "default_extension_callflow": {
- "default": "{\"data\": { \"id\": \"~s\" }, \"module\": \"user\", \"children\": { \"_\": { \"data\": { \"id\": \"~s\" }, \"module\": \"voicemail\", \"children\": {}}}}",
- "description": "crossbar.onboard default extension callflow",
- "type": "string"
- },
- "default_vm_start_exten": {
- "default": 3000,
- "description": "crossbar.onboard default vm start exten",
- "type": "integer"
- },
- "device_pwd_strength": {
- "default": 6,
- "description": "crossbar.onboard device pwd strength",
- "type": "integer"
- },
- "device_username_strength": {
- "default": 3,
- "description": "crossbar.onboard device username strength",
- "type": "integer"
- }
- },
- "type": "object"
-}
diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.resources.json b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.resources.json
index 02ce059e209..bcd215ad968 100644
--- a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.resources.json
+++ b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.resources.json
@@ -3,6 +3,11 @@
"_id": "system_config.crossbar.resources",
"description": "Schema for crossbar.resources system_config",
"properties": {
+ "allow_peers": {
+ "default": false,
+ "description": "crossbar.resources allow peers",
+ "type": "boolean"
+ },
"job_recovery_threshold_s": {
"default": 3600,
"description": "crossbar.resources job recovery threshold in seconds",
diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.shared_auth.json b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.shared_auth.json
deleted file mode 100644
index 30050f86de2..00000000000
--- a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.shared_auth.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "_id": "system_config.crossbar.shared_auth",
- "description": "Schema for crossbar.shared_auth system_config",
- "properties": {
- "authoritative_crossbar": {
- "description": "crossbar.shared_auth authoritative crossbar",
- "type": "string"
- }
- },
- "type": "object"
-}
diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.ubiquiti.json b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.ubiquiti.json
deleted file mode 100644
index 95503d0633a..00000000000
--- a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.ubiquiti.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "_id": "system_config.crossbar.ubiquiti",
- "description": "Schema for crossbar.ubiquiti system_config",
- "properties": {
- "api_secret": {
- "description": "crossbar.ubiquiti api secret",
- "type": "string"
- },
- "api_token_expires_s": {
- "default": 1800,
- "description": "crossbar.ubiquiti api token expires in seconds",
- "type": "integer"
- },
- "production": {
- "properties": {
- "sso_url": {
- "default": "https://sso.ubnt.com/api/sso/v1/",
- "description": "crossbar.ubiquiti sso url",
- "type": "string"
- }
- }
- },
- "salt_length": {
- "default": 20,
- "description": "crossbar.ubiquiti salt length",
- "type": "integer"
- },
- "sso_environment": {
- "default": "staging",
- "description": "crossbar.ubiquiti sso environment",
- "type": "string"
- },
- "sso_provider_id": {
- "description": "crossbar.ubiquiti sso provider id",
- "type": "string"
- },
- "staging": {
- "properties": {
- "sso_url": {
- "default": "https://sso-stage.ubnt.com/api/sso/v1/",
- "description": "crossbar.ubiquiti sso url",
- "type": "string"
- }
- }
- },
- "tokens_per_request": {
- "default": 35,
- "description": "crossbar.ubiquiti tokens per request",
- "type": "integer"
- }
- },
- "type": "object"
-}
diff --git a/applications/crossbar/priv/couchdb/schemas/ubiquiti_auth.json b/applications/crossbar/priv/couchdb/schemas/ubiquiti_auth.json
deleted file mode 100644
index 5089e7c8edf..00000000000
--- a/applications/crossbar/priv/couchdb/schemas/ubiquiti_auth.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "_id": "ubiquiti_auth",
- "description": "Provides an auth-token via Ubiquiti's SSO",
- "properties": {
- "password": {
- "description": "Ubiquiti SSO Password",
- "maxLength": 64,
- "minLength": 1,
- "type": "string"
- },
- "username": {
- "description": "Ubiquiti SSO Username",
- "maxLength": 64,
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "password",
- "username"
- ],
- "type": "object"
-}
diff --git a/applications/crossbar/priv/couchdb/views/provisioner_templates.json b/applications/crossbar/priv/couchdb/views/provisioner_templates.json
deleted file mode 100644
index 7510939b93a..00000000000
--- a/applications/crossbar/priv/couchdb/views/provisioner_templates.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "_id": "_design/provisioner_templates",
- "kazoo": {
- "view_map": [
- {
- "classification": "account"
- },
- {
- "database": "global_provisioner"
- }
- ]
- },
- "language": "javascript",
- "views": {
- "crossbar_listing": {
- "map": "function(doc) { if (doc.pvt_type != 'provisioner_template' || doc.pvt_deleted) return; emit(doc._id, {'id': doc._id, 'name': doc.name}); }"
- }
- }
-}
diff --git a/applications/crossbar/priv/dispatch.conf b/applications/crossbar/priv/dispatch.conf
deleted file mode 100644
index 78664b6bd95..00000000000
--- a/applications/crossbar/priv/dispatch.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-%%-*- mode: erlang -*-
-{[], crossbar_resource, []}.
-
-{["api_1_0", cb_module, '*'], api_1_0_resource, []}.
-{["v1", '*'], v1_resource, []}.
-
-{['*'] %% match anything not matched by previous clauses
- ,static_resource %% defined in static_resource.erl
- ,[{root, "/www"}]}. %% serve from priv/www
diff --git a/applications/crossbar/priv/freeswitch/chatplan.xml b/applications/crossbar/priv/freeswitch/chatplan.xml
deleted file mode 100644
index 7f72a07ce2f..00000000000
--- a/applications/crossbar/priv/freeswitch/chatplan.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/applications/crossbar/priv/freeswitch/chatplan_template.xml b/applications/crossbar/priv/freeswitch/chatplan_template.xml
deleted file mode 100644
index e88136af958..00000000000
--- a/applications/crossbar/priv/freeswitch/chatplan_template.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/applications/crossbar/priv/freeswitch/dialplan.xml b/applications/crossbar/priv/freeswitch/dialplan.xml
deleted file mode 100644
index a47b0ec8670..00000000000
--- a/applications/crossbar/priv/freeswitch/dialplan.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/applications/crossbar/priv/freeswitch/dialplan_template.xml b/applications/crossbar/priv/freeswitch/dialplan_template.xml
deleted file mode 100644
index 40c52802ad2..00000000000
--- a/applications/crossbar/priv/freeswitch/dialplan_template.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/applications/crossbar/priv/freeswitch/directory.xml b/applications/crossbar/priv/freeswitch/directory.xml
deleted file mode 100644
index 9e4d8e689ac..00000000000
--- a/applications/crossbar/priv/freeswitch/directory.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/applications/crossbar/priv/freeswitch/directory_realm_template.xml b/applications/crossbar/priv/freeswitch/directory_realm_template.xml
deleted file mode 100644
index 029370a3c68..00000000000
--- a/applications/crossbar/priv/freeswitch/directory_realm_template.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/applications/crossbar/priv/freeswitch/directory_template.xml b/applications/crossbar/priv/freeswitch/directory_template.xml
deleted file mode 100644
index cd7b13899aa..00000000000
--- a/applications/crossbar/priv/freeswitch/directory_template.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- {% if auth_nonce %}
- {% endif %}
-
- {% for i in variables %}
- {% endfor %}{% if effective_caller_id_number %}
- {% endif %}
-
- {% for i in headers %}
- {% endfor %}
-
-
-
diff --git a/applications/crossbar/priv/oas3/oas3-parameters.yml b/applications/crossbar/priv/oas3/oas3-parameters.yml
index 7a30079ca7b..e61ed7af1f9 100644
--- a/applications/crossbar/priv/oas3/oas3-parameters.yml
+++ b/applications/crossbar/priv/oas3/oas3-parameters.yml
@@ -630,23 +630,6 @@
'minLength': 15
'pattern': '^[0-9a-f]+$'
'type': string
-'TEMPLATE_ID':
- 'description': request TEMPLATE_ID parameter
- 'in': path
- 'name': TEMPLATE_ID
- 'required': true
- 'schema':
- 'maxLength': 32
- 'minLength': 32
- 'pattern': '^[0-9a-f]+$'
- 'type': string
-'TEMPLATE_NAME':
- 'description': request TEMPLATE_NAME parameter
- 'in': path
- 'name': TEMPLATE_NAME
- 'required': true
- 'schema':
- 'type': string
'TEMPORAL_RULE_ID':
'description': request TEMPORAL_RULE_ID parameter
'in': path
diff --git a/applications/crossbar/priv/oas3/oas3-schemas.yml b/applications/crossbar/priv/oas3/oas3-schemas.yml
index b2d39fb2e40..671f7180e24 100644
--- a/applications/crossbar/priv/oas3/oas3-schemas.yml
+++ b/applications/crossbar/priv/oas3/oas3-schemas.yml
@@ -127,11 +127,6 @@
'log_failed_attempts': true
'log_successful_attempts': false
'token_auth_expiry_s': 3600
- 'cb_ubiquiti_auth':
- 'enabled': true
- 'log_failed_attempts': true
- 'log_successful_attempts': false
- 'token_auth_expiry_s': 3600
'cb_user_auth':
'enabled': true
'log_failed_attempts': true
@@ -145,8 +140,6 @@
'$ref': '#/auth_module_config'
'cb_ip_auth':
'$ref': '#/auth_module_config'
- 'cb_ubiquiti_auth':
- '$ref': '#/auth_module_config'
'cb_user_auth':
'$ref': '#/auth_module_config'
'type': object
@@ -8186,18 +8179,6 @@
'type': object
'type': array
'type': object
-'shared_auth':
- 'additionalProperties': false
- 'description': Provides a local auth-token via a shared auth-token
- 'properties':
- 'shared_auth':
- 'description': The shared token
- 'maxLength': 64
- 'minLength': 64
- 'type': string
- 'required':
- - shared_auth
- 'type': object
'skels':
'description': Skeleton JSON schema
'properties': {}
@@ -9820,11 +9801,6 @@
'log_failed_attempts': true
'log_successful_attempts': false
'token_auth_expiry_s': 3600
- 'cb_ubiquiti_auth':
- 'enabled': true
- 'log_failed_attempts': true
- 'log_successful_attempts': false
- 'token_auth_expiry_s': 3600
'cb_user_auth':
'enabled': true
'log_failed_attempts': true
@@ -9838,8 +9814,6 @@
'$ref': '#/auth_module_config'
'cb_ip_auth':
'$ref': '#/auth_module_config'
- 'cb_ubiquiti_auth':
- '$ref': '#/auth_module_config'
'cb_user_auth':
'$ref': '#/auth_module_config'
'type': object
@@ -9849,7 +9823,6 @@
- cb_api_auth
- cb_auth
- cb_ip_auth
- - cb_ubiquiti_auth
'description': List of crossbar auth configurable modules
'items':
'type': string
@@ -9966,47 +9939,6 @@
'description': crossbar.devices provisioning url
'type': string
'type': object
-'system_config.crossbar.freeswitch':
- 'description': Schema for crossbar.freeswitch system_config
- 'properties':
- 'files_to_include':
- 'default':
- - freeswitch_dialplan
- - freeswitch_chatplan
- 'description': crossbar.freeswitch files to include
- 'items':
- 'type': string
- 'type': array
- 'offline_configuration_key':
- 'description': crossbar.freeswitch offline configuration key
- 'type': string
- 'realm_templates_to_process':
- 'default':
- - freeswitch_directory_realm
- 'description': crossbar.freeswitch realm templates to process
- 'items':
- 'type': string
- 'type': array
- 'templates_to_process':
- 'default':
- - freeswitch_directory
- 'description': crossbar.freeswitch templates to process
- 'items':
- 'type': string
- 'type': array
- 'work_dir':
- 'default': /tmp/
- 'description': crossbar.freeswitch work dir
- 'type': string
- 'type': object
-'system_config.crossbar.local_resources':
- 'description': Schema for crossbar.local_resources system_config
- 'properties':
- 'allow_peers':
- 'default': false
- 'description': crossbar.local_resources allow peers
- 'type': boolean
- 'type': object
'system_config.crossbar.media':
'description': Schema for crossbar.media system_config
'properties':
@@ -10032,31 +9964,6 @@
'description': crossbar.notifications notification timeout in milliseconds
'type': integer
'type': object
-'system_config.crossbar.onboard':
- 'description': Schema for crossbar.onboard system_config
- 'properties':
- 'default_callflow_start_exten':
- 'default': 2000
- 'description': crossbar.onboard default callflow start exten
- 'type': integer
- 'default_extension_callflow':
- 'default': |-
- {"data": { "id": "~s" }, "module": "user", "children": { "_": { "data": { "id": "~s" }, "module": "voicemail", "children": {}}}}
- 'description': crossbar.onboard default extension callflow
- 'type': string
- 'default_vm_start_exten':
- 'default': 3000
- 'description': crossbar.onboard default vm start exten
- 'type': integer
- 'device_pwd_strength':
- 'default': 6
- 'description': crossbar.onboard device pwd strength
- 'type': integer
- 'device_username_strength':
- 'default': 3
- 'description': crossbar.onboard device username strength
- 'type': integer
- 'type': object
'system_config.crossbar.phone_numbers':
'description': Schema for crossbar.phone_numbers system_config
'properties':
@@ -10082,6 +9989,10 @@
'system_config.crossbar.resources':
'description': Schema for crossbar.resources system_config
'properties':
+ 'allow_peers':
+ 'default': false
+ 'description': crossbar.resources allow peers
+ 'type': boolean
'job_recovery_threshold_s':
'default': 3600
'description': crossbar.resources job recovery threshold in seconds
@@ -10091,13 +10002,6 @@
'description': crossbar.resources job recovery timeout in seconds
'type': integer
'type': object
-'system_config.crossbar.shared_auth':
- 'description': Schema for crossbar.shared_auth system_config
- 'properties':
- 'authoritative_crossbar':
- 'description': crossbar.shared_auth authoritative crossbar
- 'type': string
- 'type': object
'system_config.crossbar.sms':
'description': Schema for crossbar.sms system_config
'properties':
@@ -10121,44 +10025,6 @@
'description': crossbar.token_restrictions default priv level
'type': string
'type': object
-'system_config.crossbar.ubiquiti':
- 'description': Schema for crossbar.ubiquiti system_config
- 'properties':
- 'api_secret':
- 'description': crossbar.ubiquiti api secret
- 'type': string
- 'api_token_expires_s':
- 'default': 1800
- 'description': crossbar.ubiquiti api token expires in seconds
- 'type': integer
- 'production':
- 'properties':
- 'sso_url':
- 'default': 'https://sso.ubnt.com/api/sso/v1/'
- 'description': crossbar.ubiquiti sso url
- 'type': string
- 'salt_length':
- 'default': 20
- 'description': crossbar.ubiquiti salt length
- 'type': integer
- 'sso_environment':
- 'default': staging
- 'description': crossbar.ubiquiti sso environment
- 'type': string
- 'sso_provider_id':
- 'description': crossbar.ubiquiti sso provider id
- 'type': string
- 'staging':
- 'properties':
- 'sso_url':
- 'default': 'https://sso-stage.ubnt.com/api/sso/v1/'
- 'description': crossbar.ubiquiti sso url
- 'type': string
- 'tokens_per_request':
- 'default': 35
- 'description': crossbar.ubiquiti tokens per request
- 'type': integer
- 'type': object
'system_config.crossbar.users':
'description': Schema for crossbar.users system_config
'properties':
@@ -14233,23 +14099,6 @@
'required':
- account
- type
-'ubiquiti_auth':
- 'description': Provides an auth-token via Ubiquiti's SSO
- 'properties':
- 'password':
- 'description': Ubiquiti SSO Password
- 'maxLength': 64
- 'minLength': 1
- 'type': string
- 'username':
- 'description': Ubiquiti SSO Username
- 'maxLength': 64
- 'minLength': 1
- 'type': string
- 'required':
- - password
- - username
- 'type': object
'user_auth':
'description': Provides an auth-token via user credentials
'properties':
diff --git a/applications/crossbar/priv/oas3/openapi.yml b/applications/crossbar/priv/oas3/openapi.yml
index 210307973e6..63c731c7a0a 100644
--- a/applications/crossbar/priv/oas3/openapi.yml
+++ b/applications/crossbar/priv/oas3/openapi.yml
@@ -74,8 +74,6 @@
'/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}':
'$ref': >-
paths/blacklists.yml#/paths/~1accounts~1{ACCOUNT_ID}~1blacklists~1{BLACKLIST_ID}
- '/accounts/{ACCOUNT_ID}/bulk':
- '$ref': 'paths/bulk.yml#/paths/~1accounts~1{ACCOUNT_ID}~1bulk'
'/accounts/{ACCOUNT_ID}/call_inspector':
'$ref': 'paths/call_inspector.yml#/paths/~1accounts~1{ACCOUNT_ID}~1call_inspector'
'/accounts/{ACCOUNT_ID}/call_inspector/{CALL_ID}':
@@ -194,8 +192,6 @@
'/accounts/{ACCOUNT_ID}/faxes/smtplog/{ATTEMPT_ID}':
'$ref': >-
paths/faxes.yml#/paths/~1accounts~1{ACCOUNT_ID}~1faxes~1smtplog~1{ATTEMPT_ID}
- '/accounts/{ACCOUNT_ID}/freeswitch':
- '$ref': 'paths/freeswitch.yml#/paths/~1accounts~1{ACCOUNT_ID}~1freeswitch'
'/accounts/{ACCOUNT_ID}/functions':
'$ref': 'paths/functions.yml#/paths/~1accounts~1{ACCOUNT_ID}~1functions'
'/accounts/{ACCOUNT_ID}/functions/samples':
@@ -203,15 +199,6 @@
'/accounts/{ACCOUNT_ID}/functions/{FUNCTION_ID}':
'$ref': >-
paths/functions.yml#/paths/~1accounts~1{ACCOUNT_ID}~1functions~1{FUNCTION_ID}
- '/accounts/{ACCOUNT_ID}/global_provisioner_templates':
- '$ref': >-
- paths/global_provisioner_templates.yml#/paths/~1accounts~1{ACCOUNT_ID}~1global_provisioner_templates
- '/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}':
- '$ref': >-
- paths/global_provisioner_templates.yml#/paths/~1accounts~1{ACCOUNT_ID}~1global_provisioner_templates~1{TEMPLATE_ID}
- '/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image':
- '$ref': >-
- paths/global_provisioner_templates.yml#/paths/~1accounts~1{ACCOUNT_ID}~1global_provisioner_templates~1{TEMPLATE_ID}~1image
'/accounts/{ACCOUNT_ID}/groups':
'$ref': 'paths/groups.yml#/paths/~1accounts~1{ACCOUNT_ID}~1groups'
'/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}':
@@ -264,15 +251,6 @@
'/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}/vcard':
'$ref': >-
paths/lists.yml#/paths/~1accounts~1{ACCOUNT_ID}~1lists~1{LIST_ID}~1entries~1{LIST_ENTRY_ID}~1vcard
- '/accounts/{ACCOUNT_ID}/local_provisioner_templates':
- '$ref': >-
- paths/local_provisioner_templates.yml#/paths/~1accounts~1{ACCOUNT_ID}~1local_provisioner_templates
- '/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}':
- '$ref': >-
- paths/local_provisioner_templates.yml#/paths/~1accounts~1{ACCOUNT_ID}~1local_provisioner_templates~1{TEMPLATE_ID}
- '/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image':
- '$ref': >-
- paths/local_provisioner_templates.yml#/paths/~1accounts~1{ACCOUNT_ID}~1local_provisioner_templates~1{TEMPLATE_ID}~1image
'/accounts/{ACCOUNT_ID}/media':
'$ref': 'paths/media.yml#/paths/~1accounts~1{ACCOUNT_ID}~1media'
'/accounts/{ACCOUNT_ID}/media/languages':
@@ -330,8 +308,6 @@
'/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}/preview':
'$ref': >-
paths/notifications.yml#/paths/~1accounts~1{ACCOUNT_ID}~1notifications~1{NOTIFICATION_ID}~1preview
- '/accounts/{ACCOUNT_ID}/onboard':
- '$ref': 'paths/onboard.yml#/paths/~1accounts~1{ACCOUNT_ID}~1onboard'
'/accounts/{ACCOUNT_ID}/parents':
'$ref': 'paths/accounts.yml#/paths/~1accounts~1{ACCOUNT_ID}~1parents'
'/accounts/{ACCOUNT_ID}/parked_calls':
@@ -719,8 +695,6 @@
'$ref': 'paths/schemas.yml#/paths/~1schemas~1{SCHEMA_NAME}'
'/schemas/{SCHEMA_NAME}/validation':
'$ref': 'paths/schemas.yml#/paths/~1schemas~1{SCHEMA_NAME}~1validation'
- '/shared_auth':
- '$ref': 'paths/shared_auth.yml#/paths/~1shared_auth'
'/sup/{MODULE}':
'$ref': 'paths/sup.yml#/paths/~1sup~1{MODULE}'
'/sup/{MODULE}/{FUNCTION}':
@@ -736,14 +710,8 @@
paths/system_configs.yml#/paths/~1system_configs~1{SYSTEM_CONFIG_ID}~1{NODE}
'/system_status':
'$ref': 'paths/system_status.yml#/paths/~1system_status'
- '/templates':
- '$ref': 'paths/templates.yml#/paths/~1templates'
- '/templates/{TEMPLATE_NAME}':
- '$ref': 'paths/templates.yml#/paths/~1templates~1{TEMPLATE_NAME}'
'/token_auth':
'$ref': 'paths/token_auth.yml#/paths/~1token_auth'
- '/ubiquiti_auth':
- '$ref': 'paths/ubiquiti_auth.yml#/paths/~1ubiquiti_auth'
'/user_auth':
'$ref': 'paths/user_auth.yml#/paths/~1user_auth'
'/user_auth/recovery':
diff --git a/applications/crossbar/priv/oas3/paths/freeswitch.yml b/applications/crossbar/priv/oas3/paths/freeswitch.yml
deleted file mode 100644
index d1c075d98ce..00000000000
--- a/applications/crossbar/priv/oas3/paths/freeswitch.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-paths:
- /accounts/{ACCOUNT_ID}/freeswitch:
- get:
- operationId: GetAccountsAccountIdFreeswitch
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- responses:
- 200:
- description: Successful operation
- summary: Get all freeswitch
- tags:
- - freeswitch
diff --git a/applications/crossbar/priv/oas3/paths/global_provisioner_templates.yml b/applications/crossbar/priv/oas3/paths/global_provisioner_templates.yml
deleted file mode 100644
index 2d6382d4328..00000000000
--- a/applications/crossbar/priv/oas3/paths/global_provisioner_templates.yml
+++ /dev/null
@@ -1,98 +0,0 @@
-paths:
- /accounts/{ACCOUNT_ID}/global_provisioner_templates:
- get:
- operationId: GetAccountsAccountIdGlobalProvisionerTemplates
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- responses:
- 200:
- description: Successful operation
- summary: Get all global_provisioner_templates
- tags:
- - global_provisioner_templates
- put:
- operationId: PutAccountsAccountIdGlobalProvisionerTemplates
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- responses:
- 200:
- description: Successful operation
- summary: Add an instance of global_provisioner_templates
- tags:
- - global_provisioner_templates
- /accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}:
- delete:
- operationId: DeleteAccountsAccountIdGlobalProvisionerTemplatesTemplateId
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Delete an instance of global_provisioner_templates
- tags:
- - global_provisioner_templates
- get:
- operationId: GetAccountsAccountIdGlobalProvisionerTemplatesTemplateId
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Get a global_provisioner_templates by ID
- tags:
- - global_provisioner_templates
- post:
- operationId: PostAccountsAccountIdGlobalProvisionerTemplatesTemplateId
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Update an instance of global_provisioner_templates
- tags:
- - global_provisioner_templates
- /accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image:
- delete:
- operationId: DeleteAccountsAccountIdGlobalProvisionerTemplatesTemplateIdImage
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Delete an instance of global_provisioner_templates
- tags:
- - global_provisioner_templates
- get:
- operationId: GetAccountsAccountIdGlobalProvisionerTemplatesTemplateIdImage
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Get image of global_provisioner_templates
- tags:
- - global_provisioner_templates
- post:
- operationId: PostAccountsAccountIdGlobalProvisionerTemplatesTemplateIdImage
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Update an instance of global_provisioner_templates
- tags:
- - global_provisioner_templates
diff --git a/applications/crossbar/priv/oas3/paths/local_provisioner_templates.yml b/applications/crossbar/priv/oas3/paths/local_provisioner_templates.yml
deleted file mode 100644
index 433ad902528..00000000000
--- a/applications/crossbar/priv/oas3/paths/local_provisioner_templates.yml
+++ /dev/null
@@ -1,98 +0,0 @@
-paths:
- /accounts/{ACCOUNT_ID}/local_provisioner_templates:
- get:
- operationId: GetAccountsAccountIdLocalProvisionerTemplates
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- responses:
- 200:
- description: Successful operation
- summary: Get all local_provisioner_templates
- tags:
- - local_provisioner_templates
- put:
- operationId: PutAccountsAccountIdLocalProvisionerTemplates
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- responses:
- 200:
- description: Successful operation
- summary: Add an instance of local_provisioner_templates
- tags:
- - local_provisioner_templates
- /accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}:
- delete:
- operationId: DeleteAccountsAccountIdLocalProvisionerTemplatesTemplateId
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Delete an instance of local_provisioner_templates
- tags:
- - local_provisioner_templates
- get:
- operationId: GetAccountsAccountIdLocalProvisionerTemplatesTemplateId
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Get a local_provisioner_templates by ID
- tags:
- - local_provisioner_templates
- post:
- operationId: PostAccountsAccountIdLocalProvisionerTemplatesTemplateId
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Update an instance of local_provisioner_templates
- tags:
- - local_provisioner_templates
- /accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image:
- delete:
- operationId: DeleteAccountsAccountIdLocalProvisionerTemplatesTemplateIdImage
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Delete an instance of local_provisioner_templates
- tags:
- - local_provisioner_templates
- get:
- operationId: GetAccountsAccountIdLocalProvisionerTemplatesTemplateIdImage
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Get image of local_provisioner_templates
- tags:
- - local_provisioner_templates
- post:
- operationId: PostAccountsAccountIdLocalProvisionerTemplatesTemplateIdImage
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- - $ref: '../oas3-parameters.yml#/TEMPLATE_ID'
- responses:
- 200:
- description: Successful operation
- summary: Update an instance of local_provisioner_templates
- tags:
- - local_provisioner_templates
diff --git a/applications/crossbar/priv/oas3/paths/onboard.yml b/applications/crossbar/priv/oas3/paths/onboard.yml
deleted file mode 100644
index 8ee121a8f1d..00000000000
--- a/applications/crossbar/priv/oas3/paths/onboard.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-paths:
- /accounts/{ACCOUNT_ID}/onboard:
- put:
- operationId: PutAccountsAccountIdOnboard
- parameters:
- - $ref: '../oas3-parameters.yml#/auth_token_header'
- - $ref: '../oas3-parameters.yml#/ACCOUNT_ID'
- responses:
- 200:
- description: Successful operation
- summary: Add an instance of onboard
- tags:
- - onboard
diff --git a/applications/crossbar/priv/oas3/paths/shared_auth.yml b/applications/crossbar/priv/oas3/paths/shared_auth.yml
deleted file mode 100644
index 39ec9060a2b..00000000000
--- a/applications/crossbar/priv/oas3/paths/shared_auth.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-paths:
- /shared_auth:
- get:
- operationId: GetSharedAuth
- parameters: []
- responses:
- 200:
- description: Successful operation
- summary: Get all shared_auth
- tags:
- - shared_auth
- put:
- operationId: PutSharedAuth
- parameters: []
- requestBody:
- content:
- application/json:
- schema:
- $ref: '../oas3-schemas.yml#/shared_auth'
- responses:
- 200:
- description: Successful operation
- summary: Add an instance of shared_auth
- tags:
- - shared_auth
diff --git a/applications/crossbar/priv/oas3/paths/templates.yml b/applications/crossbar/priv/oas3/paths/templates.yml
deleted file mode 100644
index bd3c04b5be4..00000000000
--- a/applications/crossbar/priv/oas3/paths/templates.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-paths:
- /templates:
- get:
- operationId: GetTemplates
- parameters: []
- responses:
- 200:
- description: Successful operation
- summary: Get all templates
- tags:
- - templates
- /templates/{TEMPLATE_NAME}:
- delete:
- operationId: DeleteTemplatesTemplateName
- parameters:
- - $ref: '../oas3-parameters.yml#/TEMPLATE_NAME'
- responses:
- 200:
- description: Successful operation
- summary: Delete an instance of templates
- tags:
- - templates
- put:
- operationId: PutTemplatesTemplateName
- parameters:
- - $ref: '../oas3-parameters.yml#/TEMPLATE_NAME'
- responses:
- 200:
- description: Successful operation
- summary: Add an instance of templates
- tags:
- - templates
diff --git a/applications/crossbar/priv/oas3/paths/ubiquiti_auth.yml b/applications/crossbar/priv/oas3/paths/ubiquiti_auth.yml
deleted file mode 100644
index 869e7b24f82..00000000000
--- a/applications/crossbar/priv/oas3/paths/ubiquiti_auth.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-paths:
- /ubiquiti_auth:
- put:
- operationId: PutUbiquitiAuth
- parameters: []
- requestBody:
- content:
- application/json:
- schema:
- $ref: '../oas3-schemas.yml#/ubiquiti_auth'
- responses:
- 200:
- description: Successful operation
- summary: Add an instance of ubiquiti_auth
- tags:
- - ubiquiti_auth
diff --git a/applications/crossbar/priv/signup/activation_email_html.tmpl b/applications/crossbar/priv/signup/activation_email_html.tmpl
deleted file mode 100644
index 13f4f98791a..00000000000
--- a/applications/crossbar/priv/signup/activation_email_html.tmpl
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-Welcome {{user.first_name}} {{user.last_name}}
-
-
-Welcome to 2600hz!
-
-
-
-Your account username is : {{user.username}}.
-
-
-
-You are one step away from completing your registration, click on this link to activate your account.
-
-
-
-If you have any issues with this link, please copy and paste the URL below in your web browser to activate the account:
-
-{{account.app_url}}?activation_key={{activation_key}}
-
-
-
-
diff --git a/applications/crossbar/priv/signup/activation_email_plain.tmpl b/applications/crossbar/priv/signup/activation_email_plain.tmpl
deleted file mode 100644
index e3b235a322e..00000000000
--- a/applications/crossbar/priv/signup/activation_email_plain.tmpl
+++ /dev/null
@@ -1,11 +0,0 @@
-Welcome {{user.first_name}} {{user.last_name}}
-
-Welcome to 2600hz!
-
-Your account username is : {{user.username}}.
-
-You are one step away from completing your registration, and activating your account.
-
-Please copy and paste the URL below in your web browser:
-
-{{account.app_url}}?activation_key={{activation_key}}
diff --git a/applications/crossbar/priv/signup/signup.conf b/applications/crossbar/priv/signup/signup.conf
deleted file mode 100644
index 3fbf68872cd..00000000000
--- a/applications/crossbar/priv/signup/signup.conf
+++ /dev/null
@@ -1,101 +0,0 @@
-%%==============================================================================
-%% The templates used here are a erlang implentation of the django
-%% templates. See: http://code.google.com/p/erlydtl/wiki/TagsAndFilters
-%% for details.
-%% If the template is provided as a binary:
-%% <<"my template">>
-%% then the provided string is used as the template; however,
-%% if the template is provided as a string/list:
-%% "my template"
-%% then it is considered a path to a file whoes contents
-%% is the template. If the path does not start with
-%% "/" then it is considered relative to this file.
-%%==============================================================================
-
-
-%%==============================================================================
-%% This is the rate, in seconds, to check the signup database for expired
-%% signups. This number should be smaller then signup_lifespan. By default
-%% it is set to every 5 hours (18000).
-{cleanup_interval, 18000}.
-
-
-%%==============================================================================
-%% This is the lifespan, in seconds, of an un-activated signup. By default
-%% this is set to 24 hours (86400).
-{signup_lifespan, 86400}.
-
-
-%%==============================================================================
-%% This is the plain text version of the activation email to send, if commented
-%% out no plain text version will be sent. The properties avaliable are:
-%% * account (object): the account defintion that will be used if activated
-%% * user (object): the user defintion that will be used if activated
-%% * request (object): any properties (other than account and user) provided
-%% in the signup request
-%% * api_url (object): there are two properties in this, host and path, and
-%% representing the API url used to submit the request
-%% * host (string): the hostname of the server processing the signup request
-%% * activation_key (string): the key that must be submited back to signup
-%% to activate this request
-{activation_email_plain, "activation_email_plain.tmpl"}.
-
-
-%%==============================================================================
-%% This is the html version of the activation email to send, if commented
-%% out no html version will be sent. The properties avaliable are:
-%% * account (object): the account defintion that will be used if activated
-%% * user (object): the user defintion that will be used if activated
-%% * request (object): any properties (other than account and user) provided
-%% in the signup request
-%% * api_url (object): there are two properties in this, host and path, and
-%% representing the API url used to submit the request
-%% * host (string): the hostname of the server processing the signup request
-%% * activation_key (string): the key that must be submited back to signup
-%% to activate this request
-{activation_email_html, "activation_email_html.tmpl"}.
-
-
-%%==============================================================================
-%% This is what will be displayed as the email sender, if it
-%% is commented out a default will be used. The properties avaliable are:
-%% * account (object): the account defintion that will be used if activated
-%% * user (object): the user defintion that will be used if activated
-%% * request (object): any properties (other than account and user) provided
-%% in the signup request
-%% * api_url (object): there are two properties in this, host and path, and
-%% representing the API url used to submit the request
-%% * host (string): the hostname of the server processing the signup request
-%% * activation_key (string): the key that must be submited back to signup
-%% to activate this request
-{activation_email_from, <<"noreply@2600hz.com">>}.
-
-
-%%==============================================================================
-%% This is the subject line of the activation email that will be sent, if it
-%% is commented out a default will be used. The properties avaliable are:
-%% * account (object): the account defintion that will be used if activated
-%% * user (object): the user defintion that will be used if activated
-%% * request (object): any properties (other than account and user) provided
-%% in the signup request
-%% * api_url (object): there are two properties in this, host and path, and
-%% representing the API url used to submit the request
-%% * host (string): the hostname of the server processing the signup request
-%% * activation_key (string): the key that must be submited back to signup
-%% to activate this request
-{activation_email_subject, <<"Activate your 2600hz account">>}.
-
-
-%%==============================================================================
-%% This is an optional command that can be executed when a new singup request
-%% is received (not necessarly activated). The properties avaliable are:
-%% * account (object): the account defintion that will be used if activated
-%% * user (object): the user defintion that will be used if activated
-%% * request (object): any properties (other than account and user) provided
-%% in the signup request
-%% * api_url (object): there are two properties in this, host and path, and
-%% representing the API url used to submit the request
-%% * host (string): the hostname of the server processing the signup request
-%% * activation_key (string): the key that must be submited back to signup
-%% to activate this request
-{register_cmd, <<"echo \"{{account.realm}},{{activation_key}},{{user.first_name}},{{user.last_name}},{{user.username}},{{user.email}}\" > /tmp/reg_{{account.realm}}_$(date +%s).txt">>}.
diff --git a/applications/crossbar/src/api_resource.erl b/applications/crossbar/src/api_resource.erl
index 9b7f5c06a50..ac297381bf8 100644
--- a/applications/crossbar/src/api_resource.erl
+++ b/applications/crossbar/src/api_resource.erl
@@ -234,7 +234,7 @@ find_version(Path, Req) ->
find_version(Path) ->
lager:info("find version in ~s", [Path]),
case binary:split(Path, <<"/">>, ['global']) of
- [Path] -> ?VERSION_1;
+ [Path] -> ?VERSION_2;
[<<>>, Ver | _] -> to_version(Ver);
[Ver | _] -> to_version(Ver)
end.
@@ -244,9 +244,9 @@ to_version(<<"v", Int/binary>>=Version) ->
try kz_term:to_integer(Int) of
_ -> Version
catch
- _:_ -> ?VERSION_1
+ _:_ -> ?VERSION_2
end;
-to_version(_) -> ?VERSION_1.
+to_version(_) -> ?VERSION_2.
-spec maybe_allow_proxy_req(kz_term:ne_binary(), kz_term:ne_binary()) -> kz_term:ne_binary().
maybe_allow_proxy_req(Peer, ForwardIP) ->
diff --git a/applications/crossbar/src/api_util.erl b/applications/crossbar/src/api_util.erl
index 0da5a5cf040..4ad776fe958 100644
--- a/applications/crossbar/src/api_util.erl
+++ b/applications/crossbar/src/api_util.erl
@@ -146,6 +146,17 @@ get_cors_headers(Allow) ->
{cb_context:context(), cowboy_req:req()} |
stop_return().
get_req_data(Context, Req0) ->
+ maybe_get_req_data(Context, Req0, cb_context:api_version(Context)).
+
+-spec maybe_get_req_data(cb_context:context(), cowboy_req:req(), kz_term:ne_binary()) ->
+ {cb_context:context(), cowboy_req:req()} |
+ stop_return().
+maybe_get_req_data(Context, Req, ?VERSION_1) ->
+ lager:debug("unsupported version 1 request, stopping here..."),
+ Message = <<"API version 1 is not supported. Please upgrade your code to use version 2.">>,
+ Context1 = cb_context:add_system_error(410, 'gone', Message, Context),
+ ?MODULE:stop(Req, Context1);
+maybe_get_req_data(Context, Req0, _Version) ->
{QS, Req1} = get_query_string_data(Req0),
get_req_data(Context, Req1, get_content_type(Req1), QS).
@@ -1149,12 +1160,11 @@ execute_request(Req, Context) ->
-spec execute_request(cowboy_req:req(), cb_context:context(), kz_term:ne_binary(), kz_term:ne_binaries(), http_method()) ->
{boolean() | 'stop', cowboy_req:req(), cb_context:context()}.
execute_request(Req, Context, Mod, Params, Verb) ->
- Context1 = maybe_set_accepting_charges(Context),
- Event = create_event_name(Context1, [<<"execute">>
- ,kz_term:to_lower_binary(Verb)
- ,Mod
- ]),
- Payload = [Context1 | Params],
+ Event = create_event_name(Context, [<<"execute">>
+ ,kz_term:to_lower_binary(Verb)
+ ,Mod
+ ]),
+ Payload = [Context | Params],
Context2 = crossbar_bindings:fold(Event, Payload),
case cb_context:is_context(Context2) of
@@ -1164,17 +1174,6 @@ execute_request(Req, Context, Mod, Params, Verb) ->
execute_request_failure(Req, Context, Context2)
end.
-%%------------------------------------------------------------------------------
-%% @doc Backwards compatibility: no 402 Payment Required for v1 APIs
-%% @end
-%%------------------------------------------------------------------------------
--spec maybe_set_accepting_charges(cb_context:context()) -> cb_context:context().
-maybe_set_accepting_charges(Context) ->
- case cb_context:api_version(Context) of
- <<"v1">> -> cb_context:set_accepting_charges(Context);
- _ -> Context
- end.
-
-spec execute_request_failure(cowboy_req:req(), cb_context:context(), any()) ->
{'false', cowboy_req:req(), cb_context:context()}.
execute_request_failure(Req, Context, {'error', _E}) ->
diff --git a/applications/crossbar/src/cb_context.erl b/applications/crossbar/src/cb_context.erl
index aedd8f66de5..ea3194bb9c7 100644
--- a/applications/crossbar/src/cb_context.erl
+++ b/applications/crossbar/src/cb_context.erl
@@ -433,9 +433,6 @@ path_tokens(#cb_context{raw_path=Path}) ->
magic_pathed(#cb_context{magic_pathed=MP}) -> MP.
-spec should_paginate(context()) -> boolean().
-should_paginate(#cb_context{api_version=?VERSION_1}) ->
- lager:debug("pagination disabled in this API version"),
- 'false';
should_paginate(#cb_context{should_paginate='undefined'}=Context) ->
case req_value(Context, <<"paginate">>) of
'undefined' -> 'true';
@@ -451,10 +448,6 @@ pagination_page_size() ->
-spec pagination_page_size(context()) -> pos_integer().
pagination_page_size(Context) ->
- pagination_page_size(Context, api_version(Context)).
-
--spec pagination_page_size(context(), kz_term:ne_binary()) -> pos_integer().
-pagination_page_size(Context, _Version) ->
case req_value(Context, <<"page_size">>) of
'undefined' -> pagination_page_size();
V ->
diff --git a/applications/crossbar/src/modules/cb_modules_util.erl b/applications/crossbar/src/cb_modules_util.erl
similarity index 93%
rename from applications/crossbar/src/modules/cb_modules_util.erl
rename to applications/crossbar/src/cb_modules_util.erl
index a641b775fdd..a5793bcfe8b 100644
--- a/applications/crossbar/src/modules/cb_modules_util.erl
+++ b/applications/crossbar/src/cb_modules_util.erl
@@ -39,6 +39,12 @@
,maybe_convert_numbers_to_list/1
]).
+-export([phonebook_port_in/1
+ ,phonebook_comment/2
+
+ ,should_send_to_phonebook/1
+ ]).
+
-include("crossbar.hrl").
-include_lib("kazoo_stdlib/include/kazoo_json.hrl").
@@ -85,6 +91,29 @@ cavs_from_request(ReqData, QueryString) ->
CAVs = kz_json:get_json_value(<<"custom_application_vars">>, ReqData, kz_json:new()),
kapps_call_util:filter_ccvs(kz_json:merge(CAVs, QueryString)).
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec phonebook_port_in(cb_context:context()) -> knm_phonebook:response().
+phonebook_port_in(Context) ->
+ knm_phonebook:maybe_create_port_in(cb_context:doc(Context), phonebook_options(Context)).
+
+-spec phonebook_comment(cb_context:context(), kz_json:objects()) -> knm_phonebook:response().
+phonebook_comment(Context, Comments) ->
+ knm_phonebook:maybe_add_comment(cb_context:doc(Context), Comments, phonebook_options(Context)).
+
+-spec should_send_to_phonebook(cb_context:context()) -> boolean().
+should_send_to_phonebook(Context) ->
+ knm_phonebook:should_send_to_phonebook(phonebook_options(Context)).
+
+phonebook_options(Context) ->
+ [{'auth_token', cb_context:auth_token(Context)}
+ ,{'port_authority_id', cb_context:fetch(Context, 'port_authority_id')}
+ ,{'master_account_id', cb_context:master_account_id(Context)}
+ ,{'user_agent', cb_context:req_header(Context, <<"User-Agent">>)}
+ ].
+
%%------------------------------------------------------------------------------
%% @doc Generate an attachment name if one is not provided and ensure
%% it has an extension (for the associated content type)
diff --git a/applications/crossbar/src/crossbar.app.src b/applications/crossbar/src/crossbar.app.src
index f3402429156..4a16a9f27fc 100644
--- a/applications/crossbar/src/crossbar.app.src
+++ b/applications/crossbar/src/crossbar.app.src
@@ -1,6 +1,6 @@
{application,crossbar,
- [{applications,[cowboy,cowlib,crypto,erlang_localtime,inets,
- kazoo,kazoo_amqp,kazoo_apps,kazoo_attachments,
+ [{applications,[cowboy,cowlib,crypto,erlang_localtime,kazoo,
+ kazoo_amqp,kazoo_apps,kazoo_attachments,
kazoo_auth,kazoo_bindings,kazoo_caches,
kazoo_call,kazoo_config,kazoo_csv,kazoo_data,
kazoo_databases,kazoo_documents,kazoo_endpoint,
@@ -16,6 +16,6 @@
{env,[{is_kazoo_app,true}]},
{mod,{crossbar_app,[]}},
{modules,[]},
- {registered,[crossbar_cache,cb_jobs_listener,crossbar_sup,
+ {registered,[crossbar_cache,crossbar_jobs_listener,crossbar_sup,
crossbar_module_sup]},
{vsn,"4.0.0"}]}.
diff --git a/applications/crossbar/src/crossbar.hrl b/applications/crossbar/src/crossbar.hrl
index 86f6a6b0d80..ddf163bfbe1 100644
--- a/applications/crossbar/src/crossbar.hrl
+++ b/applications/crossbar/src/crossbar.hrl
@@ -117,7 +117,6 @@
,'cb_sms'
,'cb_system_configs'
,'cb_tasks'
- ,'cb_templates'
,'cb_temporal_rules'
,'cb_temporal_rules_sets'
,'cb_token_auth'
@@ -131,9 +130,17 @@
,'cb_whitelabel'
]).
--define(DEPRECATED_MODULES, ['cb_local_resources'
+-define(DEPRECATED_MODULES, ['cb_bulk'
+ ,'cb_freeswitch'
+ ,'cb_global_provisioner_templates'
,'cb_global_resources'
+ ,'cb_local_provisioner_templates'
+ ,'cb_local_resources'
+ ,'cb_onboard'
+ ,'cb_shared_auth'
,'cb_signup'
+ ,'cb_templates'
+ ,'cb_ubiquiti_auth'
]).
-record(cb_context, {content_types_provided = [] :: crossbar_content_handlers()
@@ -183,7 +190,7 @@
,client_ip = <<"127.0.0.1">> :: kz_term:api_ne_binary()
,load_merge_bypass :: kz_term:api_object()
,profile_id :: kz_term:api_ne_binary()
- ,api_version = ?VERSION_1 :: kz_term:ne_binary()
+ ,api_version = ?VERSION_2 :: kz_term:ne_binary()
,magic_pathed = 'false' :: boolean()
,should_paginate :: kz_term:api_boolean()
,host_url = <<>> :: binary()
@@ -206,10 +213,6 @@
,{<<"connectivity">>, <<"sys_info">>}
,{<<"directories">>, <<"directory">>}
,{<<"faxes">>, <<"fax">>}
- ,{<<"global_provisioner_templates">>, <<"provisioner_template">>}
- ,{<<"global_resources">>, <<"resource">>}
- ,{<<"local_provisioner_templates">>, <<"provisioner_template">>}
- ,{<<"local_resources">>, <<"resource">>}
,{<<"rate_limit">>, <<"resource">>}
,{<<"sms">>, <<"sms">>}
,{<<"phone_numbers">>, <<"phone_numbers">>} %% weird...
diff --git a/applications/crossbar/src/crossbar_auth.erl b/applications/crossbar/src/crossbar_auth.erl
index cb7430fe174..02ed4352ae0 100644
--- a/applications/crossbar/src/crossbar_auth.erl
+++ b/applications/crossbar/src/crossbar_auth.erl
@@ -37,7 +37,6 @@
,{<<"cb_api_auth">>, ?DEFAULT_METHOD_CONFIG('false')}
,{<<"cb_auth">>, ?DEFAULT_METHOD_CONFIG('false')}
,{<<"cb_ip_auth">>, ?DEFAULT_METHOD_CONFIG('false')}
- ,{<<"cb_ubiquiti_auth">>, ?DEFAULT_METHOD_CONFIG('false')}
]
)
).
diff --git a/applications/crossbar/src/crossbar_bindings.erl b/applications/crossbar/src/crossbar_bindings.erl
index c1b9b8a5783..6ec3982b131 100644
--- a/applications/crossbar/src/crossbar_bindings.erl
+++ b/applications/crossbar/src/crossbar_bindings.erl
@@ -52,10 +52,10 @@
-type payload() :: path_tokens() | % mapping over path tokens in URI
[cb_context:context() | path_token() | 'undefined',...] |
cb_context:context() |
- {cb_context:context(), kz_term:proplist()} | % v1_resource:rest_init/2
- {'error', _} | % v1_util:execute_request/2
+ {cb_context:context(), kz_term:proplist()} | % api_resource:rest_init/2
+ {'error', _} | % api_util:execute_request/2
{kz_json:path(), cb_context:context(), path_tokens()} |
- {kz_time:datetime(), cowboy_req:req(), cb_context:context()} | % v1_resource:expires/2
+ {kz_time:datetime(), cowboy_req:req(), cb_context:context()} | % api_resource:expires/2
{cowboy_req:req(), cb_context:context()}. % mapping over the request/context records
%%%=============================================================================
diff --git a/applications/crossbar/src/crossbar_doc.erl b/applications/crossbar/src/crossbar_doc.erl
index b0035e59fcf..c480645280c 100644
--- a/applications/crossbar/src/crossbar_doc.erl
+++ b/applications/crossbar/src/crossbar_doc.erl
@@ -998,9 +998,8 @@ maybe_apply_custom_filter(Context, FilterFun, JObjs) ->
-spec handle_datamgr_success(kz_json:object() | kz_json:objects(), cb_context:context()) -> cb_context:context().
handle_datamgr_success([], Context) ->
- cb_context:setters(handle_thing_success([], Context)
- ,version_specific_success([], Context)
- );
+ RespEnv = kz_json:set_value(<<"page_size">>, 0, cb_context:resp_envelope(Context)),
+ handle_thing_success([], cb_context:set_resp_envelope(Context, RespEnv));
handle_datamgr_success([JObj|_]=JObjs, Context) ->
case kz_json:is_json_object(JObj) of
'true' -> handle_json_success(JObjs, Context);
@@ -1061,12 +1060,13 @@ handle_json_success(JObjs, Context, _Verb) when is_list(JObjs) ->
|| JObj <- JObjs,
not kz_doc:is_soft_deleted(JObj)
],
+ RespEnv = kz_json:set_value(<<"page_size">>, length(JObjs), cb_context:resp_envelope(Context)),
cb_context:setters(Context
,[{fun cb_context:set_doc/2, JObjs}
,{fun cb_context:set_resp_status/2, 'success'}
,{fun cb_context:set_resp_data/2, RespData}
,{fun cb_context:set_resp_etag/2, rev_to_etag(JObjs)}
- | version_specific_success(JObjs, Context)
+ ,{fun cb_context:set_resp_envelope/2, RespEnv}
]);
handle_json_success(JObj, Context, ?HTTP_PUT) ->
RespHeaders = add_location_header(JObj, cb_context:resp_headers(Context)),
@@ -1094,17 +1094,6 @@ handle_json_success(JObj, Context, _Verb) ->
,{fun cb_context:set_resp_etag/2, rev_to_etag(JObj)}
]).
--spec version_specific_success(kz_json:objects(), cb_context:context()) -> list().
-version_specific_success(JObjs, Context) ->
- version_specific_success(JObjs, Context, cb_context:api_version(Context)).
-version_specific_success(_JObjs, _Context, ?VERSION_1) ->
- [];
-version_specific_success(JObjs, Context, _Version) ->
- [{fun cb_context:set_resp_envelope/2
- ,kz_json:set_value(<<"page_size">>, length(JObjs), cb_context:resp_envelope(Context))
- }
- ].
-
%%------------------------------------------------------------------------------
%% @doc
%% @end
diff --git a/applications/crossbar/src/crossbar_freeswitch.erl b/applications/crossbar/src/crossbar_freeswitch.erl
deleted file mode 100644
index efaf5dd120a..00000000000
--- a/applications/crossbar/src/crossbar_freeswitch.erl
+++ /dev/null
@@ -1,538 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Create freeswitch offline configuration
-%%% @author Luis Azedo
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(crossbar_freeswitch).
--behaviour(gen_server).
-
--export([start_link/0]).
--export([init/1
- ,handle_call/3
- ,handle_cast/2
- ,handle_info/2
- ,terminate/2
- ,code_change/3
- ]).
-
-
--export([reset/0]).
-
--include("crossbar.hrl").
--include_lib("kazoo_numbers/include/knm_phone_number.hrl").
-
--define(SERVER, ?MODULE).
-
--define(CALLFLOW_VIEW, <<"callflows/listing_by_number">>).
--define(DEVICES_VIEW, <<"devices/listing_by_owner">>).
-
--define(MOD_CONFIG_CAT, <<(?CONFIG_CAT)/binary, ".freeswitch">>).
-
--define(FS_DIALPLAN, 'freeswitch_dialplan').
--define(FS_CHATPLAN, 'freeswitch_chatplan').
--define(FS_DIRECTORY, 'freeswitch_directory').
-
--define(FS_DIRECTORY_REALM, 'freeswitch_directory_realm').
--define(FS_DIALPLAN_REALM, 'freeswitch_dialplan_realm').
--define(FS_CHATPLAN_REALM, 'freeswitch_chatplan_realm').
-
--define(DEFAULT_FS_TEMPLATES, [?FS_DIRECTORY]).
--define(DEFAULT_FS_INCLUDE_DIRECTORY_FILES, [?FS_DIALPLAN, ?FS_CHATPLAN]).
-
--define(FS_TEMPLATES, [?FS_DIRECTORY, ?FS_DIALPLAN, ?FS_CHATPLAN]).
--define(FS_REALM_TEMPLATES, [?FS_DIRECTORY_REALM]).
--define(FS_ALL_TEMPLATES, [?FS_DIRECTORY, ?FS_DIALPLAN, ?FS_CHATPLAN, ?FS_DIRECTORY_REALM]).
-
--define(AUTHN_TIMEOUT, 5 * ?MILLISECONDS_IN_SECOND).
-
--record(state, {config = 'undefined' :: kz_term:api_binary()
- ,is_running = 'false' :: boolean()
- ,monitor :: kz_term:api_reference()
- ,hourly_timer = hourly_timer() :: reference()
- }).
--type state() :: #state{}.
-
-%% this shouldn't be here. we need to move this definition from
-%% ecallmgr.hrl into the database or into kazoo/include
--define(CHANNEL_VAR_PREFIX, "ecallmgr_").
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec reset() -> 'ok'.
-reset() ->
- gen_server:cast(crossbar_sup:find_proc(?SERVER), 'reset').
-
-%%------------------------------------------------------------------------------
-%% @doc Starts the server
-%% @end
-%%------------------------------------------------------------------------------
--spec start_link() -> kz_types:startlink_ret().
-start_link() ->
- gen_server:start_link(?SERVER, [], []).
-
-%%%=============================================================================
-%%% gen_server callbacks
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc Initializes the server.
-%% @end
-%%------------------------------------------------------------------------------
--spec init([]) -> {ok, state()}.
-init([]) ->
- process_flag(trap_exit, 'true'),
- compile_templates(),
- _ = gen_server:cast(self(), 'periodic_build'),
- {'ok', #state{}}.
-
-%%------------------------------------------------------------------------------
-%% @doc Handling call messages.
-%% @end
-%%------------------------------------------------------------------------------
--spec handle_call(any(), kz_term:pid_ref(), state()) -> kz_types:handle_call_ret_state(state()).
-handle_call('current', _From, #state{config='undefined'}=State) ->
- {'reply', {'error', 'no_file'}, State};
-handle_call('current', _From, #state{config=Config}=State) ->
- {'reply', {'ok', Config}, State};
-
-handle_call(_Request, _From, State) ->
- {'reply', {'error', 'not_implemented'}, State}.
-
-%%------------------------------------------------------------------------------
-%% @doc Handling cast messages.
-%% @end
-%%------------------------------------------------------------------------------
--spec handle_cast(any(), state()) -> kz_types:handle_cast_ret_state(state()).
-handle_cast('periodic_build', #state{is_running='true'}=State) ->
- {'noreply', State};
-handle_cast('periodic_build', #state{is_running='false'}=State) ->
- {Pid, Monitor} = kz_process:spawn_monitor(fun build_freeswitch/1, [self()]),
- lager:debug("started new freeswitch offline configuration builder ~p", [Pid]),
- {'noreply', State#state{is_running='true', monitor=Monitor}};
-
-handle_cast({'completed', File}, #state{config=Config}=State) ->
- lager:debug("created new freeswitch offline configuration ~s", [File]),
- gen_server:cast(self(), {'delete', Config}),
- {'noreply', State#state{is_running='false', config=File}};
-
-handle_cast({'delete', 'undefined'}, State) ->
- {'noreply', State};
-handle_cast({'delete', File}, State) ->
- lager:debug("removing prior freeswitch offline configuration ~s", [File]),
- kz_util:delete_file(File),
- {'noreply', State};
-
-handle_cast('reset', #state{config=Config}=State) ->
- lager:debug("resetting freeswitch state"),
- gen_server:cast(self(), {'delete', Config}),
- {'noreply', State#state{is_running='false'}};
-
-handle_cast(_Msg, State) ->
- lager:debug("unhandled cast: ~p", [_Msg]),
- {'noreply', State}.
-
-%%------------------------------------------------------------------------------
-%% @doc Handling all non call/cast messages.
-%% @end
-%%------------------------------------------------------------------------------
--spec handle_info(any(), state()) -> kz_types:handle_info_ret_state(state()).
-handle_info({'DOWN', MonitorRef, 'process', _, 'normal'}, #state{monitor=MonitorRef}=State) ->
- {'noreply', State#state{is_running='false'}};
-handle_info({'DOWN', MonitorRef, _, _Pid, _Reason}, #state{monitor=MonitorRef}=State) ->
- lager:debug("freeswitch offline configuration builder ~p died unexpectedly: ~p"
- ,[_Pid, _Reason]),
- {'noreply', State#state{is_running='false'}};
-
-handle_info({timeout, Ref, _Msg}, #state{hourly_timer = Ref}=State) ->
- _ = gen_server:cast(self(), 'periodic_build'),
- {'noreply', State#state{hourly_timer = hourly_timer()}};
-
-handle_info(_Info, State) ->
- {'noreply', State}.
-
-%%------------------------------------------------------------------------------
-%% @doc This function is called by a `gen_server' when it is about to
-%% terminate. It should be the opposite of {@link init/1} and do any
-%% necessary cleaning up. When it returns, the `gen_server' terminates
-%% with Reason. The return value is ignored.
-%% @end
-%%------------------------------------------------------------------------------
--spec terminate(any(), state()) -> 'ok'.
-terminate(_Reason, _State) ->
- lager:debug("crossbar freeswitch terminating: ~p", [_Reason]).
-
-%%------------------------------------------------------------------------------
-%% @doc Convert process state when code is changed.
-%% @end
-%%------------------------------------------------------------------------------
--spec code_change(any(), state(), any()) -> {'ok', state()}.
-code_change(_OldVsn, State, _Extra) ->
- {'ok', State}.
-
-
-%%%=============================================================================
-%%% Internal functions
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec hourly_timer() -> reference().
-hourly_timer() ->
- erlang:start_timer(?MILLISECONDS_IN_HOUR, self(), ok).
-
--spec zip_directory(file:filename_all()) -> string().
-zip_directory(WorkDir0) ->
- WorkDir = kz_term:to_list(WorkDir0),
- ZipName = lists:concat([WorkDir, ".zip"]),
- Files = [kz_term:to_list(F) || F <- filelib:wildcard("*", WorkDir)],
- {'ok', _} = zip:zip(ZipName , Files, [{'cwd', WorkDir}]),
- ZipName.
-
--spec setup_directory() -> file:filename_all().
-setup_directory() ->
- TopDir = kz_binary:rand_hex(8),
- WorkRootDir = kapps_config:get_binary(?MOD_CONFIG_CAT, <<"work_dir">>, <<"/tmp/">>),
- WorkDir = filename:join([WorkRootDir, TopDir]),
- kz_util:make_dir(WorkDir),
- Files = [{<<"directory">>, ?FS_DIRECTORY}
- ,{<<"chatplan">>, ?FS_CHATPLAN}
- ,{<<"dialplan">>, ?FS_DIALPLAN}
- ],
- Filter = kapps_config:get(?MOD_CONFIG_CAT, <<"files_to_include">>, ?DEFAULT_FS_INCLUDE_DIRECTORY_FILES),
- _ = [kz_util:make_dir(filename:join([WorkDir, Dir])) || {Dir, _} <- Files],
- _ = [kz_util:write_file(filename:join([WorkDir, D, xml_file_name(T)])
- ,xml_file_from_config(T)
- )
- || {D, T} <- Files,
- lists:member(kz_term:to_binary(T), Filter)
- ],
- _ = put(<<"WorkDir">>, WorkDir),
- _ = put(<<"Realms">>, []),
- WorkDir.
-
--spec process_realms() -> 'ok'.
-process_realms() ->
- Realms = get(<<"Realms">>),
- Templates = [{<<"directory">>, ?FS_DIRECTORY_REALM}
- ,{<<"chatplan">>, ?FS_CHATPLAN_REALM}
- ,{<<"dialplan">>, ?FS_DIALPLAN_REALM}
- ],
- Filter = kapps_config:get(?MOD_CONFIG_CAT, <<"realm_templates_to_process">>, ?FS_REALM_TEMPLATES),
- _ = [process_realms(Realms, D, T)
- || {D, T} <- Templates,
- lists:member(kz_term:to_binary(T), Filter)
- ],
- 'ok'.
-
--spec process_realms(kz_term:api_binaries(), kz_term:ne_binary(), atom()) -> 'ok'.
-process_realms('undefined', _Dir, _Module) -> 'ok';
-process_realms([], _, _) -> 'ok';
-process_realms([Realm | Realms], Dir, Module) ->
- process_realm(Realm, Dir, Module),
- process_realms(Realms, Dir, Module).
-
--spec process_realm(kz_term:ne_binary(), kz_term:ne_binary(), atom()) -> 'ok'.
-process_realm(Realm, Dir, Module) ->
- Props = [{<<"realm">>, Realm}],
- WorkDir = get(<<"WorkDir">>),
- OutDir = filename:join([WorkDir, Dir]),
- kz_util:make_dir(OutDir),
- XMLFile = filename:join([OutDir, <>]),
- case kz_template:render(Module, Props) of
- {'ok', Result} ->
- kz_util:write_file(XMLFile, Result),
- lager:debug("wrote file ~s", [XMLFile]);
- {'error', E} ->
- lager:debug("error rendering template ~s for realm ~s: ~p"
- ,[Module, Realm, E])
- end.
-
--spec build_freeswitch(pid()) -> any().
-build_freeswitch(Pid) ->
- WorkDir = setup_directory(),
- lists:foreach(fun crawl_numbers_db/1, knm_util:get_all_number_dbs()),
- process_realms(),
- File = zip_directory(WorkDir),
- kz_util:delete_dir(kz_term:to_list(WorkDir)),
- gen_server:cast(Pid, {'completed', File}).
-
--spec crawl_numbers_db(kz_term:ne_binary()) -> 'ok'.
-crawl_numbers_db(NumberDb) ->
- lager:debug("getting all numbers from ~s",[NumberDb]),
- Db = kz_term:to_binary(http_uri:encode(kz_term:to_list(NumberDb))),
- try kz_datamgr:all_docs(Db) of
- {'ok', []} ->
- lager:debug("no number docs in ~s",[NumberDb]);
- {'ok', JObjs} ->
- Numbers = get_numbers(JObjs),
- maybe_export_numbers(Db, Numbers);
- {'error', _R} ->
- lager:debug("error getting number docs from ~s: ~p", [NumberDb, _R])
- catch
- _E:_R ->
- lager:debug("~s getting number docs from ~s: ~p", [_E, Db, _R])
- end.
-
--spec get_numbers(kz_json:objects()) -> kz_term:ne_binaries().
-get_numbers(JObjs) ->
- [Number
- || JObj <- JObjs,
- case (Number = kz_doc:id(JObj)) of
- <<"_design/", _/binary>> -> 'false';
- _Else -> 'true'
- end
- ].
-
--spec maybe_export_numbers(kz_term:ne_binary(), kz_term:ne_binaries()) -> 'ok'.
-maybe_export_numbers(_, []) -> 'ok';
-maybe_export_numbers(Db, [Number|Numbers]) ->
- _ = case kz_datamgr:open_doc(Db, Number) of
- {'ok', JObj} ->
- maybe_export_number(Number
- ,kzd_phone_numbers:pvt_state(JObj)
- ,kzd_phone_numbers:pvt_assigned_to(JObj)
- );
- {'error', _R} ->
- lager:debug("error fetching number ~s from ~d: ~p", [Number, Db, _R])
- end,
- maybe_export_numbers(Db, Numbers).
-
--spec maybe_export_number(kz_term:ne_binary(), kz_term:api_binary(), kz_term:api_binary()) -> 'ok'.
-maybe_export_number(Number, ?NUMBER_STATE_IN_SERVICE, AccountId) ->
- AccountDb = kz_util:format_account_id(AccountId, 'encoded'),
- ViewOptions = [{'key', Number}
- ,'include_docs'
- ],
- %% TODO: This is not very DB friendly as we are iterating the numbers
- %% and the callflows. Once possible improvement might be to walk
- %% the accounts, pulling all callflows and building for any assigned
- %% reconcilable number (instead of walking the numbers).
- case kz_datamgr:get_results(AccountDb, ?CALLFLOW_VIEW, ViewOptions) of
- {'ok', []} ->
- lager:debug("number ~s in service for account ~s but no callflows using it"
- ,[Number, AccountId]);
- {'ok', JObjs} ->
- Flows = [kz_json:get_value(<<"doc">>, JObj) || JObj <- JObjs],
- process_callflows(Number, AccountId, Flows);
- {'error', _R} ->
- lager:debug("unable to get callflows for number ~s in account ~s"
- ,[Number, AccountId])
- end;
-maybe_export_number(_, _, _) -> 'ok'.
-
--spec process_callflows(kz_term:ne_binary(), kz_term:ne_binary(), kz_json:objects()) -> 'ok'.
-process_callflows(_, _, []) -> 'ok';
-process_callflows(Number, AccountId, [JObj | JObjs]) ->
- FlowId = kz_doc:id(JObj),
- Flow = kz_json:get_value(<<"flow">>, JObj),
- lager:debug("processing callflow ~s in account ~s with number ~s"
- ,[FlowId, AccountId, Number]),
- process_callflow(Number, AccountId, Flow),
- process_callflows(Number, AccountId, JObjs).
-
--spec process_callflow(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:api_object()) -> 'ok'.
-process_callflow(_, _, 'undefined') -> 'ok';
-process_callflow(Number, AccountId, Flow) ->
- Module = kz_json:get_value(<<"module">>, Flow),
- Data = kz_json:get_value([<<"data">>,<<"id">>], Flow),
- Children = kz_json:get_value(<<"children">>, Flow),
- process_callflow(Number, AccountId, Module, Data),
- process_callflow(Number, AccountId
- ,case kz_json:is_empty(Children) of
- 'true' -> 'undefined';
- _ -> Children
- end).
-
--spec process_callflow(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:api_binary()) -> 'ok'.
-process_callflow(_, _, _, 'undefined') -> 'ok';
-process_callflow(Number, AccountId, <<"device">>, DeviceId) ->
- lager:debug("found device ~s associated with ~s", [DeviceId, Number]),
- AccountDb = kz_util:format_account_id(AccountId, 'encoded'),
- case kz_datamgr:open_cache_doc(AccountDb, DeviceId) of
- {'ok', JObj } -> process_device(Number, AccountId, JObj);
- {'error', _R} ->
- lager:debug("unable to get device ~s from account ~s: ~p"
- ,[DeviceId, AccountId, _R])
- end;
-process_callflow(Number, AccountId, <<"user">>, UserId) ->
- lager:debug("found user ~s associated with ~s", [UserId, Number]),
- AccountDb = kz_util:format_account_id(AccountId, 'encoded'),
- ViewOptions = [{'key', UserId}],
- case kz_datamgr:get_results(AccountDb, ?DEVICES_VIEW, ViewOptions) of
- {'ok', JObjs} ->
- Devices = [kz_json:get_value([<<"value">>,<<"id">>], JObj)
- || JObj <- JObjs,
- kz_json:is_false([<<"value">>, <<"hotdesked">>], JObj)
- ],
- [process_callflow(Number, AccountId, <<"device">>, DeviceId)
- || DeviceId <- Devices
- ];
- {'error', _R} ->
- lager:debug("unable to get user ~s from account ~s: ~p"
- ,[UserId, AccountId, _R])
- end;
-process_callflow(_, _, _, _) -> 'ok'.
-
--spec process_device(kz_term:ne_binary(), kz_term:ne_binary(), kz_json:object()) -> 'ok'.
-process_device(Number, AccountId, JObj) ->
- AccountRealm = kzd_accounts:fetch_realm(AccountId),
- Realm = kzd_devices:sip_realm(JObj, AccountRealm),
- Username = kzd_devices:sip_username(JObj),
- case query_registrar(Realm, Username) of
- {'ok', Auth} ->
- Props = props_for_rendering(Number, Username, Realm, Auth),
- render_templates(Number, AccountId, Username, Realm, Props),
- lager:debug("rendered templates");
- {'error', _R} ->
- lager:debug("unable to query registrar for credentials of ~s@~s in account ~s: ~p"
- ,[Username, Realm, AccountId, _R])
- end.
-
--spec props_for_rendering(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_json:object()) -> kz_term:proplist().
-props_for_rendering(Number, Username, Realm, Auth) ->
- props:filter_empty(
- kz_json:recursive_to_proplist(
- normalize(
- kz_json:set_values([{<<"effective_caller_id_number">>, Number}
- ,{<<"username">>, Username}
- ,{<<"realm">>, Realm}
- ,{<<"number">>, Number}
- ]
- ,Auth
- )))).
-
--spec normalize(kz_json:object()) -> kz_json:object().
-normalize(JObj) ->
- JHeaders = kz_json:get_value(<<"Custom-SIP-Headers">>, JObj, []),
- JVariables = kz_json:get_value(<<"Custom-Channel-Vars">>, JObj, []),
- Headers = [[{<<"name">>, K}, {<<"value">>, V}]
- || {K, V} <- kz_json:to_proplist(JHeaders)
- ],
- Variables = [[{<<"name">>, <>}, {<<"value">>, V}]
- || {K, V} <- kz_json:to_proplist(JVariables)
- ],
- kz_json:set_values([{<<"variables">>, Variables}
- ,{<<"headers">>, Headers}
- ]
- ,kz_json:normalize(
- kz_json:delete_keys([<<"Custom-SIP-Headers">>
- ,<<"Custom-Channel-Vars">>
- ]
- ,JObj
- )
- )).
-
--spec render_templates(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:proplist()) -> 'ok'.
-render_templates(Number, AccountId, Username, Realm, Props) ->
- Templates = [{"directory", ?FS_DIRECTORY}
- ,{"chatplan", ?FS_CHATPLAN}
- ,{"dialplan", ?FS_DIALPLAN}
- ],
- Filter = kapps_config:get(?MOD_CONFIG_CAT, <<"templates_to_process">>, ?DEFAULT_FS_TEMPLATES),
- _ = [render_template(Number, AccountId, Username, Realm, Props, D, T)
- || {D, T} <- Templates, lists:member(kz_term:to_binary(T), Filter)
- ],
- 'ok'.
-
--spec render_template(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:proplist(), file:name_all(), atom()) -> 'ok'.
-render_template(Number, AccountId, Username, Realm, Props, Dir, Module) ->
- maybe_accumulate_realm(lists:member(Realm, get(<<"Realms">>)), Realm),
- WorkDir = get(<<"WorkDir">>),
- OutDir = filename:join([WorkDir, Dir, Realm]),
- kz_util:make_dir(OutDir),
- XMLFile = filename:join([OutDir, <>]),
- case kz_template:render(Module, Props) of
- {'ok', Result} -> kz_util:write_file(XMLFile, Result);
- {'error', _R} ->
- lager:debug("unable to render template ~s for ~s in account ~s: ~p"
- ,[Module, Number, AccountId, _R])
- end.
-
--spec maybe_accumulate_realm(boolean(), kz_term:ne_binary()) -> any().
-maybe_accumulate_realm('true', _) -> 'ok';
-maybe_accumulate_realm('false', Realm) ->
- put(<<"Realms">>, [Realm | get(<<"Realms">>)]).
-
--spec query_registrar(kz_term:ne_binary(), kz_term:ne_binary()) -> {'ok', kz_json:object()}
- | {'error', any()}.
-query_registrar(Realm, Username) ->
- FullUser = <>,
- Req = [{<<"To">>, FullUser}
- ,{<<"From">>, FullUser}
- ,{<<"Auth-User">>, Username}
- ,{<<"Auth-Realm">>, Realm}
- ,{<<"Method">>, <<"REGISTER">>}
- | kz_api:default_headers(?APP_NAME, ?APP_VERSION)
- ],
- kz_amqp_worker:call(props:filter_undefined(Req)
- ,fun kapi_authn:publish_req/1
- ,fun kapi_authn:resp_v/1
- ,?AUTHN_TIMEOUT
- ).
-
--spec template_file(atom()) -> string().
-template_file(Module) ->
- filename:join([code:priv_dir(?APP), "freeswitch", template_file_name(Module)]).
-
--spec template_file_name(?FS_CHATPLAN | ?FS_DIALPLAN | ?FS_DIRECTORY | ?FS_DIRECTORY_REALM) -> string().
-template_file_name(?FS_DIALPLAN) -> "dialplan_template.xml";
-template_file_name(?FS_CHATPLAN) -> "chatplan_template.xml";
-template_file_name(?FS_DIRECTORY) -> "directory_template.xml";
-template_file_name(?FS_DIRECTORY_REALM) -> "directory_realm_template.xml".
-
--spec compile_templates() -> ok.
-compile_templates() ->
- F = fun (T) -> compile_template(kz_term:to_atom(T, 'true')) end,
- lists:foreach(F, ?FS_ALL_TEMPLATES).
-
--spec compile_template(atom()) -> 'ok'.
-compile_template(Module) ->
- compile_template(Module, kapps_config:get_binary(?MOD_CONFIG_CAT, kz_term:to_binary(Module))).
-
--spec compile_template(atom(), kz_term:api_binary()) -> 'ok'.
-compile_template(Module, 'undefined') ->
- {'ok', Contents} = file:read_file(template_file(Module)),
- _ = kapps_config:set(?MOD_CONFIG_CAT, kz_term:to_binary(Module), Contents),
- compile_template(Module, Contents);
-compile_template(Module, Template) ->
- _ = kz_template:compile(Template, Module),
- 'ok'.
-
--spec xml_file(atom()) -> string().
-xml_file(Module) ->
- filename:join([code:priv_dir(?APP), "freeswitch", xml_file_name(Module)]).
-
--spec xml_file_name(?FS_CHATPLAN | ?FS_DIALPLAN | ?FS_DIRECTORY) -> string().
-xml_file_name(?FS_DIALPLAN) -> "dialplan.xml";
-xml_file_name(?FS_CHATPLAN) -> "chatplan.xml";
-xml_file_name(?FS_DIRECTORY) -> "directory.xml".
-
--spec xml_file_from_config(?FS_CHATPLAN | ?FS_DIALPLAN | ?FS_DIRECTORY) -> kz_term:ne_binary().
-xml_file_from_config(Module) ->
- KeyName = <<(kz_term:to_binary(Module))/binary,"_top_dir_file_content">>,
- xml_file_from_config(Module, KeyName).
-
--spec xml_file_from_config(?FS_CHATPLAN | ?FS_DIALPLAN | ?FS_DIRECTORY, kz_term:ne_binary()) -> kz_term:ne_binary().
-xml_file_from_config(Module, KeyName) ->
- xml_file_from_config(Module, kapps_config:get_binary(?MOD_CONFIG_CAT, KeyName), KeyName).
-
--spec xml_file_from_config(atom(), kz_term:api_binary(), kz_term:ne_binary()) -> kz_term:ne_binary().
-xml_file_from_config(Module, 'undefined', KeyName) ->
- {'ok', Contents} = file:read_file(xml_file(Module)),
- _ = kapps_config:set(?MOD_CONFIG_CAT, KeyName, Contents),
- Contents;
-xml_file_from_config(_, Contents, _) -> Contents.
diff --git a/applications/crossbar/src/crossbar_init.erl b/applications/crossbar/src/crossbar_init.erl
index be52270c0c8..0441b2f04ec 100644
--- a/applications/crossbar/src/crossbar_init.erl
+++ b/applications/crossbar/src/crossbar_init.erl
@@ -79,10 +79,9 @@ start_link() ->
%%------------------------------------------------------------------------------
-spec is_versioned_module(binary()) -> boolean().
is_versioned_module(Module) ->
- Mod = lists:reverse(binary_to_list(Module)),
- case Mod of
- "1v_" ++ _ -> 'true';
- "2v_" ++ _ -> 'true';
+ case kz_binary:reverse(Module) of
+ <<"1v_", _/binary>> -> 'true';
+ <<"2v_", _/binary>> -> 'true';
_ -> 'false'
end.
diff --git a/applications/crossbar/src/modules/cb_jobs_listener.erl b/applications/crossbar/src/crossbar_jobs_listener.erl
similarity index 99%
rename from applications/crossbar/src/modules/cb_jobs_listener.erl
rename to applications/crossbar/src/crossbar_jobs_listener.erl
index 2dd26875f0d..4406639b965 100644
--- a/applications/crossbar/src/modules/cb_jobs_listener.erl
+++ b/applications/crossbar/src/crossbar_jobs_listener.erl
@@ -7,7 +7,7 @@
%%%
%%% @end
%%%-----------------------------------------------------------------------------
--module(cb_jobs_listener).
+-module(crossbar_jobs_listener).
-behaviour(gen_listener).
-export([start_link/0
diff --git a/applications/crossbar/src/crossbar_maintenance.erl b/applications/crossbar/src/crossbar_maintenance.erl
index d16e7b50cca..90423d72a7f 100644
--- a/applications/crossbar/src/crossbar_maintenance.erl
+++ b/applications/crossbar/src/crossbar_maintenance.erl
@@ -128,7 +128,7 @@ migrate_accounts_data([Account|Accounts]) ->
migrate_account_data(Account) ->
_ = cb_clicktocall:maybe_migrate_history(Account),
_ = cb_vmboxes:migrate(Account),
- _ = cb_lists_v2:maybe_migrate(Account),
+ _ = cb_lists:maybe_migrate(Account),
_ = cb_apps_maintenance:migrate(Account),
'no_return'.
diff --git a/applications/crossbar/src/crossbar_migration.erl b/applications/crossbar/src/crossbar_migration.erl
new file mode 100644
index 00000000000..321cab38f86
--- /dev/null
+++ b/applications/crossbar/src/crossbar_migration.erl
@@ -0,0 +1,46 @@
+%%%-----------------------------------------------------------------------------
+%%% @copyright (C) 2011-2019, 2600Hz
+%%% @doc Crawl accounts and disable notify settings so that we use Teletype instead
+%%% @author Mark Magnusson
+%%%
+%%% This Source Code Form is subject to the terms of the Mozilla Public
+%%% License, v. 2.0. If a copy of the MPL was not distributed with this
+%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
+%%%
+%%% @end
+%%%-----------------------------------------------------------------------------
+-module(crossbar_migration).
+
+-export([perform/3
+ ,list/0
+ ]).
+
+-include("crossbar.hrl").
+
+%% Id, Description, Callback Module
+-define(MIGRATIONS_LIST, kz_json:from_list(
+ [{<<"notify_to_teletype">>, <<"Migrate account and all sub accounts to Teletype">>}
+ ]
+ )
+ ).
+
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec list() -> kz_json:object().
+list() -> ?MIGRATIONS_LIST.
+
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec perform(kz_term:ne_binary(), kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
+perform(<<"notify_to_teletype">>, Account, Context) ->
+ lager:info("migrating account ~p from notify to teletype...", [Account]),
+
+ Updates = [{[<<"notifications">>, <<"voicemail_to_email">>], 'null'}
+ ,{[<<"notifications">>, <<"fax_to_email">>], 'null'}
+ ],
+ {'ok', _} = kzd_accounts:update(Account, Updates),
+ cb_context:set_resp_status(Context, 'success').
diff --git a/applications/crossbar/src/modules/notification_util.erl b/applications/crossbar/src/crossbar_notify_util.erl
similarity index 98%
rename from applications/crossbar/src/modules/notification_util.erl
rename to applications/crossbar/src/crossbar_notify_util.erl
index 15b3a259aab..da0b49a0832 100644
--- a/applications/crossbar/src/modules/notification_util.erl
+++ b/applications/crossbar/src/crossbar_notify_util.erl
@@ -9,7 +9,7 @@
%%%
%%% @end
%%%-----------------------------------------------------------------------------
--module(notification_util).
+-module(crossbar_notify_util).
-include("crossbar.hrl").
diff --git a/applications/crossbar/src/crossbar_services.erl b/applications/crossbar/src/crossbar_services.erl
index 62eb1bf53e6..33a453bd782 100644
--- a/applications/crossbar/src/crossbar_services.erl
+++ b/applications/crossbar/src/crossbar_services.erl
@@ -71,8 +71,7 @@ dry_run(Context, Quotes, 'true') ->
-spec should_dry_run(cb_context:context()) -> boolean().
should_dry_run(Context) ->
- cb_context:accepting_charges(Context) =/= 'true'
- andalso cb_context:api_version(Context) =/= ?VERSION_1.
+ cb_context:accepting_charges(Context) =/= 'true'.
-spec check_creditably(cb_context:context(), kz_services:services(), kz_services_invoices:invoices(), boolean() | number()) ->
cb_context:context().
diff --git a/applications/crossbar/src/crossbar_sup.erl b/applications/crossbar/src/crossbar_sup.erl
index f6eb59666b4..dc258e27156 100644
--- a/applications/crossbar/src/crossbar_sup.erl
+++ b/applications/crossbar/src/crossbar_sup.erl
@@ -36,8 +36,6 @@
]
).
--define(DISPATCH_FILE, [code:priv_dir(?APP), "/dispatch.conf"]).
-
%%==============================================================================
%% API functions
%%==============================================================================
diff --git a/applications/crossbar/src/crossbar_util.erl b/applications/crossbar/src/crossbar_util.erl
index 6cd23784d51..1e408355d0e 100644
--- a/applications/crossbar/src/crossbar_util.erl
+++ b/applications/crossbar/src/crossbar_util.erl
@@ -199,7 +199,7 @@ response_range_not_satisfiable(Context) ->
%%
%% The RedirectUrl should be relative to the accessed URL. So, if the
%% URL accessed that is deprecated is:
-%% `/v1/account/{AID}/module/{MID}'
+%% `/v2/account/{AID}/module/{MID}'
%% and that MID moved to `module2', the RedirectURL should be:
%% `../../module2/{MID}'
%%
diff --git a/applications/crossbar/src/modules/cb_accounts.erl b/applications/crossbar/src/modules/cb_accounts.erl
index c7ae7669e15..b2438f5e014 100644
--- a/applications/crossbar/src/modules/cb_accounts.erl
+++ b/applications/crossbar/src/modules/cb_accounts.erl
@@ -288,7 +288,7 @@ post(Context, AccountId) ->
case kzd_accounts:save(cb_context:doc(Context)) of
{'ok', SavedAccount} ->
Context1 = crossbar_doc:handle_datamgr_success(SavedAccount, Context),
- _ = kz_process:spawn(fun notification_util:maybe_notify_account_change/2, [Existing, Context]),
+ _ = kz_process:spawn(fun crossbar_notify_util:maybe_notify_account_change/2, [Existing, Context]),
update_provisioner_account(Context1),
leak_pvt_fields(AccountId, Context1);
@@ -843,26 +843,6 @@ leak_trial_time_left(Context, JObj, _Expiration) ->
%%------------------------------------------------------------------------------
-spec load_children(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
load_children(AccountId, Context) ->
- load_children(AccountId, Context, cb_context:api_version(Context)).
-
--spec load_children(kz_term:ne_binary(), cb_context:context(), kz_term:ne_binary()) -> cb_context:context().
-load_children(AccountId, Context, ?VERSION_1) ->
- load_children_v1(AccountId, Context);
-load_children(AccountId, Context, _Version) ->
- load_paginated_children(AccountId, Context).
-
--spec load_children_v1(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-load_children_v1(AccountId, Context) ->
- crossbar_doc:load_view(?AGG_VIEW_CHILDREN
- ,[{'startkey', [AccountId]}
- ,{'endkey', [AccountId, kz_json:new()]}
- ]
- ,Context
- ,fun normalize_view_results/2
- ).
-
--spec load_paginated_children(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-load_paginated_children(AccountId, Context) ->
StartKey = start_key(Context),
fix_envelope(
crossbar_doc:load_view(?AGG_VIEW_CHILDREN
@@ -879,25 +859,6 @@ load_paginated_children(AccountId, Context) ->
%%------------------------------------------------------------------------------
-spec load_descendants(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
load_descendants(AccountId, Context) ->
- load_descendants(AccountId, Context, cb_context:api_version(Context)).
-
-load_descendants(AccountId, Context, ?VERSION_1) ->
- load_descendants_v1(AccountId, Context);
-load_descendants(AccountId, Context, _Version) ->
- load_paginated_descendants(AccountId, Context).
-
--spec load_descendants_v1(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-load_descendants_v1(AccountId, Context) ->
- crossbar_doc:load_view(?AGG_VIEW_DESCENDANTS
- ,[{'startkey', [AccountId]}
- ,{'endkey', [AccountId, kz_json:new()]}
- ]
- ,Context
- ,fun normalize_view_results/2
- ).
-
--spec load_paginated_descendants(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-load_paginated_descendants(AccountId, Context) ->
StartKey = start_key(Context),
lager:debug("account ~s startkey ~s", [AccountId, StartKey]),
fix_envelope(
@@ -922,31 +883,10 @@ load_siblings(AccountId, Context) ->
andalso kapps_config:get_is_true(?ACCOUNTS_CONFIG_CAT, <<"allow_sibling_listing">>, 'true')
)
of
- 'true' -> load_siblings(AccountId, Context, cb_context:api_version(Context));
+ 'true' -> load_paginated_siblings(AccountId, Context);
'false' -> cb_context:add_system_error('forbidden', Context)
end.
--spec load_siblings(kz_term:ne_binary(), cb_context:context(), kz_term:ne_binary()) -> cb_context:context().
-load_siblings(AccountId, Context, ?VERSION_1) ->
- load_siblings_v1(AccountId, Context);
-load_siblings(AccountId, Context, _Version) ->
- load_paginated_siblings(AccountId, Context).
-
--spec load_siblings_v1(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-load_siblings_v1(AccountId, Context) ->
- Context1 = crossbar_doc:load_view(?AGG_VIEW_PARENT
- ,[{'startkey', AccountId}
- ,{'endkey', AccountId}
- ]
- ,Context
- ),
- case cb_context:resp_status(Context1) of
- 'success' ->
- load_siblings_results(AccountId, Context1, cb_context:doc(Context1));
- _Status ->
- cb_context:add_system_error('bad_identifier', kz_json:from_list([{<<"cause">>, AccountId}]), Context)
- end.
-
-spec load_paginated_siblings(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
load_paginated_siblings(AccountId, Context) ->
Context1 =
diff --git a/applications/crossbar/src/modules/cb_alerts.erl b/applications/crossbar/src/modules/cb_alerts.erl
index 3a5eafbaf94..7c157baead0 100644
--- a/applications/crossbar/src/modules/cb_alerts.erl
+++ b/applications/crossbar/src/modules/cb_alerts.erl
@@ -1,6 +1,6 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
+%%% @doc Crossbar API for alerts.
%%% @author Peter Defebvre
%%%
%%% This Source Code Form is subject to the terms of the Mozilla Public
diff --git a/applications/crossbar/src/modules/cb_apps_link.erl b/applications/crossbar/src/modules/cb_apps_link.erl
index 58a71460106..e4ba1e6e148 100644
--- a/applications/crossbar/src/modules/cb_apps_link.erl
+++ b/applications/crossbar/src/modules/cb_apps_link.erl
@@ -1,6 +1,6 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
+%%% @doc Crossbar API for apps link.
%%% @author Karl Anderson
%%% @author James Aimonetti
%%%
diff --git a/applications/crossbar/src/modules/cb_apps_store.erl b/applications/crossbar/src/modules/cb_apps_store.erl
index dac83b49ae9..53aba7b4105 100644
--- a/applications/crossbar/src/modules/cb_apps_store.erl
+++ b/applications/crossbar/src/modules/cb_apps_store.erl
@@ -1,6 +1,6 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2013-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
+%%% @doc Crossbar API for apps store.
%%% @author Peter Defebvre
%%%
%%% This Source Code Form is subject to the terms of the Mozilla Public
diff --git a/applications/crossbar/src/modules/cb_att_handlers_errors.erl b/applications/crossbar/src/modules/cb_att_handlers_errors.erl
index 10339205042..faa51d90ac6 100644
--- a/applications/crossbar/src/modules/cb_att_handlers_errors.erl
+++ b/applications/crossbar/src/modules/cb_att_handlers_errors.erl
@@ -34,7 +34,6 @@ init() ->
Bindings = [{<<"*.allowed_methods">>, 'allowed_methods'}
,{<<"*.resource_exists">>, 'resource_exists'}
,{<<"*.validate">>, 'validate'}
- ,{<<"*.execute.get">>, 'get'}
],
_ = [crossbar_bindings:bind(<>, ?MODULE, Fun)
|| {Binding, Fun} <- Bindings
diff --git a/applications/crossbar/src/modules/cb_bulk.erl b/applications/crossbar/src/modules/cb_bulk.erl
deleted file mode 100644
index 7a042809ed9..00000000000
--- a/applications/crossbar/src/modules/cb_bulk.erl
+++ /dev/null
@@ -1,392 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
-%%% @author Karl Anderson
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_bulk).
-
--export([init/0
- ,allowed_methods/0
- ,resource_exists/0
- ,validate/1
- ,post/1
- ,delete/1
- ]).
-
--include("crossbar.hrl").
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc Initializes the bindings this module will respond to.
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> 'ok'.
-init() ->
- _ = crossbar_bindings:bind(<<"*.allowed_methods.bulk">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"*.resource_exists.bulk">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"*.validate.bulk">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"*.execute.put.bulk">>, ?MODULE, 'put'),
- _ = crossbar_bindings:bind(<<"*.execute.post.bulk">>, ?MODULE, 'post'),
- _ = crossbar_bindings:bind(<<"*.execute.delete.bulk">>, ?MODULE, 'delete').
-
-%%------------------------------------------------------------------------------
-%% @doc Given the path tokens related to this module, what HTTP methods are
-%% going to be responded to.
-%% @end
-%%------------------------------------------------------------------------------
--spec allowed_methods() -> http_methods().
-allowed_methods() -> [?HTTP_GET, ?HTTP_POST, ?HTTP_DELETE].
-
-%%------------------------------------------------------------------------------
-%% @doc Does the path point to a valid resource.
-%% For example:
-%%
-%% ```
-%% /bulk => []
-%% /bulk/foo => [<<"foo">>]
-%% /bulk/foo/bar => [<<"foo">>, <<"bar">>]
-%% '''
-%% @end
-%%------------------------------------------------------------------------------
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc Check the request (request body, query string params, path tokens, etc)
-%% and load necessary information.
-%% /bulk might load a list of bulk_update objects
-%% /bulk/123 might load the bulk_update object 123
-%% @end
-%%------------------------------------------------------------------------------
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- maybe_load_docs(Context).
-
--spec maybe_load_docs(cb_context:context()) -> cb_context:context().
-maybe_load_docs(Context) ->
- JObj = cb_context:req_data(Context),
- Ids = sets:from_list(kz_json:get_list_value(<<"ids">>, JObj, [])),
- Context1 = crossbar_doc:load(sets:to_list(Ids), Context, ?TYPE_CHECK_OPTION_ANY),
- case cb_context:resp_status(Context1) of
- 'success' -> maybe_follow_groups(Ids, Context1);
- _Else -> Context1
- end.
-
--spec maybe_follow_groups(sets:set(), cb_context:context()) -> cb_context:context().
-maybe_follow_groups(Ids, Context) ->
- maybe_follow_groups(cb_context:doc(Context), Ids, cb_context:set_doc(Context, [])).
-
--spec maybe_follow_groups(kz_json:objects(), sets:set(), cb_context:context()) ->
- cb_context:context().
-maybe_follow_groups([], _, Context) ->
- maybe_update_docs(Context);
-maybe_follow_groups([JObj|JObjs], Ids, Context) ->
- Docs = cb_context:doc(Context),
- case kz_doc:type(JObj) of
- <<"group">> ->
- follow_group(JObj, JObjs, Ids, Context);
- _Else ->
- Context1 = cb_context:set_doc(Context, [JObj|Docs]),
- maybe_follow_groups(JObjs, Ids, Context1)
- end.
-
--spec follow_group(kz_json:object(), kz_json:objects(), sets:set(), cb_context:context()) ->
- cb_context:context().
-follow_group(JObj, JObjs, Ids, Context) ->
- lager:debug("trying to follow group members"),
- Members = lists:foldr(fun(Id, S) ->
- case sets:is_element(Id, Ids) of
- 'true' -> S;
- 'false' -> sets:add_element(Id, S)
- end
- end, sets:new(), kz_json:get_keys(<<"endpoints">>, JObj)),
- Context1 = crossbar_doc:load(sets:to_list(Members), Context, ?TYPE_CHECK_OPTION_ANY),
- case cb_context:resp_status(Context1) of
- 'success' ->
- NewJObjs = cb_context:doc(Context1),
- maybe_follow_groups(NewJObjs ++ JObjs
- ,sets:union(Ids, Members)
- ,Context);
- _Else ->
- lager:info("failed to follow group, continuing"),
- maybe_follow_groups(JObjs
- ,sets:union(Ids, Members)
- ,Context)
- end.
-
--spec maybe_update_docs(cb_context:context()) -> cb_context:context().
-maybe_update_docs(Context) ->
- case get_doc_updates(Context) of
- 'undefined' ->
- lager:debug("no update provided, returning docs"),
- Context;
- Updates ->
- revalidate_docs(update_docs(Updates, Context))
- end.
-
--spec revalidate_docs(cb_context:context()) -> cb_context:context().
-revalidate_docs(Context) ->
- JObjs = cb_context:doc(Context),
- Context1 = cb_context:setters(Context
- ,[{fun cb_context:set_doc/2, []}
- ,{fun cb_context:set_resp_data/2, kz_json:new()}
- ]),
- revalidate_docs(JObjs, Context1).
-
--spec revalidate_docs(kz_json:objects(), cb_context:context()) -> cb_context:context().
-revalidate_docs([], Context) ->
- Context;
-revalidate_docs([JObj|JObjs], Context) ->
- revalidate_docs(JObjs, revalidate_doc(JObj, Context)).
-
--spec revalidate_doc(kz_json:object(), cb_context:context()) -> cb_context:context().
-revalidate_doc(JObj, Context) ->
- case kz_doc:id(JObj) of
- 'undefined' -> Context;
- Id -> revalidate_doc(Id, JObj, Context)
- end.
-
--spec revalidate_doc(kz_term:ne_binary(), kz_json:object(), cb_context:context()) ->
- cb_context:context().
-revalidate_doc(Id, JObj, Context) ->
- case get_validate_binding(JObj) of
- 'undefined' ->
- Details = [{<<"type">>, kz_doc:type(JObj)}],
- InterimContext = cb_context:add_system_error('invalid_bulk_type'
- ,kz_json:from_list(Details)
- ,cb_context:new()
- ),
- import_results(Id, InterimContext, Context);
- Binding ->
- Setters = [{fun cb_context:set_req_verb/2, ?HTTP_POST}
- ,{fun cb_context:set_method/2, ?HTTP_POST}
- ,{fun cb_context:set_auth_token/2, cb_context:auth_token(Context)}
- ,{fun cb_context:set_auth_account_id/2, cb_context:auth_account_id(Context)}
- ,{fun cb_context:set_auth_doc/2, cb_context:auth_doc(Context)}
- ,{fun cb_context:set_account_id/2, cb_context:account_id(Context)}
- ,{fun cb_context:set_account_db/2, cb_context:account_db(Context)}
- ,{fun cb_context:set_req_id/2, cb_context:req_id(Context)}
- ,{fun cb_context:set_query_string/2, cb_context:query_string(Context)}
- ,{fun cb_context:set_doc/2, JObj}
- ,{fun cb_context:set_req_data/2, JObj}
- ,{fun cb_context:set_resp_status/2, 'fatal'}
- ,{fun cb_context:set_load_merge_bypass/2, JObj}
- ],
- C = cb_context:setters(cb_context:new(), Setters),
- Payload = [C, Id],
- run_binding(Binding, Payload, Id, Context)
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec post(cb_context:context()) -> cb_context:context().
-post(Context) ->
- JObjs = cb_context:doc(Context),
- maybe_save_docs(JObjs, Context).
-
--spec maybe_save_docs(kz_json:objects(), cb_context:context()) ->
- cb_context:context().
-maybe_save_docs(JObjs, Context) ->
- lists:foldl(fun maybe_save_doc/2, Context, JObjs).
-
--spec maybe_save_doc(kz_json:object(), cb_context:context()) ->
- cb_context:context().
-maybe_save_doc(JObj, Context) ->
- Doc = kz_json:get_value(<<"doc">>, JObj),
- DbDoc = kz_json:get_value(<<"db_doc">>, JObj),
-
- case kz_doc:id(Doc) of
- 'undefined' -> Context;
- Id -> maybe_save_doc(Id, Doc, DbDoc, Context)
- end.
-
--spec maybe_save_doc(kz_term:ne_binary(), kz_json:object(), kz_json:object(), cb_context:context()) ->
- cb_context:context().
-maybe_save_doc(Id, JObj, DbDoc, Context) ->
- case get_post_binding(JObj) of
- 'undefined' ->
- Details = [{<<"type">>, kz_doc:type(JObj)}],
- InterimContext = cb_context:add_system_error('invalid_bulk_type'
- ,kz_json:from_list(Details)
- ,cb_context:new()
- ),
- import_results(Id, InterimContext, Context);
- Binding ->
- Setters = [{fun cb_context:set_req_verb/2, ?HTTP_POST}
- ,{fun cb_context:set_method/2, ?HTTP_POST}
- ,{fun cb_context:set_auth_token/2, cb_context:auth_token(Context)}
- ,{fun cb_context:set_auth_account_id/2, cb_context:auth_account_id(Context)}
- ,{fun cb_context:set_auth_doc/2, cb_context:auth_doc(Context)}
- ,{fun cb_context:set_account_id/2, cb_context:account_id(Context)}
- ,{fun cb_context:set_account_db/2, cb_context:account_db(Context)}
- ,{fun cb_context:set_req_id/2, cb_context:req_id(Context)}
- ,{fun cb_context:set_query_string/2, cb_context:query_string(Context)}
- ,{fun cb_context:set_doc/2, JObj}
- ,{fun cb_context:set_req_data/2, JObj}
- ,{fun cb_context:set_resp_status/2, 'success'}
- ],
- C = cb_context:setters(cb_context:new(), Setters),
- Payload = [cb_context:store(C, 'db_doc', DbDoc), Id],
- run_binding(Binding, Payload, Id, Context)
- end.
-
--spec delete(cb_context:context()) -> cb_context:context().
-delete(Context) ->
- JObjs = cb_context:doc(Context),
- Context1 = cb_context:set_resp_data(Context, kz_json:new()),
- maybe_delete_docs(JObjs, Context1).
-
--spec maybe_delete_docs(kz_json:objects(), cb_context:context()) ->
- cb_context:context().
-maybe_delete_docs(JObjs, Context) ->
- lists:foldl(fun maybe_delete_doc/2, Context, JObjs).
-
--spec maybe_delete_doc(kz_json:object(), cb_context:context()) ->
- cb_context:context().
-maybe_delete_doc(JObj, Context) ->
- Doc = kz_json:get_value(<<"doc">>, JObj),
- DbDoc = kz_json:get_value(<<"db_doc">>, JObj),
-
- case kz_doc:id(Doc) of
- 'undefined' -> Context;
- Id -> maybe_delete_doc(Id, Doc, DbDoc, Context)
- end.
-
--spec maybe_delete_doc(kz_term:ne_binary(), kz_json:object(), kz_json:object(), cb_context:context()) ->
- cb_context:context().
-maybe_delete_doc(Id, JObj, DbDoc, Context) ->
- lager:debug("try to delete ~p", [Id]),
- case get_delete_binding(JObj) of
- 'undefined' ->
- Details = [{<<"type">>, kz_doc:type(JObj)}],
- InterimContext = cb_context:add_system_error('invalid_bulk_type'
- ,kz_json:from_list(Details)
- ,cb_context:new()
- ),
- import_results(Id, InterimContext, Context);
- Binding ->
- Setters = [{fun cb_context:set_req_verb/2, ?HTTP_DELETE}
- ,{fun cb_context:set_method/2, ?HTTP_DELETE}
- ,{fun cb_context:set_auth_token/2, cb_context:auth_token(Context)}
- ,{fun cb_context:set_auth_account_id/2, cb_context:auth_account_id(Context)}
- ,{fun cb_context:set_auth_doc/2, cb_context:auth_doc(Context)}
- ,{fun cb_context:set_account_id/2, cb_context:account_id(Context)}
- ,{fun cb_context:set_account_db/2, cb_context:account_db(Context)}
- ,{fun cb_context:set_req_id/2, cb_context:req_id(Context)}
- ,{fun cb_context:set_query_string/2, cb_context:query_string(Context)}
- ,{fun cb_context:set_doc/2, JObj}
- ,{fun cb_context:set_req_data/2, JObj}
- ],
- C = cb_context:setters(cb_context:new(), Setters),
- Payload = [cb_context:store(C, 'db_doc', DbDoc), Id],
- run_binding(Binding, Payload, Id, Context)
- end.
-
--spec run_binding(kz_term:ne_binary(), list(), kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-run_binding(Binding, Payload, Id, Context) ->
- lager:debug("bulk update running: ~p", [Binding]),
- InterimContext = crossbar_bindings:fold(Binding, Payload),
- import_results(Id, cb_context:import_errors(InterimContext), Context).
-
--spec import_results(kz_term:ne_binary(), cb_context:context(), cb_context:context()) ->
- cb_context:context().
-import_results(Id, C, Context) ->
- case cb_context:resp_status(C) of
- 'success' -> import_results_success(Id, C, Context);
- _Error -> import_results_error(Id, C, Context)
- end.
-
--spec import_results_success(kz_term:ne_binary(), cb_context:context(), cb_context:context()) ->
- cb_context:context().
-import_results_success(Id, C, Context) ->
- Doc = cb_context:doc(C),
- Docs = cb_context:doc(Context),
- JObj = cb_context:resp_data(Context),
- DbDoc = select_doc(Id, cb_context:fetch(Context, 'db_doc')),
- Resp = kz_json:from_list([{<<"status">>, <<"success">>}]),
- cb_context:setters(Context
- ,[{fun cb_context:set_resp_data/2, kz_json:set_value(Id, Resp, JObj)}
- ,{fun cb_context:set_doc/2
- ,[kz_json:from_list([{<<"doc">>, Doc}
- ,{<<"db_doc">>, DbDoc}
- ])
- | Docs
- ]
- }
- ]).
-
--spec import_results_error(kz_term:ne_binary(), cb_context:context(), cb_context:context()) ->
- cb_context:context().
-import_results_error(Id, C, Context) ->
- Status = cb_context:resp_status(C),
- ErrorCode = cb_context:resp_error_code(C),
- ErrorMsg = cb_context:resp_error_msg(C),
- Errors = cb_context:resp_data(C),
- JObj = cb_context:resp_data(Context),
-
- Resp = kz_json:from_list([{<<"status">>, kz_term:to_binary(Status)}
- ,{<<"error">>, ErrorCode}
- ,{<<"message">>, ErrorMsg}
- ,{<<"data">>, Errors}
- ]),
- cb_context:set_resp_data(Context, kz_json:set_value(Id, Resp, JObj)).
-
--spec select_doc(kz_term:ne_binary(), kz_json:objects()) -> kz_term:api_object().
-select_doc(_Id, []) -> 'undefined';
-select_doc(Id, [JObj|JObjs]) ->
- case kz_doc:id(JObj) of
- Id -> JObj;
- _ -> select_doc(Id, JObjs)
- end.
-
--spec get_doc_updates(cb_context:context()) -> kz_term:api_object().
-get_doc_updates(Context) ->
- JObj = cb_context:req_data(Context),
- case kz_json:get_value(<<"updates">>, JObj) of
- 'undefined' -> 'undefined';
- Updates -> kz_doc:public_fields(Updates)
- end.
-
--spec update_docs(kz_json:object(), cb_context:context()) ->
- cb_context:context().
-update_docs(Updates, Context) ->
- JObjs = [kz_json:merge(JObj, Updates)
- || JObj <- cb_context:doc(Context)
- ],
- cb_context:set_doc(Context, JObjs).
-
--spec get_post_binding(kz_json:object() | kz_term:ne_binary()) -> kz_term:api_binary().
-get_post_binding(<<"device">>) -> <<"v1_resource.execute.post.devices">>;
-get_post_binding(<<"user">>) -> <<"v1_resource.execute.post.users">>;
-get_post_binding(<<"conference">>) -> <<"v1_resource.execute.post.conferences">>;
-get_post_binding(<<"vmbox">>) -> <<"v1_resource.execute.post.vmboxes">>;
-get_post_binding(<<_/binary>>) -> 'undefined';
-get_post_binding(JObj) -> get_post_binding(kz_doc:type(JObj)).
-
--spec get_delete_binding(kz_json:object() | kz_term:ne_binary()) -> kz_term:api_binary().
-get_delete_binding(<<"device">>) -> <<"v1_resource.execute.delete.devices">>;
-get_delete_binding(<<"user">>) -> <<"v1_resource.execute.delete.users">>;
-get_delete_binding(<<"conference">>) -> <<"v1_resource.execute.delete.conferences">>;
-get_delete_binding(<<"vmbox">>) -> <<"v1_resource.execute.delete.vmboxes">>;
-get_delete_binding(<<_/binary>>) -> 'undefined';
-get_delete_binding(JObj) -> get_delete_binding(kz_doc:type(JObj)).
-
--spec get_validate_binding(kz_json:object() | kz_term:ne_binary()) -> kz_term:api_binary().
-get_validate_binding(<<"device">>) -> <<"v1_resource.validate.devices">>;
-get_validate_binding(<<"user">>) -> <<"v1_resource.validate.users">>;
-get_validate_binding(<<"conference">>) -> <<"v1_resource.validate.conferences">>;
-get_validate_binding(<<"vmbox">>) -> <<"v1_resource.validate.vmboxes">>;
-get_validate_binding(<<_/binary>>) -> 'undefined';
-get_validate_binding(JObj) -> get_validate_binding(kz_doc:type(JObj)).
diff --git a/applications/crossbar/src/modules/cb_comments.erl b/applications/crossbar/src/modules/cb_comments.erl
index 8f0b050e9e1..5e9bc62be42 100644
--- a/applications/crossbar/src/modules/cb_comments.erl
+++ b/applications/crossbar/src/modules/cb_comments.erl
@@ -1,6 +1,6 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
+%%% @doc Crossbar API for comment.
%%% @author Karl Anderson
%%% @author James Aimonetti
%%%
@@ -259,7 +259,7 @@ create(Context) ->
-spec create(cb_context:context(), {kz_term:ne_binary(), kz_term:ne_binaries()}) -> cb_context:context().
create(Context, {<<"port_requests">>, _}) ->
NewComments = cb_context:fetch(Context, 'req_comments', []),
- case phonebook:maybe_add_comment(Context, NewComments) of
+ case cb_modules_util:phonebook_comment(Context, NewComments) of
{'ok', _} ->
crossbar_doc:save(Context);
{'error', _} ->
diff --git a/applications/crossbar/src/modules/cb_contact_list.erl b/applications/crossbar/src/modules/cb_contact_list.erl
index 1df01bed9d1..c8a1bf8cc92 100644
--- a/applications/crossbar/src/modules/cb_contact_list.erl
+++ b/applications/crossbar/src/modules/cb_contact_list.erl
@@ -1,6 +1,6 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
+%%% @doc Crossbar API for contact list.
%%% @author Karl Anderson
%%% @author James Aimonetti
%%%
diff --git a/applications/crossbar/src/modules_v2/cb_devices_v2.erl b/applications/crossbar/src/modules/cb_devices.erl
similarity index 98%
rename from applications/crossbar/src/modules_v2/cb_devices_v2.erl
rename to applications/crossbar/src/modules/cb_devices.erl
index 01eeb825649..ca99ed5996a 100644
--- a/applications/crossbar/src/modules_v2/cb_devices_v2.erl
+++ b/applications/crossbar/src/modules/cb_devices.erl
@@ -13,7 +13,7 @@
%%%
%%% @end
%%%-----------------------------------------------------------------------------
--module(cb_devices_v2).
+-module(cb_devices).
-export([init/0
,allowed_methods/0, allowed_methods/1, allowed_methods/2
@@ -59,16 +59,16 @@
%%------------------------------------------------------------------------------
-spec init() -> 'ok'.
init() ->
- Bindings = [{<<"v2_resource.allowed_methods.devices">>, 'allowed_methods'}
- ,{<<"v2_resource.resource_exists.devices">>, 'resource_exists'}
- ,{<<"v2_resource.authenticate.devices">>, 'authenticate'}
- ,{<<"v2_resource.authorize.devices">>, 'authorize'}
- ,{<<"v2_resource.validate_resource.devices">>, 'validate_resource'}
- ,{<<"v2_resource.validate.devices">>, 'validate'}
- ,{<<"v2_resource.execute.put.devices">>, 'put'}
- ,{<<"v2_resource.execute.post.devices">>, 'post'}
- ,{<<"v2_resource.execute.patch.devices">>, 'patch'}
- ,{<<"v2_resource.execute.delete.devices">>, 'delete'}
+ Bindings = [{<<"*.allowed_methods.devices">>, 'allowed_methods'}
+ ,{<<"*.resource_exists.devices">>, 'resource_exists'}
+ ,{<<"*.authenticate.devices">>, 'authenticate'}
+ ,{<<"*.authorize.devices">>, 'authorize'}
+ ,{<<"*.validate_resource.devices">>, 'validate_resource'}
+ ,{<<"*.validate.devices">>, 'validate'}
+ ,{<<"*.execute.put.devices">>, 'put'}
+ ,{<<"*.execute.post.devices">>, 'post'}
+ ,{<<"*.execute.patch.devices">>, 'patch'}
+ ,{<<"*.execute.delete.devices">>, 'delete'}
],
cb_modules_util:bind(?MODULE, Bindings),
'ok'.
@@ -957,7 +957,7 @@ add_mdn(MDN, Context) ->
case knm_number:create(MDN, Options) of
{'error', _}=Error ->
_ = crossbar_doc:delete(Context),
- cb_phone_numbers_v2:set_response(Error, Context);
+ cb_phone_numbers:set_response(Error, Context);
{'ok', _} ->
lager:debug("created new mdn ~s with public fields set to ~s"
,[MDN, kz_json:encode(PublicFields)]
diff --git a/applications/crossbar/src/modules/cb_freeswitch.erl b/applications/crossbar/src/modules/cb_freeswitch.erl
deleted file mode 100644
index 4cf1a4b3d09..00000000000
--- a/applications/crossbar/src/modules/cb_freeswitch.erl
+++ /dev/null
@@ -1,173 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Handle CRUD operations for Directories
-%%% @author James Aimonetti
-%%% @author Luis Azedo
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_freeswitch).
-
--export([init/0
- ,allowed_methods/0
- ,resource_exists/0
- ,validate_freeswitch/1
- ,content_types_provided/1
- ,authenticate/1
- ,authorize/1
- ]).
-
--include("crossbar.hrl").
-
--define(FS_OFFLINE_SERVER, 'crossbar_freeswitch').
-
--define(MIME_TYPE_GZIP, {<<"application">>, <<"x-gzip">>}).
--define(MIME_TYPE_ZIP, {<<"application">>, <<"zip">>}).
--define(MIME_TYPE_ZIP2, <<"application/zip">>).
--define(MIME_TYPE_RAR, {<<"application">>, <<"x-rar-compressed">>}).
--define(MIME_TYPE_TAR, {<<"application">>, <<"x-tar">>}).
-
--define(MIME_TYPES, [?MIME_TYPE_GZIP
- ,?MIME_TYPE_ZIP
- ,?MIME_TYPE_RAR
- ,?MIME_TYPE_TAR
- ]).
-
--define(MOD_CONFIG_CAT, <<(?CONFIG_CAT)/binary, ".freeswitch">>).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> ok.
-init() ->
- _ = supervisor:start_child('crossbar_sup', ?WORKER(?FS_OFFLINE_SERVER)),
- _ = crossbar_bindings:bind(<<"*.authenticate">>, ?MODULE, 'authenticate'),
- _ = crossbar_bindings:bind(<<"*.authorize">>, ?MODULE, 'authorize'),
- _ = crossbar_bindings:bind(<<"*.content_types_provided.freeswitch">>, ?MODULE, 'content_types_provided'),
- _ = crossbar_bindings:bind(<<"*.allowed_methods.freeswitch">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"*.resource_exists.freeswitch">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"*.validate.freeswitch">>, ?MODULE, 'validate_freeswitch'),
- ok.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec authenticate(cb_context:context()) -> boolean().
-authenticate(Context) ->
- authenticate(cb_context:req_nouns(Context), cb_context:req_verb(Context), Context).
-
--spec authenticate(req_nouns(), http_method(), cb_context:context()) -> boolean().
-authenticate([{<<"freeswitch">>,[]}], ?HTTP_GET, Context) ->
- UserKey = kz_json:get_value(<<"key">>, cb_context:query_string(Context)),
- ServerKey = kapps_config:get_binary(?MOD_CONFIG_CAT
- ,<<"offline_configuration_key">>
- ,kz_binary:rand_hex(32)),
- case UserKey =:= ServerKey of
- 'true' ->
- lager:debug("authenticating offline configuration request", []),
- 'true';
- 'false' ->
- lager:debug("request for offline configuration with invalid key ~s"
- ,[UserKey]),
- 'false'
- end;
-authenticate(_Nouns, _Verb, _Context) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec authorize(cb_context:context()) -> boolean().
-authorize(Context) ->
- authorize(cb_context:req_nouns(Context), cb_context:req_verb(Context)).
-
--spec authorize(req_nouns(), http_method()) -> boolean().
-authorize([{<<"freeswitch">>,[]}], ?HTTP_GET) ->
- lager:debug("authorizing offline configuration request", []),
- 'true';
-authorize(_Nouns, _Verb) -> 'false'.
-
--spec content_types_provided(cb_context:context()) -> cb_context:context().
-content_types_provided(Context) ->
- cb_context:set_content_types_provided(Context, [{'to_binary', ?MIME_TYPES}]).
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
--spec allowed_methods() -> http_methods().
-allowed_methods() ->
- [?HTTP_GET].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
--spec validate_freeswitch(cb_context:context()) -> cb_context:context().
-validate_freeswitch(Context) ->
- validate_freeswitch(Context, cb_context:req_verb(Context)).
-
--spec validate_freeswitch(cb_context:context(), http_method()) -> cb_context:context().
-validate_freeswitch(Context, ?HTTP_GET) ->
- maybe_load_last_data(Context).
-
-%%%=============================================================================
-%%% Internal functions
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec maybe_load_last_data(cb_context:context()) -> cb_context:context().
-maybe_load_last_data(Context) ->
- case gen_server:call(crossbar_sup:find_proc(?FS_OFFLINE_SERVER), 'current') of
- {'ok', File} -> load_last_data(Context, File);
- {'error', Error} ->
- cb_context:add_system_error(Error, Context)
- end.
-
--spec load_last_data(cb_context:context(), kz_term:ne_binary()) -> cb_context:context().
-load_last_data(Context, File) ->
- {'ok', AttachBin} = file:read_file(File),
- BaseName = kz_term:to_binary(filename:basename(File)),
- ContentType = extension_to_content_type(kz_term:to_lower_binary(filename:extension(BaseName))),
- cb_context:setters(Context
- ,[{fun cb_context:set_resp_status/2, 'success'}
- ,{fun cb_context:set_resp_data/2, AttachBin}
- ,{fun cb_context:add_resp_headers/2,
- #{<<"content-disposition">> => <<"attachment; filename=", BaseName/binary>>
- ,<<"content-type">> => ContentType
- }
- }
- ]).
-
--spec extension_to_content_type(kz_term:ne_binary()) -> kz_term:ne_binary().
-extension_to_content_type(<<".gzip">>) -> ?MIME_TYPE_GZIP;
-extension_to_content_type(<<".zip">>) -> ?MIME_TYPE_ZIP2;
-extension_to_content_type(<<".rar">>) -> ?MIME_TYPE_RAR;
-extension_to_content_type(<<".tar">>) -> ?MIME_TYPE_TAR.
diff --git a/applications/crossbar/src/modules/cb_global_provisioner_templates.erl b/applications/crossbar/src/modules/cb_global_provisioner_templates.erl
deleted file mode 100644
index 493bbeb3128..00000000000
--- a/applications/crossbar/src/modules/cb_global_provisioner_templates.erl
+++ /dev/null
@@ -1,383 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Provision template module.
-%%% Handle client requests for provisioner template documents
-%%%
-%%% Regarding storing the template as an attachment:
-%%% Since the template is a 300k JSON object it is more efficient to store it as
-%%% an attachment, funky I know but necessary. Also since we already require
-%%% two API calls for editing a template we will maintain backward compatibility by
-%%% not requiring an additional API call for the template and merge/unmerge it
-%%% from requests.
-%%%
-%%%
-%%% @author Jon Blanton
-%%% @author Karl Anderson
-%%% @author James Aimonetti
-%%% @author Pierre Fenoll
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_global_provisioner_templates).
-
--export([init/0
- ,content_types_provided/3, content_types_accepted/3
- ,allowed_methods/0, allowed_methods/1, allowed_methods/2
- ,resource_exists/0, resource_exists/1, resource_exists/2
- ,validate/1, validate/2, validate/3
- ,put/1
- ,post/2
- ,delete/2
- ,put/3
- ,post/3
- ,delete/3
-
- ,acceptable_content_types/0
- ]).
-
--include("crossbar.hrl").
-
--define(MOD_CONFIG_CAT, <<(?CONFIG_CAT)/binary, ".provisioner_templates">>).
--define(CB_LIST, <<"provisioner_templates/crossbar_listing">>).
--define(IMAGE_REQ, <<"image">>).
--define(TEMPLATE_ATTCH, <<"template">>).
--define(MIME_TYPES, [{<<"image">>, <<"*">>, '*'}
- ,{<<"application">>, <<"octet-stream">>, '*'}
- | ?BASE64_CONTENT_TYPES
- ]).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> 'ok'.
-init() ->
- init_db(),
- _ = crossbar_bindings:bind(<<"*.content_types_provided.global_provisioner_templates">>, ?MODULE, 'content_types_provided'),
- _ = crossbar_bindings:bind(<<"*.content_types_accepted.global_provisioner_templates">>, ?MODULE, 'content_types_accepted'),
- _ = crossbar_bindings:bind(<<"*.allowed_methods.global_provisioner_templates">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"*.resource_exists.global_provisioner_templates">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"*.validate.global_provisioner_templates">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"*.execute.put.global_provisioner_templates">>, ?MODULE, 'put'),
- _ = crossbar_bindings:bind(<<"*.execute.post.global_provisioner_templates">>, ?MODULE, 'post'),
- _ = crossbar_bindings:bind(<<"*.execute.delete.global_provisioner_templates">>, ?MODULE, 'delete'),
- 'ok'.
-
-init_db() ->
- _ = kz_datamgr:db_create(?KZ_PROVISIONER_DB),
- _ = kapps_maintenance:refresh(?KZ_PROVISIONER_DB),
- 'ok'.
-
-%%------------------------------------------------------------------------------
-%% @doc Add content types provided by this module.
-%% @end
-%%------------------------------------------------------------------------------
--spec acceptable_content_types() -> cowboy_content_types().
-acceptable_content_types() -> ?MIME_TYPES.
-
--spec content_types_provided(cb_context:context(), path_token(), path_token()) ->
- cb_context:context().
-content_types_provided(Context, PT1, PT2) ->
- content_types_provided_for_provisioner(Context, PT1, PT2, cb_context:req_verb(Context)).
-
--spec content_types_provided_for_provisioner(cb_context:context(), path_token(), path_token(), http_method()) ->
- cb_context:context().
-content_types_provided_for_provisioner(Context, DocId, ?IMAGE_REQ, ?HTTP_GET) ->
- case kz_datamgr:open_doc(?KZ_PROVISIONER_DB, DocId) of
- {'error', _} -> Context;
- {'ok', JObj} ->
- [Type, SubType] = binary:split(get_content_type(JObj), <<"/">>),
- lager:debug("found attachment of content type: ~s/~s~n", [Type, SubType]),
- cb_context:set_content_types_provided(Context, [{'to_binary', [{Type, SubType}]}])
- end;
-content_types_provided_for_provisioner(Context, _, _, _) ->
- Context.
-
--spec get_content_type(kz_json:object()) -> kz_term:ne_binary().
-get_content_type(JObj) ->
- kz_doc:attachment_content_type(JObj, ?IMAGE_REQ, <<"application/octet-stream">>).
-
-%%------------------------------------------------------------------------------
-%% @doc Add content types accepted by this module.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec content_types_accepted(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-content_types_accepted(Context, PT1, PT2) ->
- content_types_accepted(Context, PT1, PT2, cb_context:req_verb(Context)).
-
--spec content_types_accepted(cb_context:context(), path_token(), path_token(), http_method()) -> cb_context:context().
-content_types_accepted(Context, _, ?IMAGE_REQ, ?HTTP_PUT) ->
- cb_context:set_content_types_accepted(Context, [{'from_binary', ?MIME_TYPES}]);
-content_types_accepted(Context, _, ?IMAGE_REQ, ?HTTP_POST) ->
- cb_context:set_content_types_accepted(Context, [{'from_binary', ?MIME_TYPES}]);
-content_types_accepted(Context, _, ?IMAGE_REQ, _) ->
- Context.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec allowed_methods() -> http_methods().
-allowed_methods() ->
- [?HTTP_GET, ?HTTP_PUT].
-
--spec allowed_methods(path_token()) -> http_methods().
-allowed_methods(_TemplateId) ->
- [?HTTP_GET, ?HTTP_POST, ?HTTP_DELETE].
-
--spec allowed_methods(path_token(), path_token()) -> http_methods().
-allowed_methods(_TemplateId, ?IMAGE_REQ) ->
- [?HTTP_GET, ?HTTP_POST, ?HTTP_DELETE].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
--spec resource_exists(path_token()) -> 'true'.
-resource_exists(_) -> 'true'.
-
--spec resource_exists(path_token(), path_token()) -> 'true'.
-resource_exists(_, ?IMAGE_REQ) -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- validate_verb(Context, cb_context:req_verb(Context)).
-
--spec validate_verb(cb_context:context(), http_method()) -> cb_context:context().
-validate_verb(Context, ?HTTP_GET) ->
- load_provisioner_template_summary(cb_context:set_account_db(Context, ?KZ_PROVISIONER_DB));
-validate_verb(Context, ?HTTP_PUT) ->
- create_provisioner_template(cb_context:set_account_db(Context, ?KZ_PROVISIONER_DB)).
-
--spec validate(cb_context:context(), path_token()) -> cb_context:context().
-validate(Context, DocId) ->
- validate_verb(Context, cb_context:req_verb(Context), DocId).
-
--spec validate_verb(cb_context:context(), http_method(), path_token()) -> cb_context:context().
-validate_verb(Context, ?HTTP_GET, DocId) ->
- load_provisioner_template(DocId, cb_context:set_account_db(Context, ?KZ_PROVISIONER_DB));
-validate_verb(Context, ?HTTP_POST, DocId) ->
- update_provisioner_template(DocId, cb_context:set_account_db(Context, ?KZ_PROVISIONER_DB));
-validate_verb(Context, ?HTTP_DELETE, DocId) ->
- load_provisioner_template(DocId, cb_context:set_account_db(Context, ?KZ_PROVISIONER_DB)).
-
--spec validate(cb_context:context(), path_token(), kz_term:ne_binary()) -> cb_context:context().
-validate(Context, DocId, Noun) ->
- validate_verb(Context, cb_context:req_verb(Context), DocId, Noun).
-
--spec validate_verb(cb_context:context(), http_method(), path_token(), kz_term:ne_binary()) ->
- cb_context:context().
-validate_verb(Context, ?HTTP_GET, DocId, ?IMAGE_REQ) ->
- load_template_image(DocId, cb_context:set_account_db(Context, ?KZ_PROVISIONER_DB));
-validate_verb(Context, ?HTTP_PUT, _DocId, ?IMAGE_REQ) ->
- upload_template_image(cb_context:set_account_db(Context, ?KZ_PROVISIONER_DB));
-validate_verb(Context, ?HTTP_POST, _DocId, ?IMAGE_REQ) ->
- upload_template_image(cb_context:set_account_db(Context, ?KZ_PROVISIONER_DB));
-validate_verb(Context, ?HTTP_DELETE, DocId, ?IMAGE_REQ) ->
- load_template_image(DocId, cb_context:set_account_db(Context, ?KZ_PROVISIONER_DB)).
-
--spec post(cb_context:context(), path_token()) -> cb_context:context().
-post(Context, DocId) ->
- %% see note at top of file
- JObj = cb_context:doc(Context),
- Template = kz_json:get_value(<<"template">>, JObj),
- Doc = kz_json:delete_key(<<"template">>, JObj),
- Context1 = crossbar_doc:save(cb_context:set_doc(Context, Doc)),
- case cb_context:resp_status(Context1) of
- 'success' ->
- Opts = [{'content_type', <<"application/json">>} | ?TYPE_CHECK_OPTION(<<"provisioner_template">>)],
- Context2 = crossbar_doc:save_attachment(DocId, ?TEMPLATE_ATTCH, kz_json:encode(Template), Context, Opts),
- case cb_context:resp_status(Context2) of
- 'success' ->
- SavedResp = cb_context:resp_data(Context1),
- NewRespData = kz_json:set_value(<<"template">>, Template, SavedResp),
- cb_context:set_resp_data(Context1, NewRespData);
- Else -> Else
- end;
- Else -> Else
- end.
-
--spec put(cb_context:context()) -> cb_context:context().
-put(Context) ->
- %% see note at top of file
- JObj = cb_context:doc(Context),
- Template = kz_json:get_value(<<"template">>, JObj),
- Doc = kz_json:delete_key(<<"template">>, JObj),
- Context1 = crossbar_doc:save(cb_context:set_doc(Context, Doc)),
- case cb_context:resp_status(Context1) of
- 'success' ->
- DocId = kz_doc:id(cb_context:doc(Context1)),
- Opts = [{'content_type', <<"application/json">>} | ?TYPE_CHECK_OPTION(<<"provisioner_template">>)],
- Context2 = crossbar_doc:save_attachment(DocId, ?TEMPLATE_ATTCH, kz_json:encode(Template), Context, Opts),
- case cb_context:resp_status(Context2) of
- 'success' ->
- SavedResp = cb_context:resp_data(Context1),
- cb_context:set_resp_data(Context1, kz_json:set_value(<<"template">>, Template, SavedResp));
- Else -> Else
- end;
- Else -> Else
- end.
-
--spec delete(cb_context:context(), path_token()) -> cb_context:context().
-delete(Context, _) ->
- crossbar_doc:delete(Context).
-
--spec post(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-post(Context, DocId, ?IMAGE_REQ) ->
- [{_, JObj}] = cb_context:req_files(Context),
- Contents = kz_json:get_value(<<"contents">>, JObj),
- CT = kz_json:get_value([<<"headers">>, <<"content_type">>], JObj, <<"application/octet-stream">>),
- Opts = [{'content_type', CT} | ?TYPE_CHECK_OPTION(<<"provisioner_template">>)],
- crossbar_doc:save_attachment(DocId, ?IMAGE_REQ, Contents, Context, Opts).
-
--spec put(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-put(Context, DocId, ?IMAGE_REQ) ->
- [{_, JObj}] = cb_context:req_files(Context),
- Contents = kz_json:get_value(<<"contents">>, JObj),
- CT = kz_json:get_value([<<"headers">>, <<"content_type">>], JObj, <<"application/octet-stream">>),
- Opts = [{'content_type', CT} | ?TYPE_CHECK_OPTION(<<"provisioner_template">>)],
- crossbar_doc:save_attachment(DocId, ?IMAGE_REQ, Contents, Context, Opts).
-
--spec delete(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-delete(Context, DocId, ?IMAGE_REQ) ->
- crossbar_doc:delete_attachment(DocId, ?IMAGE_REQ, Context).
-
-%%%=============================================================================
-%%% Internal functions
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec load_template_image(path_token(), cb_context:context()) -> cb_context:context().
-load_template_image(DocId, Context) ->
- crossbar_doc:load_attachment(DocId, ?IMAGE_REQ, ?TYPE_CHECK_OPTION(<<"provisioner_template">>), Context).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec upload_template_image(cb_context:context()) -> cb_context:context().
-upload_template_image(Context) ->
- upload_template_image(Context, cb_context:req_files(Context)).
-upload_template_image(Context, []) ->
- Msg = kz_json:from_list([{<<"message">>, <<"Please provide an image file">>}]),
- cb_context:add_validation_error(<<"file">>
- ,<<"required">>
- ,Msg
- ,Context
- );
-upload_template_image(Context, [{_, _}]) ->
- crossbar_util:response(kz_json:new(), Context);
-upload_template_image(Context, [_|_]) ->
- Msg = kz_json:from_list([{<<"message">>, <<"Please provide a single image file">>}]),
- cb_context:add_validation_error(<<"file">>, <<"maxItems">>, Msg, Context).
-
-%%------------------------------------------------------------------------------
-%% @doc Attempt to load list of provision templates, each summarized. Or a specific
-%% provision template summary.
-%% @end
-%%------------------------------------------------------------------------------
--spec load_provisioner_template_summary(cb_context:context()) -> cb_context:context().
-load_provisioner_template_summary(Context) ->
- crossbar_doc:load_view(?CB_LIST, [], Context, fun normalize_view_results/2).
-
-%%------------------------------------------------------------------------------
-%% @doc Create a new provision template document with the data provided, if it is valid
-%% @end
-%%------------------------------------------------------------------------------
--spec create_provisioner_template(cb_context:context()) -> cb_context:context().
-create_provisioner_template(Context) ->
- OnSuccess = fun(C) -> on_successful_validation('undefined', C) end,
- cb_context:validate_request_data(<<"provisioner_templates">>, Context, OnSuccess).
-
-%%------------------------------------------------------------------------------
-%% @doc Load a provision template document from the database
-%% @end
-%%------------------------------------------------------------------------------
--spec load_provisioner_template(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-load_provisioner_template(DocId, Context) ->
- %% see note at top of file
- Context1 = crossbar_doc:load(DocId, Context, ?TYPE_CHECK_OPTION(<<"provisioner_template">>)),
- case cb_context:resp_status(Context1) of
- 'success' ->
- Context2 = crossbar_doc:load_attachment(DocId, ?TEMPLATE_ATTCH, ?TYPE_CHECK_OPTION(<<"provisioner_template">>), Context),
- case cb_context:resp_status(Context2) of
- 'success' ->
- Template = kz_json:decode(cb_context:resp_data(Context2)),
- RespJObj = cb_context:resp_data(Context1),
- cb_context:set_resp_data(Context1, kz_json:set_value(<<"template">>, Template, RespJObj));
- Else -> Else
- end;
- Else -> Else
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Update an existing provision template document with the data provided, if it is
-%% valid
-%% @end
-%%------------------------------------------------------------------------------
--spec update_provisioner_template(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-update_provisioner_template(DocId, Context) ->
- OnSuccess = fun(C) -> on_successful_validation(DocId, C) end,
- cb_context:validate_request_data(<<"provisioner_templates">>, Context, OnSuccess).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec on_successful_validation(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-on_successful_validation('undefined', Context) ->
- Doc = kz_json:set_values([{<<"pvt_type">>, <<"provisioner_template">>}
- ,{<<"pvt_provider">>, <<"provisioner.net">>}
- ,{<<"pvt_provisioner_type">>, <<"global">>}
- ]
- ,cb_context:doc(Context)
- ),
-
- case provisioner_util:get_provision_defaults(Doc) of
- {'ok', Defaults} ->
- cb_context:setters(Context
- ,[{fun cb_context:set_doc/2, Defaults}
- ,{fun cb_context:set_resp_status/2, 'success'}
- ]);
- {'error', Msg} ->
- crossbar_util:response('error', Msg, 500, Context)
- end;
-on_successful_validation(DocId, Context) ->
- crossbar_doc:load_merge(DocId, Context, ?TYPE_CHECK_OPTION(<<"provisioner_template">>)).
-
-%%------------------------------------------------------------------------------
-%% @doc Normalizes the results of a view.
-%% @end
-%%------------------------------------------------------------------------------
--spec normalize_view_results(kz_json:object(), kz_json:objects()) -> kz_json:objects().
-normalize_view_results(JObj, Acc) ->
- [kz_json:get_value(<<"value">>, JObj) | Acc].
diff --git a/applications/crossbar/src/modules_v2/cb_limits_v2.erl b/applications/crossbar/src/modules/cb_limits.erl
similarity index 95%
rename from applications/crossbar/src/modules_v2/cb_limits_v2.erl
rename to applications/crossbar/src/modules/cb_limits.erl
index 25cb0bc1c4f..7457ca330ab 100644
--- a/applications/crossbar/src/modules_v2/cb_limits_v2.erl
+++ b/applications/crossbar/src/modules/cb_limits.erl
@@ -9,7 +9,7 @@
%%%
%%% @end
%%%-----------------------------------------------------------------------------
--module(cb_limits_v2).
+-module(cb_limits).
-export([init/0
,allowed_methods/0
@@ -34,10 +34,10 @@
%%------------------------------------------------------------------------------
-spec init() -> 'ok'.
init() ->
- _ = crossbar_bindings:bind(<<"v2_resource.allowed_methods.limits">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"v2_resource.resource_exists.limits">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"v2_resource.validate.limits">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"v2_resource.execute.post.limits">>, ?MODULE, 'post'),
+ _ = crossbar_bindings:bind(<<"*.allowed_methods.limits">>, ?MODULE, 'allowed_methods'),
+ _ = crossbar_bindings:bind(<<"*.resource_exists.limits">>, ?MODULE, 'resource_exists'),
+ _ = crossbar_bindings:bind(<<"*.validate.limits">>, ?MODULE, 'validate'),
+ _ = crossbar_bindings:bind(<<"*.execute.post.limits">>, ?MODULE, 'post'),
'ok'.
%%------------------------------------------------------------------------------
diff --git a/applications/crossbar/src/modules_v2/cb_lists_v2.erl b/applications/crossbar/src/modules/cb_lists.erl
similarity index 95%
rename from applications/crossbar/src/modules_v2/cb_lists_v2.erl
rename to applications/crossbar/src/modules/cb_lists.erl
index 34ecff4379b..00ea67ad57f 100644
--- a/applications/crossbar/src/modules_v2/cb_lists_v2.erl
+++ b/applications/crossbar/src/modules/cb_lists.erl
@@ -12,7 +12,7 @@
%%%
%%% @end
%%%-----------------------------------------------------------------------------
--module(cb_lists_v2).
+-module(cb_lists).
-export([maybe_migrate/1]).
-export([init/0
@@ -121,14 +121,14 @@ migrate_to_entry_doc(AccountDb, EntryId, EntryJObj, ListJObj) ->
-spec init() -> any().
init() ->
[crossbar_bindings:bind(Binding, ?MODULE, F)
- || {Binding, F} <- [{<<"v2_resource.allowed_methods.lists">>, 'allowed_methods'}
- ,{<<"v2_resource.resource_exists.lists">>, 'resource_exists'}
- ,{<<"v2_resource.content_types_provided.lists">>, 'content_types_provided'}
- ,{<<"v2_resource.validate.lists">>, 'validate'}
- ,{<<"v2_resource.execute.put.lists">>, 'save'}
- ,{<<"v2_resource.execute.post.lists">>, 'save'}
- ,{<<"v2_resource.execute.patch.lists">>, 'save'}
- ,{<<"v2_resource.execute.delete.lists">>, 'delete'}
+ || {Binding, F} <- [{<<"*.allowed_methods.lists">>, 'allowed_methods'}
+ ,{<<"*.resource_exists.lists">>, 'resource_exists'}
+ ,{<<"*.content_types_provided.lists">>, 'content_types_provided'}
+ ,{<<"*.validate.lists">>, 'validate'}
+ ,{<<"*.execute.put.lists">>, 'save'}
+ ,{<<"*.execute.post.lists">>, 'save'}
+ ,{<<"*.execute.patch.lists">>, 'save'}
+ ,{<<"*.execute.delete.lists">>, 'delete'}
]
].
@@ -311,8 +311,8 @@ save(Context, _, ?ENTRIES, _) ->
-spec save(cb_context:context(), path_token(), path_token(), path_token(), path_token()) -> cb_context:context().
save(Context, _, ?ENTRIES, EntryId, ?PHOTO) ->
- %% May be move code from cb_users_v2 to crossbar_doc?
- cb_users_v2:post(Context, EntryId, ?PHOTO).
+ %% May be move code from cb_users to crossbar_doc?
+ cb_users:post(Context, EntryId, ?PHOTO).
-spec type_schema_name(kz_term:ne_binary()) -> kz_term:ne_binary().
type_schema_name(?TYPE_LIST) -> <<"lists">>;
@@ -345,7 +345,7 @@ set_org(JObj, _, _, ListId) ->
-spec set_photo(kz_json:object(), cb_context:context()) -> kz_json:object().
set_photo(JObj, Context) ->
- %% This code is copied from cb_users_v2. May be move it to crossbar_doc?
+ %% This code is copied from cb_users. May be move it to crossbar_doc?
DocId = kz_json:get_value(<<"_id">>, cb_context:doc(Context)),
Attach = crossbar_doc:load_attachment(DocId, ?PHOTO, ?TYPE_CHECK_OPTION(?TYPE_LIST_ENTRY), Context),
case cb_context:resp_status(Attach) of
diff --git a/applications/crossbar/src/modules/cb_local_provisioner_templates.erl b/applications/crossbar/src/modules/cb_local_provisioner_templates.erl
deleted file mode 100644
index ca2807d4700..00000000000
--- a/applications/crossbar/src/modules/cb_local_provisioner_templates.erl
+++ /dev/null
@@ -1,373 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Provision template module.
-%%% Handle client requests for provisioner template documents.
-%%%
-%%% Regarding storing the template as an attachment:
-%%% Since the template is a 300k JSON object it is more efficient to store it as
-%%% an attachment, funky I know but necessary. Also since we already require
-%%% two API calls for editing a template we will maintain backward compatibility by
-%%% not requiring an additional API call for the template and merge/unmerge it
-%%% from requests
.
-%%%
-%%%
-%%% @author Jon Blanton
-%%% @author Karl Anderson
-%%% @author Pierre Fenoll
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_local_provisioner_templates).
-
--export([init/0
- ,content_types_provided/3, content_types_accepted/3
- ,allowed_methods/0, allowed_methods/1, allowed_methods/2
- ,resource_exists/0, resource_exists/1, resource_exists/2
- ,validate/1, validate/2, validate/3
- ,put/1
- ,post/2
- ,delete/2
- ,put/3
- ,post/3
- ,delete/3
- ]).
-
--include("crossbar.hrl").
-
--define(MOD_CONFIG_CAT, <<(?CONFIG_CAT)/binary, ".provisioner_templates">>).
--define(CB_LIST, <<"provisioner_templates/crossbar_listing">>).
--define(IMAGE_REQ, <<"image">>).
--define(TEMPLATE_ATTCH, <<"template">>).
--define(MIME_TYPES, [{<<"image">>, <<"*">>}
- ,{<<"application">>, <<"octet-stream">>}
- | ?BASE64_CONTENT_TYPES
- ]).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> 'ok'.
-init() ->
- _ = crossbar_bindings:bind(<<"*.content_types_provided.local_provisioner_templates">>, ?MODULE, 'content_types_provided'),
- _ = crossbar_bindings:bind(<<"*.content_types_accepted.local_provisioner_templates">>, ?MODULE, 'content_types_accepted'),
- _ = crossbar_bindings:bind(<<"*.allowed_methods.local_provisioner_templates">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"*.resource_exists.local_provisioner_templates">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"*.validate.local_provisioner_templates">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"*.execute.put.local_provisioner_templates">>, ?MODULE, 'put'),
- _ = crossbar_bindings:bind(<<"*.execute.post.local_provisioner_templates">>, ?MODULE, 'post'),
- _ = crossbar_bindings:bind(<<"*.execute.delete.local_provisioner_templates">>, ?MODULE, 'delete'),
- 'ok'.
-
-%%------------------------------------------------------------------------------
-%% @doc Add content types provided by this module
-%% @end
-%%------------------------------------------------------------------------------
-
--spec content_types_provided(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-content_types_provided(Context, PT1, PT2) ->
- content_types_provided_for_provisioner(Context, PT1, PT2, cb_context:req_verb(Context)).
-
--spec content_types_provided_for_provisioner(cb_context:context(), path_token(), path_token(), http_method()) -> cb_context:context().
-content_types_provided_for_provisioner(Context, DocId, ?IMAGE_REQ, ?HTTP_GET) ->
- Db = kz_util:format_account_id(cb_context:auth_account_id(Context), 'encoded'),
- case kz_datamgr:open_doc(Db, DocId) of
- {'error', _} -> Context;
- {'ok', JObj} ->
- CT = kz_doc:attachment_content_type(JObj, ?IMAGE_REQ, <<"application/octet-stream">>),
- [Type, SubType] = binary:split(CT, <<"/">>),
- lager:debug("found attachment of content type: ~s/~s~n", [Type, SubType]),
- cb_context:set_content_types_provided(Context, [{'to_binary', [{Type, SubType}]}])
- end;
-content_types_provided_for_provisioner(Context, _, _, _) ->
- Context.
-
-%%------------------------------------------------------------------------------
-%% @doc Add content types accepted by this module
-%% @end
-%%------------------------------------------------------------------------------
-
--spec content_types_accepted(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-content_types_accepted(Context, PT1, PT2) ->
- content_types_accepted(Context, PT1, PT2, cb_context:req_verb(Context)).
-
--spec content_types_accepted(cb_context:context(), path_token(), path_token(), http_method()) -> cb_context:context().
-content_types_accepted(Context, _, ?IMAGE_REQ, ?HTTP_PUT) ->
- cb_context:set_content_types_accepted(Context, [{'from_binary', ?MIME_TYPES}]);
-content_types_accepted(Context, _, ?IMAGE_REQ, ?HTTP_POST) ->
- cb_context:set_content_types_accepted(Context, [{'from_binary', ?MIME_TYPES}]);
-content_types_accepted(Context, _, _, _) ->
- Context.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec allowed_methods() -> http_methods().
-allowed_methods() ->
- [?HTTP_GET, ?HTTP_PUT].
-
--spec allowed_methods(path_token()) -> http_methods().
-allowed_methods(_TemplateId) ->
- [?HTTP_GET, ?HTTP_POST, ?HTTP_DELETE].
-
--spec allowed_methods(path_token(), path_token()) -> http_methods().
-allowed_methods(_TemplateId, ?IMAGE_REQ) ->
- [?HTTP_GET, ?HTTP_POST, ?HTTP_DELETE].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
--spec resource_exists(path_token()) -> 'true'.
-resource_exists(_) -> 'true'.
-
--spec resource_exists(path_token(), path_token()) -> 'true'.
-resource_exists(_, ?IMAGE_REQ) -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- validate_verb(Context, cb_context:req_verb(Context)).
-
--spec validate(cb_context:context(), path_token()) -> cb_context:context().
-validate(Context, PT1) ->
- validate_verb(Context, PT1, cb_context:req_verb(Context)).
-
--spec validate(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-validate(Context, PT1, PT2) ->
- validate_verb(Context, PT1, PT2, cb_context:req_verb(Context)).
-
-
--spec validate_verb(cb_context:context(), http_method()) -> cb_context:context().
-validate_verb(Context, ?HTTP_GET) ->
- load_provisioner_template_summary(Context);
-validate_verb(Context, ?HTTP_PUT) ->
- create_provisioner_template(Context).
-
--spec validate_verb(cb_context:context(), path_token(), http_method()) -> cb_context:context().
-validate_verb(Context, DocId, ?HTTP_GET) ->
- load_provisioner_template(DocId, Context);
-validate_verb(Context, DocId, ?HTTP_POST) ->
- update_provisioner_template(DocId, Context);
-validate_verb(Context, DocId, ?HTTP_DELETE) ->
- load_provisioner_template(DocId, Context).
-
--spec validate_verb(cb_context:context(), path_token(), path_token(), http_method()) -> cb_context:context().
-validate_verb(Context, DocId, ?IMAGE_REQ, ?HTTP_GET) ->
- load_template_image(DocId, Context);
-validate_verb(Context, _DocId, ?IMAGE_REQ, ?HTTP_PUT) ->
- upload_template_image(Context);
-validate_verb(Context, _DocId, ?IMAGE_REQ, ?HTTP_POST) ->
- upload_template_image(Context);
-validate_verb(Context, DocId, ?IMAGE_REQ, ?HTTP_DELETE) ->
- load_template_image(DocId, Context).
-
--spec post(cb_context:context(), path_token()) -> cb_context:context().
-post(Context, DocId) ->
- %% see note at top of file
- JObj = cb_context:doc(Context),
- Template = kz_json:get_value(<<"template">>, JObj),
- Doc = kz_json:delete_key(<<"template">>, JObj),
- Context1 = crossbar_doc:save(cb_context:set_doc(Context, Doc)),
- case cb_context:resp_status(Context1) of
- 'success' ->
- SavedResp = cb_context:resp_data(Context1),
- Opts = [{'content_type', <<"application/json">>} | ?TYPE_CHECK_OPTION(<<"provisioner_template">>)],
- Ctx2 = crossbar_doc:save_attachment(DocId, ?TEMPLATE_ATTCH, kz_json:encode(Template), Context, Opts),
- case cb_context:resp_status(Ctx2) of
- 'success' ->
- cb_context:set_resp_data(Context1, kz_json:set_value(<<"template">>, Template, SavedResp));
- _Error -> Ctx2
- end;
- _Error -> Context1
- end.
-
--spec put(cb_context:context()) -> cb_context:context().
-put(Context) ->
- %% see note at top of file
- JObj = cb_context:doc(Context),
- Template = kz_json:get_value(<<"template">>, JObj),
- Doc = kz_json:delete_key(<<"template">>, JObj),
- Context1 = crossbar_doc:save(cb_context:set_doc(Context, Doc)),
- case cb_context:resp_status(Context1) of
- 'success' ->
- SavedDoc = cb_context:doc(Context1),
- SavedResp = cb_context:resp_data(Context1),
- DocId = kz_doc:id(SavedDoc),
- Opts = [{'content_type', <<"application/json">>} | ?TYPE_CHECK_OPTION(<<"provisioner_template">>)],
- Ctx2 = crossbar_doc:save_attachment(DocId, ?TEMPLATE_ATTCH, kz_json:encode(Template), Context, Opts),
- case cb_context:resp_status(Ctx2) of
- 'success' ->
- cb_context:set_resp_data(Context1, kz_json:set_value(<<"template">>, Template, SavedResp));
- Else -> Else
- end;
- Else -> Else
- end.
-
--spec delete(cb_context:context(), path_token()) -> cb_context:context().
-delete(Context, _) ->
- crossbar_doc:delete(Context).
-
--spec post(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-post(Context, DocId, ?IMAGE_REQ) ->
- [{_, JObj}] = cb_context:req_files(Context),
- Contents = kz_json:get_value(<<"contents">>, JObj),
- CT = kz_json:get_value([<<"headers">>, <<"content_type">>], JObj, <<"application/octet-stream">>),
- Opts = [{'content_type', CT} | ?TYPE_CHECK_OPTION(<<"provisioner_template">>)],
- crossbar_doc:save_attachment(DocId, ?IMAGE_REQ, Contents, Context, Opts).
-
--spec put(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-put(Context, DocId, ?IMAGE_REQ) ->
- [{_, JObj}] = cb_context:req_files(Context),
- Contents = kz_json:get_value(<<"contents">>, JObj),
- CT = kz_json:get_value([<<"headers">>, <<"content_type">>], JObj, <<"application/octet-stream">>),
- Opts = [{'content_type', CT} | ?TYPE_CHECK_OPTION(<<"provisioner_template">>)],
- crossbar_doc:save_attachment(DocId, ?IMAGE_REQ, Contents, Context, Opts).
-
--spec delete(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-delete(Context, DocId, ?IMAGE_REQ) ->
- crossbar_doc:delete_attachment(DocId, ?IMAGE_REQ, Context).
-
-%%%=============================================================================
-%%% Internal functions
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec load_template_image(path_token(), cb_context:context()) -> cb_context:context().
-load_template_image(DocId, Context) ->
- crossbar_doc:load_attachment(DocId, ?IMAGE_REQ, ?TYPE_CHECK_OPTION(<<"provisioner_template">>), Context).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
-
--spec upload_template_image(cb_context:context()) -> cb_context:context().
-upload_template_image(Context) ->
- upload_template_image(Context, cb_context:req_files(Context)).
-
--spec upload_template_image(cb_context:context(), req_files()) -> cb_context:context().
-upload_template_image(Context, []) ->
- cb_context:add_validation_error(<<"file">>
- ,<<"required">>
- ,kz_json:from_list([{<<"message">>, <<"please provide an image file">>}])
- ,Context
- );
-upload_template_image(Context, [{_, _}]) ->
- crossbar_util:response(kz_json:new(), Context);
-upload_template_image(Context, [_|_]) ->
- cb_context:add_validation_error(<<"file">>
- ,<<"maxItems">>
- ,kz_json:from_list([{<<"message">>, <<"Please provide a single image file">>}])
- ,Context
- ).
-
-%%------------------------------------------------------------------------------
-%% @doc Attempt to load list of provision templates, each summarized. Or a specific
-%% provision template summary.
-%% @end
-%%------------------------------------------------------------------------------
--spec load_provisioner_template_summary(cb_context:context()) -> cb_context:context().
-load_provisioner_template_summary(Context) ->
- crossbar_doc:load_view(?CB_LIST, [], Context, fun normalize_view_results/2).
-
-%%------------------------------------------------------------------------------
-%% @doc Create a new provision template document with the data provided, if it is valid
-%% @end
-%%------------------------------------------------------------------------------
--spec create_provisioner_template(cb_context:context()) -> cb_context:context().
-create_provisioner_template(Context) ->
- OnSuccess = fun(C) -> on_successful_validation('undefined', C) end,
- cb_context:validate_request_data(<<"provisioner_templates">>, Context, OnSuccess).
-
-%%------------------------------------------------------------------------------
-%% @doc Load a provision template document from the database
-%% @end
-%%------------------------------------------------------------------------------
--spec load_provisioner_template(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-load_provisioner_template(DocId, Context) ->
- %% see note at top of file
- Context1 = crossbar_doc:load(DocId, Context, ?TYPE_CHECK_OPTION(<<"provisioner_template">>)),
- case cb_context:resp_status(Context1) of
- 'success' ->
- RespJObj = cb_context:resp_data(Context1),
- Ctx2 = crossbar_doc:load_attachment(DocId, ?TEMPLATE_ATTCH, ?TYPE_CHECK_OPTION(<<"provisioner_template">>), Context),
- case cb_context:resp_status(Ctx2) of
- 'success' ->
- Template = kz_json:decode(cb_context:resp_data(Ctx2)),
- cb_context:set_resp_data(Context1, kz_json:set_value(<<"template">>, Template, RespJObj));
- Else -> Else
- end;
- Else -> Else
- end.
-%%------------------------------------------------------------------------------
-%% @doc Update an existing provision template document with the data provided, if it is
-%% valid
-%% @end
-%%------------------------------------------------------------------------------
--spec update_provisioner_template(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-update_provisioner_template(DocId, Context) ->
- OnSuccess = fun(C) -> on_successful_validation(DocId, C) end,
- cb_context:validate_request_data(<<"provisioner_templates">>, Context, OnSuccess).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec on_successful_validation(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-on_successful_validation('undefined', Context) ->
- Doc = kz_json:set_values([{<<"pvt_type">>, <<"provisioner_template">>}
- ,{<<"pvt_provider">>, <<"provisioner.net">>}
- ,{<<"pvt_provisioner_type">>, <<"local">>}
- ]
- ,cb_context:doc(Context)
- ),
-
- case provisioner_util:get_provision_defaults(Doc) of
- {'ok', Defaults} ->
- cb_context:setters(Context
- ,[{fun cb_context:set_doc/2, Defaults}
- ,{fun cb_context:set_resp_status/2, 'success'}
- ]);
- {'error', Msg} ->
- crossbar_util:response('error', Msg, 500, Context)
- end;
-on_successful_validation(DocId, Context) ->
- crossbar_doc:load_merge(DocId, Context, ?TYPE_CHECK_OPTION(<<"provisioner_template">>)).
-
-%%------------------------------------------------------------------------------
-%% @doc Normalizes the results of a view.
-%% @end
-%%------------------------------------------------------------------------------
--spec normalize_view_results(kz_json:object(), kz_json:objects()) -> kz_json:objects().
-normalize_view_results(JObj, Acc) ->
- [kz_json:get_value(<<"value">>, JObj) | Acc].
diff --git a/applications/crossbar/src/modules/cb_local_resources.erl b/applications/crossbar/src/modules/cb_local_resources.erl
deleted file mode 100644
index abaf6c8e5aa..00000000000
--- a/applications/crossbar/src/modules/cb_local_resources.erl
+++ /dev/null
@@ -1,318 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Handle client requests for local resource documents
-%%% @author Karl Anderson
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_local_resources).
-
--export([init/0]).
-
--export([validate_request/2
- ,maybe_remove_aggregate/2
- ,maybe_aggregate_resources/1
- ,maybe_aggregate_resource/1
- ,maybe_remove_aggregates/1
- ]).
-
--include("crossbar.hrl").
-
--define(MOD_CONFIG_CAT, <<(?CONFIG_CAT)/binary, ".local_resources">>).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> ok.
-init() ->
- _ = crossbar_maintenance:start_module('cb_resources'),
- ok.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec validate_request(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-validate_request(ResourceId, Context) ->
- check_for_registering_gateways(ResourceId, Context).
-
--spec check_for_registering_gateways(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-check_for_registering_gateways(ResourceId, Context) ->
- case lists:any(fun is_registering_gateway/1
- ,cb_context:req_value(Context, <<"gateways">>, [])
- )
- of
- 'true' ->
- check_if_peer(ResourceId, cb_context:store(Context, 'aggregate_resource', 'true'));
- 'false' ->
- check_if_peer(ResourceId, Context)
- end.
-
--spec is_registering_gateway(kz_json:object()) -> boolean().
-is_registering_gateway(Gateway) ->
- kz_json:is_true(<<"register">>, Gateway)
- andalso kz_json:is_true(<<"enabled">>, Gateway).
-
--spec check_if_peer(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-check_if_peer(ResourceId, Context) ->
- case {kz_term:is_true(cb_context:req_value(Context, <<"peer">>))
- ,kapps_config:get_is_true(?MOD_CONFIG_CAT, <<"allow_peers">>, 'false')
- }
- of
- {'true', 'true'} ->
- check_if_gateways_have_ip(ResourceId, Context);
- {'true', 'false'} ->
- C = cb_context:add_validation_error([<<"peer">>]
- ,<<"forbidden">>
- ,kz_json:from_list([{<<"message">>, <<"Peers are currently disabled, please contact the system admin">>}])
- ,Context
- ),
- check_resource_schema(ResourceId, C);
- {_, _} ->
- check_resource_schema(ResourceId, Context)
- end.
-
--spec check_if_gateways_have_ip(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-check_if_gateways_have_ip(ResourceId, Context) ->
- Gateways = cb_context:req_value(Context, <<"gateways">>, []),
- IPs = extract_gateway_ips(Gateways, 0, []),
- SIPAuth = get_all_sip_auth_ips(),
- ACLs = get_all_acl_ips(),
- validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, Context, cb_context:resp_status(Context)).
-
--spec validate_gateway_ips(gateway_ips(), sip_auth_ips(), acl_ips(), kz_term:api_binary(), cb_context:context(), crossbar_status()) -> cb_context:context().
-validate_gateway_ips([], _, _, ResourceId, Context, 'error') ->
- check_resource_schema(ResourceId, Context);
-validate_gateway_ips([], _, _, ResourceId, Context, 'success') ->
- check_resource_schema(ResourceId, cb_context:store(Context, 'aggregate_resource', 'true'));
-validate_gateway_ips([{Idx, 'undefined', 'undefined'}|IPs], SIPAuth, ACLs, ResourceId, Context, 'success') ->
- C = cb_context:add_validation_error([<<"gateways">>, Idx, <<"server">>]
- ,<<"required">>
- ,kz_json:from_list([{<<"message">>, <<"Gateway server must be an IP when peering with the resource">>}
- ,{<<"cause">>, Idx}
- ])
- ,Context
- ),
- validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, C, cb_context:resp_status(C));
-validate_gateway_ips([{Idx, 'undefined', ServerIP}|IPs], SIPAuth, ACLs, ResourceId, Context, 'success') ->
- case kz_network_utils:is_ipv4(ServerIP) of
- 'true' ->
- case validate_ip(ServerIP, SIPAuth, ACLs, ResourceId) of
- 'true' ->
- validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, Context, cb_context:resp_status(Context));
- 'false' ->
- C = cb_context:add_validation_error([<<"gateways">>, Idx, <<"server">>]
- ,<<"unique">>
- ,kz_json:from_list([{<<"message">>, <<"Gateway server ip is already in use">>}
- ,{<<"cause">>, Idx}
- ])
- ,Context
- ),
- validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, C, cb_context:resp_status(C))
- end;
- 'false' ->
- validate_gateway_ips([{Idx, 'undefined', 'undefined'}|IPs], SIPAuth, ACLs, ResourceId, Context, cb_context:resp_status(Context))
- end;
-validate_gateway_ips([{Idx, InboundIP, ServerIP}|IPs], SIPAuth, ACLs, ResourceId, Context, 'success') ->
- case kz_network_utils:is_ipv4(InboundIP) of
- 'true' ->
- case validate_ip(InboundIP, SIPAuth, ACLs, ResourceId) of
- 'true' ->
- validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, Context, cb_context:resp_status(Context));
- 'false' ->
- C = cb_context:add_validation_error([<<"gateways">>, Idx, <<"inbound_ip">>]
- ,<<"unique">>
- ,kz_json:from_list([{<<"message">>, <<"Gateway inbound ip is already in use">>}
- ,{<<"cause">>, Idx}
- ])
- ,Context
- ),
- validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, C, cb_context:resp_status(C))
- end;
- 'false' ->
- validate_gateway_ips([{Idx, 'undefined', ServerIP}|IPs], SIPAuth, ACLs, ResourceId, Context, cb_context:resp_status(Context))
- end.
-
--spec check_resource_schema(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-check_resource_schema(ResourceId, Context) ->
- %% This has been validated in cb_resources already!
- on_successful_validation(ResourceId, Context).
-
--spec on_successful_validation(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-on_successful_validation('undefined', Context) ->
- cb_context:set_doc(Context, kz_doc:set_type(cb_context:doc(Context), <<"resource">>));
-on_successful_validation(Id, Context) ->
- crossbar_doc:load_merge(Id, Context, ?TYPE_CHECK_OPTION(<<"resource">>)).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
-
--spec maybe_aggregate_resource(cb_context:context()) -> boolean().
-maybe_aggregate_resource(Context) ->
- maybe_aggregate_resource(Context, cb_context:resp_status(Context)).
-
--spec maybe_aggregate_resource(cb_context:context(), crossbar_status()) -> boolean().
-maybe_aggregate_resource(Context, 'success') ->
- ResourceId = kz_doc:id(cb_context:doc(Context)),
- case kz_term:is_true(cb_context:fetch(Context, 'aggregate_resource')) of
- 'false' ->
- maybe_remove_aggregate(ResourceId, Context);
- 'true' ->
- aggregate_resource(kz_doc:set_id(cb_context:doc(Context), ResourceId)),
- _ = kapi_switch:publish_reload_gateways(),
- _ = kapi_switch:publish_reload_acls(),
- 'true'
- end;
-maybe_aggregate_resource(_Context, _Status) -> 'false'.
-
--spec aggregate_resource(kz_json:object()) -> 'ok'.
-aggregate_resource(Resource) ->
- lager:debug("adding resource to the sip auth aggregate"),
- Doc = kz_doc:delete_revision(Resource),
- 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'.
-
--spec maybe_remove_aggregate(kz_term:ne_binary(), cb_context:context()) -> boolean().
-maybe_remove_aggregate(ResourceId, Context) ->
- maybe_remove_aggregate(ResourceId, Context, cb_context:resp_status(Context)).
-
--spec maybe_remove_aggregate(kz_term:ne_binary(), cb_context:context(), crossbar_status()) -> boolean().
-maybe_remove_aggregate(ResourceId, _Context, 'success') ->
- case kz_datamgr:del_doc(?KZ_SIP_DB, ResourceId) of
- {'ok', _JObj} ->
- _ = kapi_switch:publish_reload_gateways(),
- _ = kapi_switch:publish_reload_acls(),
- 'true';
- {'error', 'not_found'} -> 'false'
- end;
-maybe_remove_aggregate(_ResourceId, _Context, _Status) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--type sip_auth_ip() :: {kz_term:ne_binary(), kz_term:ne_binary()}.
--type sip_auth_ips() :: [sip_auth_ip()].
-
--spec get_all_sip_auth_ips() -> sip_auth_ips().
-get_all_sip_auth_ips() ->
- ViewOptions = [],
- case kz_datamgr:get_results(?KZ_SIP_DB, <<"credentials/lookup_by_ip">>, ViewOptions) of
- {'ok', JObjs} -> lists:foldr(fun get_sip_auth_ip/2, [], JObjs);
- {'error', _} -> []
- end.
-
--spec get_sip_auth_ip(kz_json:object(), sip_auth_ips()) -> sip_auth_ips().
-get_sip_auth_ip(JObj, IPs) ->
- [{kz_json:get_value(<<"key">>, JObj), kz_doc:id(JObj)} | IPs].
-
--type acl_ips() :: kz_term:ne_binaries().
--spec get_all_acl_ips() -> acl_ips().
-get_all_acl_ips() ->
- Req = [{<<"Category">>, <<"ecallmgr">>}
- ,{<<"Key">>, <<"acls">>}
- ,{<<"Node">>, <<"all">>}
- ,{<<"Default">>, kz_json:new()}
- ,{<<"Msg-ID">>, kz_binary:rand_hex(16)}
- | kz_api:default_headers(?APP_NAME, ?APP_VERSION)
- ],
- Resp = kz_amqp_worker:call(props:filter_undefined(Req)
- ,fun kapi_sysconf:publish_get_req/1
- ,fun kapi_sysconf:get_resp_v/1
- ),
- case Resp of
- {'error', _} -> [];
- {'ok', JObj} ->
- extract_all_ips(kz_json:get_value(<<"Value">>, JObj, kz_json:new()))
- end.
-
--spec extract_all_ips(kz_json:object()) -> acl_ips().
-extract_all_ips(JObj) ->
- kz_json:foldl(fun extract_ips_fold/3, [], JObj).
-
--spec extract_ips_fold(kz_json:path(), kz_json:object(), acl_ips()) -> acl_ips().
-extract_ips_fold(_K, JObj, IPs) ->
- case kz_json:get_value(<<"cidr">>, JObj) of
- 'undefined' -> IPs;
- CIDR ->
- AuthorizingId = kz_json:get_value(<<"authorizing_id">>, JObj),
- [{CIDR, AuthorizingId} | IPs]
- end.
-
--type gateway_ip() :: {non_neg_integer(), kz_term:api_binary(), kz_term:api_binary()}.
--type gateway_ips() :: [gateway_ip()].
--spec extract_gateway_ips(kz_json:objects(), non_neg_integer(), gateway_ips()) -> gateway_ips().
-extract_gateway_ips([], _, IPs) -> IPs;
-extract_gateway_ips([Gateway|Gateways], Idx, IPs) ->
- IP = {Idx
- ,kz_json:get_ne_value(<<"inbound_ip">>, Gateway)
- ,kz_json:get_ne_value(<<"server">>, Gateway)
- },
- extract_gateway_ips(Gateways, Idx + 1, [IP|IPs]).
-
--spec validate_ip(kz_term:api_binary(), sip_auth_ips(), acl_ips(), kz_term:api_binary()) -> boolean().
-validate_ip(IP, SIPAuth, ACLs, ResourceId) ->
- lists:all(fun({CIDR, AuthId}) ->
- AuthId =:= ResourceId
- orelse not (kz_network_utils:verify_cidr(IP, CIDR))
- end, ACLs)
- andalso lists:all(fun({AuthIp, Id}) ->
- IP =/= AuthIp
- orelse ResourceId =:= Id
- end, SIPAuth).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec maybe_aggregate_resources(kz_json:objects()) -> 'ok'.
-maybe_aggregate_resources([]) -> 'ok';
-maybe_aggregate_resources([Resource|Resources]) ->
- 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, [])
- )
- of
- 'true' ->
- aggregate_resource(Resource),
- _ = kapi_switch:publish_reload_gateways(),
- _ = kapi_switch:publish_reload_acls(),
- maybe_aggregate_resources(Resources);
- 'false' ->
- _ = maybe_remove_aggregates([Resource]),
- maybe_aggregate_resources(Resources)
- end.
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec maybe_remove_aggregates(kz_json:objects()) -> '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.
diff --git a/applications/crossbar/src/modules/cb_migration_disable_notify.erl b/applications/crossbar/src/modules/cb_migration_disable_notify.erl
deleted file mode 100644
index c54dc5731f2..00000000000
--- a/applications/crossbar/src/modules/cb_migration_disable_notify.erl
+++ /dev/null
@@ -1,26 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Crawl accounts and disable notify settings so that we use Teletype instead
-%%% @author Mark Magnusson
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_migration_disable_notify).
-
--export([perform_migration/2]).
-
--include("crossbar.hrl").
-
--spec perform_migration(binary(), cb_context:context()) -> cb_context:context().
-perform_migration(Account, Context) ->
- lager:info("migrating account ~p from notify to teletype...", [Account]),
-
- Updates = [{[<<"notifications">>, <<"voicemail_to_email">>], 'null'}
- ,{[<<"notifications">>, <<"fax_to_email">>], 'null'}
- ],
- {'ok', _} = kzd_accounts:update(Account, Updates),
- cb_context:set_resp_status(Context, 'success').
diff --git a/applications/crossbar/src/modules/cb_migrations.erl b/applications/crossbar/src/modules/cb_migrations.erl
index c1a6c6a09f3..9ee8a14e3d2 100644
--- a/applications/crossbar/src/modules/cb_migrations.erl
+++ b/applications/crossbar/src/modules/cb_migrations.erl
@@ -20,19 +20,23 @@
-include("crossbar.hrl").
%% {ACCOUNT_ID}.migrations
--define(MIGRATIONS_DOC, <<"migrations">>).
+-define(MIGRATIONS_DOC_ID, <<"migrations">>).
-%% Id, Description, Callback Module
--define(MIGRATIONS_LIST, [{<<"notify_to_teletype">>, <<"Migrate account and all sub accounts to Teletype">>, 'cb_migration_disable_notify'}
- ]).
-
--spec init() -> ok.
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec init() -> 'ok'.
init() ->
_ = crossbar_bindings:bind(<<"*.allowed_methods.migrations">>, ?MODULE, 'allowed_methods'),
_ = crossbar_bindings:bind(<<"*.resource_exists.migrations">>, ?MODULE, 'resource_exists'),
_ = crossbar_bindings:bind(<<"*.validate.migrations">>, ?MODULE, 'validate'),
- ok.
+ 'ok'.
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
-spec allowed_methods() -> http_methods().
allowed_methods() ->
[?HTTP_GET].
@@ -41,15 +45,23 @@ allowed_methods() ->
allowed_methods(_MigrationId) ->
[?HTTP_GET, ?HTTP_POST].
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
-spec resource_exists() -> 'true'.
resource_exists() -> 'true'.
-spec resource_exists(path_token()) -> 'true'.
resource_exists(_) -> 'true'.
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
-spec validate(cb_context:context()) -> cb_context:context().
validate(Context) ->
- maybe_create_migration_doc(cb_context:account_db(Context)),
+ maybe_create_migration_doc(Context),
validate(Context, cb_context:req_verb(Context)).
-spec validate(cb_context:context(), path_token()) -> cb_context:context().
@@ -66,43 +78,50 @@ validate(Context, DocId, ?HTTP_GET) ->
validate(Context, DocId, ?HTTP_POST) ->
maybe_perform_migration(DocId, Context).
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
-spec load_migration_list(cb_context:context()) -> cb_context:context().
load_migration_list(Context) ->
- Format = fun({I, D, _C}, Acc) ->
- kz_json:set_value(I, D, Acc)
- end,
-
- Resp = lists:foldl(Format, kz_json:new(), ?MIGRATIONS_LIST),
- Context1 = cb_context:set_resp_data(Context, Resp),
-
- cb_context:set_resp_status(Context1, 'success').
+ Setters = [{fun cb_context:set_resp_data/2, 'success'}
+ ,{fun cb_context:set_resp_data/2, crossbar_migration:list()}
+ ],
+ cb_context:setters(Context, Setters).
-spec load_migration_summary(binary(), cb_context:context()) -> cb_context:context().
load_migration_summary(MigId, Context) ->
- case lists:keyfind(MigId, 1, ?MIGRATIONS_LIST) of
- 'false' ->
+ case kz_json:get_ne_binary_value(MigId, crossbar_migration:list()) of
+ 'undefined' ->
Context1 = cb_context:set_resp_data(Context, <<"migration not found">>),
cb_context:set_resp_error_code(Context1, 404);
- Migration ->
- render_migration_summary(Migration, Context)
+ Desc ->
+ render_migration_summary(MigId, Desc, Context)
end.
--spec render_migration_summary({binary(), binary(), atom()}, cb_context:context()) -> cb_context:context().
-render_migration_summary({Id, Desc, _Callback}, Context) ->
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec render_migration_summary(kz_term:ne_binary(), kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
+render_migration_summary(Id, Desc, Context) ->
Base = [{<<"id">>, Id}
,{<<"description">>, Desc}
+ | get_migration_performed(Id, Context)
],
-
- Perf = get_migration_performed(Id, Context),
- Resp = kz_json:from_list(Base ++ Perf),
+ Resp = kz_json:from_list(Base),
Context1 = cb_context:set_resp_data(Context, Resp),
cb_context:set_resp_status(Context1, 'success').
--spec get_migration_performed(binary(), cb_context:context()) -> list().
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec get_migration_performed(binary(), cb_context:context()) -> kz_term:proplist().
get_migration_performed(Id, Context) ->
- case kz_datamgr:open_cache_doc(cb_context:account_db(Context), ?MIGRATIONS_DOC) of
+ case kz_datamgr:open_cache_doc(cb_context:account_db(Context), ?MIGRATIONS_DOC_ID) of
{'ok', Doc} ->
check_migration_performed(Id, Doc);
@@ -110,7 +129,7 @@ get_migration_performed(Id, Context) ->
[{<<"performed">>, 'false'}]
end.
--spec check_migration_performed(binary(), kz_json:object()) -> list().
+-spec check_migration_performed(binary(), kz_json:object()) -> kz_term:proplist().
check_migration_performed(Id, Doc) ->
case kz_json:get_value([<<"migrations_performed">>, Id], Doc) of
'undefined' ->
@@ -120,7 +139,11 @@ check_migration_performed(Id, Doc) ->
[{<<"performed">>, 'true'}, {<<"performed_time">>, kz_json:get_value(<<"performed_time">>, Value)}]
end.
--spec maybe_perform_migration(binary(), cb_context:context()) -> cb_context:context().
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec maybe_perform_migration(path_token(), cb_context:context()) -> cb_context:context().
maybe_perform_migration(MigId, Context) ->
case kz_json:get_value(<<"perform_migration">>, cb_context:req_data(Context)) of
<<"now">> ->
@@ -131,91 +154,69 @@ maybe_perform_migration(MigId, Context) ->
cb_context:add_validation_error(<<"migration">>, <<"failed">>, Cause, Context)
end.
--spec check_migration_valid(binary(), cb_context:context()) -> cb_context:context().
+-spec check_migration_valid(path_token(), cb_context:context()) -> cb_context:context().
check_migration_valid(MigId, Context) ->
- case lists:keyfind(MigId, 1, ?MIGRATIONS_LIST) of
- 'false' ->
+ case kz_json:get_ne_binary_value(MigId, crossbar_migration:list()) of
+ 'undefined' ->
Cause = kz_json:from_list([{<<"migration">>, <<"not found">>}]),
cb_context:add_validation_error(<<"migration">>, <<"invalid">>, Cause, Context);
- {_, _, Module} ->
- Context1 = perform_migration(MigId, Module, Context),
+ _ ->
+ Context1 = perform_migration(MigId, Context),
cb_context:set_resp_status(Context1, 'success')
end.
--spec perform_migration(binary(), atom(), cb_context:context()) -> cb_context:context().
-perform_migration(MigId, Module, Context) ->
- {'ok', All} = kz_datamgr:get_all_results(<<"accounts">>, <<"accounts/listing_by_descendants">>),
- Account = cb_context:account_id(Context),
-
- Result = case kz_json:is_true(<<"include_descendants">>, cb_context:req_data(Context)) of
- 'true' ->
- Descendants = filter_account_descendants(Account, All, []),
- Filtered = maybe_filter_resellers(Descendants, Context),
- List = [migrate_on_account(kz_json:get_value(<<"id">>, X), MigId, Module, Context) || X <- Filtered],
- kz_json:from_list([{<<"performed_on">>, List}]);
-
- 'false' ->
- _ = migrate_on_account(cb_context:account_id(Context), MigId, Module, Context),
- kz_json:from_list([{<<"performed_on">>, [cb_context:account_id(Context)]}])
- end,
- cb_context:set_resp_data(Context, Result).
-
--spec maybe_filter_resellers(list(), cb_context:context()) -> list(kz_json:object()).
-maybe_filter_resellers(Accounts, Context) ->
- case kz_json:is_true(<<"include_resellers">>, cb_context:req_data(Context)) of
- 'true' -> Accounts;
- 'false' -> filter_account_resellers(Accounts)
+-spec perform_migration(path_token(), cb_context:context()) -> cb_context:context().
+perform_migration(MigId, Context) ->
+ case kz_json:is_true(<<"include_descendants">>, cb_context:req_data(Context)) of
+ 'true' ->
+ Descendants = get_account_descendants(Context),
+ List = [migrate_on_account(AccountId, MigId, Context) || AccountId <- Descendants],
+ cb_context:set_resp_data(Context, kz_json:from_list([{<<"performed_on">>, List}]));
+
+ 'false' ->
+ _ = migrate_on_account(cb_context:account_id(Context), MigId, Context),
+ cb_context:set_resp_data(Context, kz_json:from_list([{<<"performed_on">>, [cb_context:account_id(Context)]}]))
+ end.
+
+-spec get_account_descendants(cb_context:context()) -> kz_term:ne_binaries().
+get_account_descendants(Context) ->
+ AccountId = cb_context:account_id(Context),
+ IncludeResellers = kz_json:is_true(<<"include_resellers">>, cb_context:req_data(Context)),
+
+ ViewOptions = [{'startkey', [AccountId]}
+ ,{'endkey', [AccountId, kz_json:new()]}
+ ],
+ View = <<"accounts/listing_by_descendants">>,
+ case kz_datamgr:get_results(?KZ_ACCOUNTS_DB, View, ViewOptions) of
+ {'ok', JObjs} ->
+ Descendants = [kz_doc:id(JObj) || JObj <- JObjs],
+ [AccountId, maybe_filter_resellers(Descendants, IncludeResellers)];
+ {'error', _Reason} ->
+ lager:debug("failed to get account ~s descendants: ~p", [AccountId, _Reason]),
+ [AccountId]
end.
--spec filter_account_descendants(binary(), list(), list()) -> list().
-filter_account_descendants(Account, [H|T], Acc) ->
- case kz_json:get_value(<<"key">>, H) of
- [Account, _] -> filter_account_descendants(Account, T, [H|Acc]);
- _OtherValue -> filter_account_descendants(Account, T, Acc)
- end;
-
-filter_account_descendants(_Account, [], Acc) ->
- Acc.
-
--spec filter_account_resellers(list()) -> list().
-filter_account_resellers(Accounts) ->
- Resellers = get_resellers(Accounts, []),
- filter_account_resellers(Accounts, Resellers, []).
-
--spec filter_account_resellers(list(), list(), list()) -> list().
-filter_account_resellers([H|T], Res, Acc) ->
- Tree = kz_json:get_value([<<"value">>, <<"tree">>], H),
-
- case lists:subtract(Tree, Res) of
- New when length(New) < length(Tree) ->
- filter_account_resellers(T, Res, Acc);
-
- _NotInList ->
- filter_account_resellers(T, Res, [H|Acc])
- end;
-
-filter_account_resellers([], _Res, Acc) ->
- Acc.
-
--spec get_resellers(list(), list()) -> list().
-get_resellers([H|T], Acc) ->
- Account = kz_json:get_value(<<"id">>, H),
- case kz_services_reseller:is_reseller(Account) of
- 'true' -> get_resellers(T, [Account|Acc]);
- 'false' -> get_resellers(T, Acc)
- end;
-
-get_resellers([], Acc) ->
- Acc.
-
--spec migrate_on_account(binary(), binary(), atom(), cb_context:context()) -> binary().
-migrate_on_account(Account, MigId, Module, Context) ->
- Result = Module:perform_migration(Account, Context),
+-spec maybe_filter_resellers(kz_term:ne_binaries(), boolean()) -> kz_term:ne_binaries().
+maybe_filter_resellers(AccountIds, 'false') ->
+ [Id
+ || Id <- AccountIds,
+ not kz_services_reseller:is_reseller(Id)
+ ];
+maybe_filter_resellers(AccountIds, 'true') ->
+ AccountIds.
+
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec migrate_on_account(kz_term:ne_binary(), kz_term:ne_binary(), cb_context:context()) -> binary().
+migrate_on_account(Account, MigId, Context) ->
+ Result = crossbar_migration:perform(MigId, Account, Context),
maybe_mark_as_complete(MigId, Account, Result),
Account.
--spec maybe_mark_as_complete(binary(), binary(), cb_context:context()) -> 'ok'.
+-spec maybe_mark_as_complete(kz_term:ne_binary(), kz_term:ne_binary(), cb_context:context()) -> 'ok'.
maybe_mark_as_complete(MigId, Account, Context) ->
case cb_context:resp_status(Context) of
'success' ->
@@ -224,14 +225,14 @@ maybe_mark_as_complete(MigId, Account, Context) ->
lager:info("migration ~p failed to complete", [MigId])
end.
--spec mark_migration_complete(binary(), binary(), cb_context:context()) -> 'ok'.
+-spec mark_migration_complete(kz_term:ne_binary(), kz_term:ne_binary(), cb_context:context()) -> 'ok'.
mark_migration_complete(MigId, AccountId, Context) ->
lager:info("migration ~p completed successfully on account ~p", [MigId, AccountId]),
AccountDb = kz_util:format_account_db(AccountId),
- maybe_create_migration_doc(AccountDb),
+ maybe_create_migration_doc(Context),
- {'ok', Doc} = kz_datamgr:open_cache_doc(AccountDb, ?MIGRATIONS_DOC),
+ {'ok', Doc} = kz_datamgr:open_cache_doc(AccountDb, ?MIGRATIONS_DOC_ID),
Migrations = kz_json:get_value(<<"migrations_performed">>, Doc),
User = cb_context:auth_user_id(Context),
@@ -259,22 +260,30 @@ get_user_name(AccountId, UserId) ->
_ -> 'undefined'
end.
--spec maybe_create_migration_doc(binary()) -> 'ok'.
-maybe_create_migration_doc(Account) ->
- case kz_datamgr:open_cache_doc(Account, ?MIGRATIONS_DOC) of
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec maybe_create_migration_doc(cb_context:context()) -> 'ok'.
+maybe_create_migration_doc(Context) ->
+ AccountDb = cb_context:account_db(Context),
+ case kz_datamgr:open_cache_doc(AccountDb, ?MIGRATIONS_DOC_ID) of
{'ok', _} -> 'ok';
{'error', 'not_found'} ->
- lager:info("creating migrations document for account ~p", [Account]),
- create_migration_doc(Account)
+ lager:info("creating migrations document for account ~p", [kz_util:format_account_id(AccountDb)]),
+ create_migration_doc(Context)
end.
--spec create_migration_doc(binary()) -> 'ok'.
-create_migration_doc(Account) ->
- Update = [{<<"pvt_created">>, kz_time:now_s()}
- ,{<<"migrations_performed">>, []}
- ],
- UpdateOptions = [{'update', Update}
- ,{'ensure_saved', 'true'}
- ],
- {'ok', _} = kz_datamgr:update_doc(Account, ?MIGRATIONS_DOC, UpdateOptions),
- lager:debug("created migration doc for account ~s", [Account]).
+-spec create_migration_doc(cb_context:context()) -> 'ok'.
+create_migration_doc(Context) ->
+ AccountDb = cb_context:account_db(Context),
+
+ Setters = [{fun kz_doc:set_id/2, ?MIGRATIONS_DOC_ID}
+ ,{fun kz_doc:set_type/2, <<"migrations">>}
+ ],
+ Doc = kz_doc:setters(kz_json:from_list([{<<"migrations_performed">>, []}]), Setters),
+ JObj = crossbar_doc:update_pvt_parameters(Doc, Context),
+
+ _ = kz_datamgr:save_doc(AccountDb, JObj),
+
+ lager:debug("created migration doc for account ~s", [kz_util:format_account_id(AccountDb)]).
diff --git a/applications/crossbar/src/modules/cb_onboard.erl b/applications/crossbar/src/modules/cb_onboard.erl
deleted file mode 100644
index 722bb56daf0..00000000000
--- a/applications/crossbar/src/modules/cb_onboard.erl
+++ /dev/null
@@ -1,597 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2010-2019, 2600Hz
-%%% @doc Handle client requests for onboard documents
-%%% @author Karl Anderson
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_onboard).
-
--export([init/0
- ,allowed_methods/0
- ,resource_exists/0
- ,validate/1
- ,authorize/1
- ,authenticate/1
- ,put/1
- ]).
-
--include("crossbar.hrl").
-
--define(OB_CONFIG_CAT, <<(?CONFIG_CAT)/binary, ".onboard">>).
--define(DEFAULT_FLOW, <<"{\"data\": { \"id\": \"~s\" }, \"module\": \"user\", \"children\": { \"_\": { \"data\": { \"id\": \"~s\" }, \"module\": \"voicemail\", \"children\": {}}}}">>).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> ok.
-init() ->
- _ = crossbar_bindings:bind(<<"*.authorize">>, ?MODULE, 'authorize'),
- _ = crossbar_bindings:bind(<<"*.authenticate">>, ?MODULE, 'authenticate'),
- _ = crossbar_bindings:bind(<<"*.allowed_methods.onboard">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"*.resource_exists.onboard">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"*.validate.onboard">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"*.execute.get.onboard">>, ?MODULE, 'get'),
- _ = crossbar_bindings:bind(<<"*.execute.put.onboard">>, ?MODULE, 'put'),
- ok.
-
--spec authorize(cb_context:context()) -> boolean().
-authorize(Context) ->
- authorize(cb_context:req_verb(Context), cb_context:req_nouns(Context)).
-authorize(?HTTP_PUT, [{<<"onboard">>,[]}]) -> 'true';
-authorize(_, _) -> 'false'.
-
--spec authenticate(cb_context:context()) -> boolean().
-authenticate(Context) ->
- authenticate(cb_context:req_verb(Context), cb_context:req_nouns(Context)).
-authenticate(?HTTP_PUT, [{<<"onboard">>,[]}]) -> 'true';
-authenticate(_, _) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
--spec allowed_methods() -> http_methods().
-allowed_methods() ->
- [?HTTP_PUT].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
--spec resource_exists() -> 'true'.
-resource_exists() ->
- 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- validate(Context, cb_context:req_verb(Context)).
-
-validate(Context, ?HTTP_PUT) ->
- JObj = cb_context:req_data(Context),
- Generators = [fun(R) -> create_extensions(JObj, Context, R) end
- ,fun(R) -> create_phone_numbers(JObj, Context, R) end
- ,fun(R) -> create_braintree_cards(JObj, Context, R) end
- ,fun(R) -> create_account(JObj, Context, R) end
- ],
- {P, Failures} = lists:foldr(fun(F, Acc) -> F(Acc) end, {[], kz_json:new()}, Generators),
- case kz_json:is_empty(Failures) of
- 'true' ->
- cb_context:setters(Context, [{fun cb_context:set_doc/2, lists:flatten(P)}
- ,{fun cb_context:set_resp_status/2, 'success'}
- ]);
- 'false' ->
- crossbar_util:response_invalid_data(Failures, Context)
- end.
-
--spec put(cb_context:context()) -> cb_context:context().
-put(Context) ->
- Data = cb_context:doc(Context),
- Context1 = populate_new_account(Data, Context),
- create_response(Context1).
-
-%%------------------------------------------------------------------------------
-%% @doc This function will loop over all the 'extensions' and collect
-%% valid context's for users, voicemail boxes, devices, and callflows.
-%% Any errors will also be collected.
-%% @end
-%%------------------------------------------------------------------------------
--spec create_extensions(kz_json:object(), cb_context:context(), {kz_term:proplist(), kz_json:object()}) -> {kz_term:proplist(), kz_json:object()}.
-create_extensions(JObj, Context, Results) ->
- Extensions = kz_json:get_value(<<"extensions">>, JObj, []),
- create_extensions(Extensions, 1, Context, Results).
-
-create_extensions([], _, _, Results) ->
- Results;
-create_extensions([Exten|Extens], Iteration, Context, {PassAcc, FailAcc}) ->
- Generators = [fun(R) -> create_exten_callflow(Exten, Iteration, Context, R) end
- ,fun(R) -> create_vmbox(Exten, Iteration, Context, R) end
- ,fun(R) -> create_device(Exten, Iteration, Context, R) end
- ,fun(R) -> create_user(Exten, Iteration, Context, R) end
- ],
- {P, F} = lists:foldr(fun(F, Acc) -> F(Acc) end, {[], kz_json:new()}, Generators),
- case kz_json:is_empty(F) of
- 'true' ->
- create_extensions(Extens, Iteration + 1, Context, {[P|PassAcc], FailAcc});
- 'false' ->
- Failures = kz_json:set_value([<<"extensions">>, kz_term:to_binary(Iteration)], F, FailAcc),
- create_extensions(Extens, Iteration + 1, Context, {[P|PassAcc], Failures})
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc This function will use the bindings to validate and create a context
-%% record to generate an account. Any failure will be added to the error
-%% json object.
-%% @end
-%%------------------------------------------------------------------------------
--spec create_account(kz_json:object(), cb_context:context(), {kz_term:proplist(), kz_json:object()}) ->
- {kz_term:proplist(), kz_json:object()}.
-create_account(JObj, Context, {Pass, Fail}) ->
- Account = kz_json:get_value(<<"account">>, JObj, kz_json:new()),
- Generators = [fun(J) -> kz_doc:set_id(J, kz_datamgr:get_uuid()) end
- ],
- NewReqData = lists:foldr(fun(F, J) -> F(J) end, Account, Generators),
- Payload = [cb_context:setters(Context, [{fun cb_context:set_req_data/2, NewReqData}
- ,{fun cb_context:set_req_nouns/2, [{?KZ_ACCOUNTS_DB, []}]}
- ])
- ],
- Context1 = crossbar_bindings:fold(<<"*.validate.accounts">>, Payload),
- case cb_context:response(Context1) of
- {'ok', _} -> {[{?KZ_ACCOUNTS_DB, Context1}|Pass], Fail};
- {'error', {_, _, Errors}} -> {Pass, kz_json:set_value(<<"account">>, Errors, Fail)}
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc This function will use the bindings to validate and create a context
-%% record to generate an account. Any failure will be added to the error
-%% json object.
-%% @end
-%%------------------------------------------------------------------------------
--spec create_phone_numbers(kz_json:object(), cb_context:context(), {kz_term:proplist(), kz_json:object()}) ->
- {kz_term:proplist(), kz_json:object()}.
-create_phone_numbers(JObj, Context, Results) ->
- PhoneNumbers = kz_json:get_value(<<"phone_numbers">>, JObj),
- lists:foldr(fun(Number, R) ->
- create_phone_number(Number
- ,kz_json:get_value([<<"phone_numbers">>, Number], JObj)
- ,Context, R)
- end, Results, kz_json:get_keys(PhoneNumbers)).
-
-create_phone_number(Number, Properties, Context, {Pass, Fail}) ->
- Payload = [cb_context:setters(Context, [{fun cb_context:set_req_data/2, Properties}
- ,{fun cb_context:set_account_db/2, <<"--">>}
- ])
- ,Number
- ,<<"activate">>
- ],
- Context1 = crossbar_bindings:fold(<<"*.validate.phone_numbers">>, Payload),
- case cb_context:response(Context1) of
- {'ok', _} -> {[{<<"phone_numbers">>, cb_context:store(Context1, 'number', Number)}|Pass], Fail};
- {'error', {_, _, Errors}} -> {Pass, kz_json:set_value(<<"phone_numbers">>, Errors, Fail)}
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc This function will use the bindings to validate and create a context
-%% record to generate an braintree_customer. Any failure will be added to the error
-%% json object.
-%% @end
-%%------------------------------------------------------------------------------
--spec create_braintree_cards(kz_json:object(), cb_context:context(), {kz_term:proplist(), kz_json:object()}) -> {kz_term:proplist(), kz_json:object()}.
-create_braintree_cards(JObj, Context, {Pass, Fail}) ->
- Account = get_context_jobj(<<"accounts">>, Pass),
- case kz_doc:id(Account) of
- 'undefined' ->
- Error = kz_json:set_value([<<"account_id">>, <<"required">>], <<"account failed validation">>, kz_json:new()),
- {Pass, kz_json:set_value(<<"braintree">>, Error, Fail)};
- AccountId ->
- Customer = kz_json:get_value(<<"braintree">>, JObj, kz_json:new()),
- Generators = [fun(J) ->
- case kz_json:get_ne_value(<<"credit_card">>, J) of
- 'undefined' -> kz_json:set_value(<<"credit_card">>, kz_json:new(), J);
- _Else -> J
- end
- end
- ],
- NewReaData = lists:foldr(fun(F, J) -> F(J) end, Customer, Generators),
- Payload = [cb_context:setters(Context, [{fun cb_context:set_req_data/2, NewReaData}
- ,{fun cb_context:set_account_id/2, AccountId}
- ,{fun cb_context:set_req_verb/2, ?HTTP_POST}
- ])
- ,<<"customer">>
- ],
- Context1 = crossbar_bindings:fold(<<"*.validate.braintree">>, Payload),
- case cb_context:response(Context1) of
- {'ok', _} -> {[{<<"braintree">>, Context1}|Pass], Fail};
- {'error', {_, _, Errors}} -> {Pass, kz_json:set_value(<<"braintree">>, Errors, Fail)}
- end
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc This function will use the bindings to validate and create a context
-%% record to generate a user. Any failure will be added to the error
-%% json object.
-%% @end
-%%------------------------------------------------------------------------------
--spec create_user(kz_json:object(), pos_integer(), cb_context:context(), {kz_term:proplist(), kz_json:object()})
- -> {kz_term:proplist(), kz_json:object()}.
-create_user(JObj, Iteration, Context, {Pass, Fail}) ->
- User = kz_json:get_value(<<"user">>, JObj, kz_json:new()),
- Generators = [fun(J) -> kz_doc:set_id(J, kz_datamgr:get_uuid()) end
- ,fun(J) when Iteration =:= 1 ->
- %% ensure the first user is a admin
- kz_json:set_value(<<"priv_level">>, <<"admin">>, J);
- (J) -> J
- end
- ,fun(J) ->
- case kz_json:get_ne_value(<<"first_name">>, J) of
- 'undefined' ->
- kz_json:set_value(<<"first_name">>, <<"User">>, J);
- _ -> J
- end
- end
- ,fun(J) ->
- case kz_json:get_ne_value(<<"last_name">>, J) of
- 'undefined' ->
- kz_json:set_value(<<"last_name">>, kz_term:to_binary(Iteration), J);
- _ -> J
- end
- end
- ,fun(J) ->
- case kz_json:get_ne_value(<<"username">>, User) of
- 'undefined' ->
- Email = kz_json:get_ne_value(<<"email">>, J),
- FirstName = kz_json:get_ne_value(<<"first_name">>, J),
- LastName = kz_json:get_ne_value(<<"last_name">>, J),
- Username = generate_username(Email, FirstName, LastName),
- kz_json:set_value(<<"username">>, Username, J);
- _Else -> J
- end
- end
- ],
- NewReqData = lists:foldr(fun(F, J) -> F(J) end, User, Generators),
- Payload = [cb_context:set_req_data(Context, NewReqData)],
- Context1 = crossbar_bindings:fold(<<"*.validate.users">>, Payload),
- case cb_context:response(Context1) of
- {'ok', _} -> {[{<<"users">>, cb_context:store(Context1, 'iteration', Iteration)}|Pass], Fail};
- {'error', {_, _, Errors}} -> {Pass, kz_json:set_value(<<"users">>, Errors, Fail)}
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc This function will use the bindings to validate and create a context
-%% record to generate a device. Any failure will be added to the error
-%% json object.
-%% @end
-%%------------------------------------------------------------------------------
--spec create_device(kz_json:object(), pos_integer(), cb_context:context(), {kz_term:proplist(), kz_json:object()})
- -> {kz_term:proplist(), kz_json:object()}.
-create_device(JObj, Iteration, Context, {Pass, Fail}) ->
- Device = kz_json:get_value(<<"device">>, JObj, kz_json:new()),
- Generators = [fun(J) -> kz_doc:set_id(J, kz_datamgr:get_uuid()) end
- ,fun(J) ->
- User = get_context_jobj(<<"users">>, Pass),
- case kz_doc:id(User) of
- 'undefined' -> J;
- OwnerId -> kz_json:set_value(<<"owner_id">>, OwnerId, J)
- end
- end
- ,fun(J) ->
- case kz_json:get_ne_value(<<"name">>, J) of
- 'undefined' ->
- User = get_context_jobj(<<"users">>, Pass),
- FirstName = kz_json:get_value(<<"first_name">>, User, <<"User">>),
- LastName = kz_json:get_value(<<"last_name">>, User, kz_term:to_binary(Iteration)),
- Name = list_to_binary([FirstName, " ", LastName, "'s Device"]),
- kz_json:set_value(<<"name">>, Name, J);
- _ ->
- J
- end
- end
- ,fun(J) ->
- case kzd_devices:sip_username(J) of
- 'undefined' ->
- Strength = kapps_config:get_integer(?OB_CONFIG_CAT, <<"device_username_strength">>, 3),
- kzd_devices:set_sip_username(J, list_to_binary(["user_", kz_binary:rand_hex(Strength)]));
- _ ->
- J
- end
- end
- ,fun(J) ->
- case kzd_devices:sip_password(J) of
- 'undefined' ->
- Strength = kapps_config:get_integer(?OB_CONFIG_CAT, <<"device_pwd_strength">>, 6),
- kzd_devices:set_sip_password(J, kz_binary:rand_hex(Strength));
- _ ->
- J
- end
- end
- ],
- NewReqData = lists:foldr(fun(F, J) -> F(J) end, Device, Generators),
- Payload = [cb_context:set_req_data(Context, NewReqData)],
- Context1 = crossbar_bindings:fold(<<"*.validate.devices">>, Payload),
- case cb_context:response(Context1) of
- {'ok', _} -> {[{<<"devices">>, cb_context:store(Context1, 'iteration', Iteration)}|Pass], Fail};
- {'error', {_, _, Errors}} -> {Pass, kz_json:set_value(<<"devices">>, Errors, Fail)}
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc This function will use the bindings to validate and create a context
-%% record to generate a vmbox. Any failure will be added to the error
-%% json object.
-%% @end
-%%------------------------------------------------------------------------------
--spec create_vmbox(kz_json:object(), pos_integer(), cb_context:context(), {kz_term:proplist(), kz_json:object()})
- -> {kz_term:proplist(), kz_json:object()}.
-create_vmbox(JObj, Iteration, Context, {Pass, Fail}) ->
- VMBox = kz_json:get_value(<<"vmbox">>, JObj, kz_json:new()),
- Generators = [fun(J) -> kz_doc:set_id(J, kz_datamgr:get_uuid()) end
- ,fun(J) ->
- User = get_context_jobj(<<"users">>, Pass),
- case kz_doc:id(User) of
- 'undefined' -> J;
- OwnerId -> kz_json:set_value(<<"owner_id">>, OwnerId, J)
- end
- end
- ,fun(J) ->
- case kz_json:get_ne_value(<<"mailbox">>, J) of
- 'undefined' ->
- StartExten = kapps_config:get_integer(?OB_CONFIG_CAT, <<"default_vm_start_exten">>, 3 * ?MILLISECONDS_IN_SECOND),
- kz_json:set_value(<<"mailbox">>, kz_term:to_binary(StartExten + Iteration), J);
- _ ->
- J
- end
- end
- ,fun(J) ->
- case kz_json:get_ne_value(<<"name">>, J) of
- 'undefined' ->
- User = get_context_jobj(<<"users">>, Pass),
- FirstName = kz_json:get_value(<<"first_name">>, User, <<"User">>),
- LastName = kz_json:get_value(<<"last_name">>, User, kz_term:to_binary(Iteration)),
- Name = list_to_binary([FirstName, " ", LastName, "'s Voicemail"]),
- kz_json:set_value(<<"name">>, Name, J);
- _ ->
- J
- end
- end
- ],
- NewReqData = lists:foldr(fun(F, J) -> F(J) end, VMBox, Generators),
- Payload = [cb_context:set_req_data(Context, NewReqData)],
- Context1 = crossbar_bindings:fold(<<"*.validate.vmboxes">>, Payload),
- case cb_context:response(Context1) of
- {'ok', _} -> {[{<<"vmboxes">>, cb_context:store(Context1, 'iteration', Iteration)}|Pass], Fail};
- {'error', {_, _, Errors}} -> {Pass, kz_json:set_value(<<"vmboxes">>, Errors, Fail)}
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc This function will use the bindings to validate and create a context
-%% record to generate a extension callflow. Any failure will be added
-%% to the error json object.
-%% @end
-%%------------------------------------------------------------------------------
--spec create_exten_callflow(kz_json:object(), pos_integer(), cb_context:context(), {kz_term:proplist(), kz_json:object()})
- -> {kz_term:proplist(), kz_json:object()}.
-create_exten_callflow(JObj, Iteration, Context, {Pass, Fail}) ->
- Callflow = kz_json:get_value(<<"callflow">>, JObj, kz_json:new()),
- Generators = [fun(J) ->
- User = get_context_jobj(<<"users">>, Pass),
- VMBox = get_context_jobj(<<"vmboxes">>, Pass),
- DefaultFlow = kapps_config:get_string(?OB_CONFIG_CAT, <<"default_extension_callflow">>, ?DEFAULT_FLOW),
- Flow = kz_json:decode(io_lib:format(DefaultFlow, [kz_doc:id(User)
- ,kz_doc:id(VMBox)
- ])),
- kz_json:set_value(<<"flow">>, Flow, J)
- end
- ,fun(J) -> kz_doc:set_id(J, kz_datamgr:get_uuid()) end
- ,fun(J) ->
- case [Num || Num <- kz_json:get_ne_value(<<"numbers">>, J, [])
- , not kz_term:is_empty(Num)]
- of
- [] ->
- StartExten = kapps_config:get_integer(?OB_CONFIG_CAT
- ,<<"default_callflow_start_exten">>
- ,2 * ?MILLISECONDS_IN_SECOND),
- kz_json:set_value(<<"numbers">>, [kz_term:to_binary(StartExten + Iteration)], J);
- Numbers -> kz_json:set_value(<<"numbers">>, Numbers, J)
- end
- end
- ],
- NewReqData = lists:foldr(fun(F, J) -> F(J) end, Callflow, Generators),
- Payload = [cb_context:set_req_data(Context, NewReqData)],
- Context1 = crossbar_bindings:fold(<<"*.validate.callflows">>, Payload),
- case cb_context:response(Context1) of
- {'ok', _} -> {[{<<"callflows">>, cb_context:store(Context1, 'iteration', Iteration)}|Pass], Fail};
- {'error', {_, _, Errors}} -> {Pass, kz_json:set_value(<<"callflows">>, Errors, Fail)}
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc This function will loop over the previously generated context records
-%% providing each to the respective 'put' binding in order to create
-%% the objects. Starts with the account :)
-%% @end
-%%------------------------------------------------------------------------------
-
--spec populate_new_account(kz_term:proplist(), cb_context:context()) -> cb_context:context().
-populate_new_account(Props, _) ->
- Context = props:get_value(?KZ_ACCOUNTS_DB, Props),
- Context1 = crossbar_bindings:fold(<<"*.execute.put.accounts">>, [cb_context:set_resp_status(Context, 'error')]),
- AccountDb = cb_context:account_db(Context1),
- AccountId = cb_context:account_id(Context1),
- case cb_context:response(Context1) of
- {'error', _} ->
- cb_context:setters(Context1, [{fun cb_context:set_account_id/2, 'undefined'}
- ,{fun cb_context:set_account_db/2, 'undefined'}
- ]);
- {'ok', _} ->
- Results = populate_new_account(prepare_props(Props), AccountDb, kz_json:new()),
- case kz_json:get_ne_value(<<"errors">>, Results) of
- 'undefined' ->
- lager:debug("new account created ~s (~s)", [AccountId, AccountDb]),
- notfy_new_account(cb_context:doc(Context1)),
- cb_context:set_doc(Context1, kz_json:set_value(<<"account_id">>, AccountId, Results));
- Failures ->
- lager:debug("account creation errors: ~p", [Failures]),
- catch (crossbar_bindings:fold(<<"*.execute.delete.accounts">>, [Context1, AccountId])),
- Ctx2 = cb_context:setters(Context1, [{fun cb_context:set_doc/2, kz_json:delete_key(<<"owner_id">>, Results)}
- ,{fun cb_context:set_account_id/2, 'undefined'}
- ,{fun cb_context:set_account_db/2, 'undefined'}
- ,{fun cb_context:set_resp_data/2, kz_json:new()}
- ]),
- crossbar_util:response_invalid_data(Failures, Ctx2)
- end
- end.
-
--spec populate_new_account(kz_term:proplist(), kz_term:ne_binary(), kz_json:object()) -> kz_json:object().
-populate_new_account([], _, Results) ->
- Results;
-
-populate_new_account([{<<"phone_numbers">>, Context}|Props], AccountDb, Results) ->
- Number = cb_context:fetch(Context, 'number'),
- AccountId = kz_util:format_account_id(AccountDb, 'raw'),
- Payload = [cb_context:setters(Context, [{fun cb_context:set_resp_status/2, 'error'}
- ,{fun cb_context:set_account_db/2, AccountDb}
- ,{fun cb_context:set_auth_account_id/2, AccountId}
- ,{fun cb_context:set_account_id/2, AccountId}
- ])
- ,Number
- ,<<"activate">>
- ],
- Context1 = crossbar_bindings:fold(<<"*.execute.put.phone_numbers">>, Payload),
- case cb_context:response(Context1) of
- {'ok', _} -> populate_new_account(Props, AccountDb, Results);
- {'error', {_, _, Errors}} ->
- populate_new_account(Props, AccountDb
- ,kz_json:set_value([<<"errors">>, <<"phone_numbers">>, Number], Errors, Results))
- end;
-
-populate_new_account([{<<"braintree">>, Context}|Props], AccountDb, Results) ->
- AccountId = kz_util:format_account_id(AccountDb, 'raw'),
- Payload = [cb_context:setters(Context, [{fun cb_context:set_resp_status/2, 'error'}
- ,{fun cb_context:set_account_db/2, AccountDb}
- ,{fun cb_context:set_account_id/2, AccountId}
- ,{fun cb_context:set_req_verb/2, ?HTTP_POST}
- ])
- ,<<"customer">>
- ],
- Context1 = crossbar_bindings:fold(<<"*.execute.post.braintree">>, Payload),
- case cb_context:response(Context1) of
- {'ok', _} -> populate_new_account(Props, AccountDb, Results);
- {'error', {_, _, Errors}} ->
- populate_new_account(Props, AccountDb
- ,kz_json:set_value([<<"errors">>, <<"braintree">>], Errors, Results))
- end;
-
-populate_new_account([{Event, Context}|Props], AccountDb, Results) ->
- Iteration = cb_context:fetch(Context, 'iteration'),
- Payload = [cb_context:setters(Context, [{fun cb_context:set_account_db/2, AccountDb}
- ,{fun cb_context:set_resp_status/2, 'error'}
- ])],
- Context1 = crossbar_bindings:fold(<<"*.execute.put.", Event/binary>>, Payload),
- JObj = cb_context:doc(Context1),
- case cb_context:response(Context1) of
- {'ok', _} ->
- case kzd_users:is_account_admin(JObj) of
- 'true' ->
- populate_new_account(Props, AccountDb
- ,kz_json:set_value(<<"owner_id">>, kz_doc:id(JObj), Results));
- 'false' ->
- populate_new_account(Props, AccountDb, Results)
- end;
- {'error', {_, _, Errors}} ->
- populate_new_account(Props, AccountDb
- ,kz_json:set_value([<<"errors">>, Event, kz_term:to_binary(Iteration)], Errors, Results))
- end.
-
-prepare_props(Props) ->
- lists:sort(fun({<<"braintree">>, _}, {_, _}) -> 'true';
- (_, _) -> 'false'
- end, props:delete(?KZ_ACCOUNTS_DB, Props)).
-
-%%------------------------------------------------------------------------------
-%% @doc Helper function to get the create object out of the successful
-%% context records for a specific key.
-%% @end
-%%------------------------------------------------------------------------------
--spec get_context_jobj(kz_term:ne_binary(), kz_term:proplist()) -> kz_json:object().
-get_context_jobj(Key, Pass) ->
- case props:get_value(Key, Pass) of
- Context when is_tuple(Context) -> cb_context:doc(Context);
- _ -> kz_json:new()
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Attempt to create a token and save it to the token db
-%% @end
-%%------------------------------------------------------------------------------
--spec create_response(cb_context:context()) -> cb_context:context().
-create_response(Context) ->
- JObj = cb_context:doc(Context),
- case cb_context:account_id(Context) of
- 'undefined' ->
- crossbar_util:response_invalid_data(JObj, Context);
- AccountId ->
- TS = kz_time:now_s(),
- Token = [{<<"account_id">>, AccountId}
- ,{<<"owner_id">>, kz_json:get_value(<<"owner_id">>, JObj)}
- ,{<<"created">>, TS}
- ,{<<"modified">>, TS}
- ,{<<"method">>, kz_term:to_binary(?MODULE)}
- ],
- case kz_datamgr:save_doc(?KZ_TOKEN_DB, kz_json:from_list(Token)) of
- {'ok', Doc} ->
- AuthToken = kz_doc:id(Doc),
- lager:debug("created new local auth token ~s", [AuthToken]),
- Context1 = cb_context:setters(Context, [{fun cb_context:set_auth_token/2, AuthToken}
- ,{fun cb_context:set_auth_doc/2, Doc}
- ]),
- crossbar_util:response(kz_json:set_value(<<"auth_token">>, AuthToken, JObj), Context1);
- {'error', R} ->
- lager:debug("could not create new local auth token, ~p", [R]),
- crossbar_util:response('error', 'undefined', 400, JObj, Context)
- end
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Attempt to create a token and save it to the token db
-%% @end
-%%------------------------------------------------------------------------------
--spec notfy_new_account(kz_json:object()) -> 'ok'.
-notfy_new_account(JObj) ->
- Notify = [{<<"Account-Name">>, kzd_accounts:name(JObj)}
- ,{<<"Account-Realm">>, kzd_accounts:realm(JObj)}
- ,{<<"Account-API-Key">>, kzd_accounts:api_key(JObj)}
- ,{<<"Account-ID">>, kz_doc:account_id(JObj)}
- ,{<<"Account-DB">>, kz_doc:account_db(JObj)}
- | kz_api:default_headers(?APP_VERSION, ?APP_NAME)
- ],
- kapps_notify_publisher:cast(Notify, fun kapi_notifications:publish_new_account/1).
-
--spec generate_username(kz_term:api_binary(), kz_term:api_binary(), kz_term:api_binary()) ->
- kz_term:ne_binary().
-generate_username('undefined', 'undefined', _) ->
- kz_binary:rand_hex(3);
-generate_username('undefined', _, 'undefined') ->
- kz_binary:rand_hex(3);
-generate_username('undefined', <>, LastName) ->
- <>;
-generate_username(Email, _, _) ->
- Email.
diff --git a/applications/crossbar/src/modules_v2/cb_phone_numbers_v2.erl b/applications/crossbar/src/modules/cb_phone_numbers.erl
similarity index 98%
rename from applications/crossbar/src/modules_v2/cb_phone_numbers_v2.erl
rename to applications/crossbar/src/modules/cb_phone_numbers.erl
index 3d612ce0628..c817a2993b1 100644
--- a/applications/crossbar/src/modules_v2/cb_phone_numbers_v2.erl
+++ b/applications/crossbar/src/modules/cb_phone_numbers.erl
@@ -10,7 +10,7 @@
%%%
%%% @end
%%%-----------------------------------------------------------------------------
--module(cb_phone_numbers_v2).
+-module(cb_phone_numbers).
-export([init/0
,allowed_methods/0, allowed_methods/1, allowed_methods/2
@@ -88,15 +88,15 @@
%%------------------------------------------------------------------------------
-spec init() -> ok.
init() ->
- _ = crossbar_bindings:bind(<<"v2_resource.authenticate.phone_numbers">>, ?MODULE, 'authenticate'),
- _ = crossbar_bindings:bind(<<"v2_resource.authorize.phone_numbers">>, ?MODULE, 'authorize'),
- _ = crossbar_bindings:bind(<<"v2_resource.allowed_methods.phone_numbers">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"v2_resource.resource_exists.phone_numbers">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"v2_resource.validate.phone_numbers">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"v2_resource.execute.put.phone_numbers">>, ?MODULE, 'put'),
- _ = crossbar_bindings:bind(<<"v2_resource.execute.post.phone_numbers">>, ?MODULE, 'post'),
- _ = crossbar_bindings:bind(<<"v2_resource.execute.patch.phone_numbers">>, ?MODULE, 'patch'),
- _ = crossbar_bindings:bind(<<"v2_resource.execute.delete.phone_numbers">>, ?MODULE, 'delete'),
+ _ = crossbar_bindings:bind(<<"*.authenticate.phone_numbers">>, ?MODULE, 'authenticate'),
+ _ = crossbar_bindings:bind(<<"*.authorize.phone_numbers">>, ?MODULE, 'authorize'),
+ _ = crossbar_bindings:bind(<<"*.allowed_methods.phone_numbers">>, ?MODULE, 'allowed_methods'),
+ _ = crossbar_bindings:bind(<<"*.resource_exists.phone_numbers">>, ?MODULE, 'resource_exists'),
+ _ = crossbar_bindings:bind(<<"*.validate.phone_numbers">>, ?MODULE, 'validate'),
+ _ = crossbar_bindings:bind(<<"*.execute.put.phone_numbers">>, ?MODULE, 'put'),
+ _ = crossbar_bindings:bind(<<"*.execute.post.phone_numbers">>, ?MODULE, 'post'),
+ _ = crossbar_bindings:bind(<<"*.execute.patch.phone_numbers">>, ?MODULE, 'patch'),
+ _ = crossbar_bindings:bind(<<"*.execute.delete.phone_numbers">>, ?MODULE, 'delete'),
ok.
%%------------------------------------------------------------------------------
diff --git a/applications/crossbar/src/modules/cb_pivot.erl b/applications/crossbar/src/modules/cb_pivot.erl
index c1a1a1e2a02..b6142f619e4 100644
--- a/applications/crossbar/src/modules/cb_pivot.erl
+++ b/applications/crossbar/src/modules/cb_pivot.erl
@@ -1,6 +1,6 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
+%%% @doc Crossbar API for pivot.
%%% @author James Aimonetti
%%%
%%% This Source Code Form is subject to the terms of the Mozilla Public
diff --git a/applications/crossbar/src/modules/cb_port_requests.erl b/applications/crossbar/src/modules/cb_port_requests.erl
index 4ffb8903efb..82ca5f6f8a8 100644
--- a/applications/crossbar/src/modules/cb_port_requests.erl
+++ b/applications/crossbar/src/modules/cb_port_requests.erl
@@ -386,7 +386,7 @@ patch(Context, Id) ->
-spec patch(cb_context:context(), path_token(), path_token()) -> cb_context:context().
patch(Context, Id, NewState=?PORT_SUBMITTED) ->
- case phonebook:maybe_create_port_in(Context) of
+ case cb_modules_util:phonebook_port_in(Context) of
{'ok', 'disabled'} ->
save_then_maybe_notify(Context, Id, NewState);
{'ok', Response} ->
@@ -474,7 +474,7 @@ save_and_send_comments(Context, _, []) ->
Context1
end;
save_and_send_comments(Context, Id, NewComments) ->
- case phonebook:maybe_add_comment(Context, NewComments) of
+ case cb_modules_util:phonebook_comment(Context, NewComments) of
{'ok', _} ->
Context1 = save(Context),
case cb_context:resp_status(Context1) of
@@ -538,7 +538,7 @@ date_as_configured_timezone(Date, Time, FromTimezone) ->
%% @doc
%% @end
%%------------------------------------------------------------------------------
--spec handle_phonebook_error(cb_context:context(), phonebook:errors()) -> cb_context:context().
+-spec handle_phonebook_error(cb_context:context(), knm_phonebook:errors()) -> cb_context:context().
handle_phonebook_error(Context, #{code := Code
,payload := Payload
,reason := 'bad_phonebook'
@@ -571,7 +571,7 @@ handle_phonebook_error(Context, #{payload := Payload}) ->
%% this could cause the UI to not showing the 'Fix' button.
-define(IMMEDIATELY_REJECTION_FUDGE_SECONDS, 1).
--spec maybe_reject_port(cb_context:context(), phonebook:errors()) -> cb_context:context().
+-spec maybe_reject_port(cb_context:context(), knm_phonebook:errors()) -> cb_context:context().
maybe_reject_port(Context, #{code := Code
,req_type := 'port_in'
,payload := Payload
@@ -1456,7 +1456,7 @@ port_state_change_notify(Context, Id, State) ->
lager:debug("failed to send the port ~s notification, maybe reverting the state change: ~s:~p"
,[State, _E, _R]
),
- maybe_revert_patch(Context, phonebook:should_send_to_phonebook(Context))
+ maybe_revert_patch(Context, cb_modules_util:should_send_to_phonebook(Context))
end.
-spec state_change_notify_fun(kz_term:ne_binary()) -> function().
diff --git a/applications/crossbar/src/modules/cb_profile.erl b/applications/crossbar/src/modules/cb_profile.erl
index a3856426221..f2667fc9123 100644
--- a/applications/crossbar/src/modules/cb_profile.erl
+++ b/applications/crossbar/src/modules/cb_profile.erl
@@ -1,6 +1,6 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
+%%% @doc Crossbar API for profile.
%%% @author James Aimonetti
%%%
%%% This Source Code Form is subject to the terms of the Mozilla Public
diff --git a/applications/crossbar/src/modules/cb_registrations.erl b/applications/crossbar/src/modules/cb_registrations.erl
index 98878358f06..abace3af327 100644
--- a/applications/crossbar/src/modules/cb_registrations.erl
+++ b/applications/crossbar/src/modules/cb_registrations.erl
@@ -1,11 +1,11 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2011-2019, 2600Hz
%%% @doc Registration viewer / creator
-%%% GET /v1/accounts/{account_id}/registrations :
+%%% GET /v2/accounts/{account_id}/registrations :
%%% Get a list of account registrations
-%%% GET /v1/accounts/{account_id}/registrations/count :
+%%% GET /v2/accounts/{account_id}/registrations/count :
%%% Get a count of account registrations
-%%% GET /v1/registrations :
+%%% GET /v2/registrations :
%%% Get a count of system-wide registrations - for superduper admins only
%%%
%%%
diff --git a/applications/crossbar/src/modules/cb_resources.erl b/applications/crossbar/src/modules/cb_resources.erl
index fec7cf4e4a9..e9932bf857b 100644
--- a/applications/crossbar/src/modules/cb_resources.erl
+++ b/applications/crossbar/src/modules/cb_resources.erl
@@ -53,21 +53,6 @@ init() ->
,{<<"*.execute.post.resources">>, 'post'}
,{<<"*.execute.patch.resources">>, 'patch'}
,{<<"*.execute.delete.resources">>, 'delete'}
-
- ,{<<"*.allowed_methods.global_resources">>, 'allowed_methods'}
- ,{<<"*.resource_exists.global_resources">>, 'resource_exists'}
- ,{<<"*.validate.global_resources">>, 'validate'}
- ,{<<"*.execute.put.global_resources">>, 'put'}
- ,{<<"*.execute.post.global_resources">>, 'post'}
- ,{<<"*.execute.delete.global_resources">>, 'delete'}
-
- ,{<<"*.allowed_methods.local_resources">>, 'allowed_methods'}
- ,{<<"*.resource_exists.local_resources">>, 'resource_exists'}
- ,{<<"*.validate.local_resources">>, 'validate'}
- ,{<<"*.execute.put.local_resources">>, 'put'}
- ,{<<"*.execute.post.local_resources">>, 'post'}
- ,{<<"*.execute.delete.local_resources">>, 'delete'}
-
,{<<"*.authorize">>, 'authorize'}
]).
@@ -75,14 +60,14 @@ init() ->
maybe_start_jobs_listener() ->
case jobs_listener_pid() of
'undefined' ->
- {'ok', Pid} = crossbar_module_sup:start_child('cb_jobs_listener'),
+ {'ok', Pid} = crossbar_module_sup:start_child('crossbar_jobs_listener'),
Pid;
Pid -> Pid
end.
-spec jobs_listener_pid() -> kz_term:api_pid().
jobs_listener_pid() ->
- whereis('cb_jobs_listener').
+ whereis('crossbar_jobs_listener').
-spec authorize(cb_context:context()) ->
boolean() |
@@ -323,7 +308,7 @@ do_post(Context, _Id) ->
Db = cb_context:account_db(Context),
maybe_reload_acls(Db),
Context1 = crossbar_doc:save(Context),
- maybe_aggregate_resource(Context1, Db).
+ maybe_aggregate_resource(Context1, Db, cb_context:resp_status(Context1)).
-spec patch(cb_context:context(), path_token()) -> cb_context:context().
patch(Context, Id) -> do_post(Context, Id).
@@ -333,7 +318,7 @@ put(Context) ->
Db = cb_context:account_db(Context),
maybe_reload_acls(Db),
Context1 = crossbar_doc:save(Context),
- maybe_aggregate_resource(Context1, Db).
+ maybe_aggregate_resource(Context1, Db, cb_context:resp_status(Context1)).
-spec put(cb_context:context(), path_token()) -> cb_context:context().
put(Context, ?COLLECTION) ->
@@ -344,7 +329,7 @@ put(Context, ?JOBS) ->
case cb_context:resp_status(Context1) of
'success' ->
- _ = cb_jobs_listener:publish_new_job(Context),
+ _ = crossbar_jobs_listener:publish_new_job(Context),
crossbar_util:response_202(<<"Job scheduled">>, cb_context:resp_data(Context1), Context1);
_Status ->
Context1
@@ -354,7 +339,7 @@ put(Context, ?JOBS) ->
delete(Context, ResourceId) ->
maybe_reload_acls(cb_context:account_db(Context)),
Context1 = crossbar_doc:delete(Context),
- maybe_remove_aggregate(Context1, ResourceId, cb_context:account_db(Context)).
+ maybe_remove_aggregate(Context1, ResourceId, cb_context:account_db(Context), cb_context:resp_status(Context)).
%%%=============================================================================
%%% Internal functions
@@ -364,16 +349,29 @@ delete(Context, ResourceId) ->
%% @doc
%% @end
%%------------------------------------------------------------------------------
--spec maybe_aggregate_resource(cb_context:context(), kz_term:ne_binary()) -> cb_context:context().
-maybe_aggregate_resource(Context, ?KZ_OFFNET_DB) -> Context;
-maybe_aggregate_resource(Context, _AccountDb) ->
- _ = cb_local_resources:maybe_aggregate_resource(Context),
+-spec maybe_aggregate_resource(cb_context:context(), kz_term:ne_binary(), crossbar_status()) -> cb_context:context().
+maybe_aggregate_resource(Context, ?KZ_OFFNET_DB, _) -> Context;
+maybe_aggregate_resource(Context, _AccountDb, 'success') ->
+ ResourceId = kz_doc:id(cb_context:doc(Context)),
+ case kz_term:is_true(cb_context:fetch(Context, 'aggregate_resource')) of
+ 'false' ->
+ _ = remove_aggregate(ResourceId),
+ Context;
+ 'true' ->
+ aggregate_resource(kz_doc:set_id(cb_context:doc(Context), ResourceId)),
+ _ = kapi_switch:publish_reload_gateways(),
+ _ = kapi_switch:publish_reload_acls(),
+ Context
+ end;
+maybe_aggregate_resource(Context, _AccountDb, _) ->
Context.
--spec maybe_remove_aggregate(cb_context:context(), kz_term:ne_binary(), kz_term:ne_binary()) -> cb_context:context().
-maybe_remove_aggregate(Context, _ResourceId, ?KZ_OFFNET_DB) -> Context;
-maybe_remove_aggregate(Context, ResourceId, _AccountDb) ->
- _ = cb_local_resources:maybe_remove_aggregate(ResourceId, Context),
+-spec maybe_remove_aggregate(cb_context:context(), kz_term:ne_binary(), kz_term:ne_binary(), crossbar_status()) -> cb_context:context().
+maybe_remove_aggregate(Context, _ResourceId, ?KZ_OFFNET_DB, _) -> Context;
+maybe_remove_aggregate(Context, ResourceId, _AccountDb, 'success') ->
+ _ = remove_aggregate(ResourceId),
+ Context;
+maybe_remove_aggregate(Context, _ResourceId, _AccountDb, _) ->
Context.
%%------------------------------------------------------------------------------
@@ -479,8 +477,16 @@ on_successful_validation(Id, Context) ->
-spec on_successful_local_validation(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-on_successful_local_validation(Id, Context) ->
- cb_local_resources:validate_request(Id, Context).
+on_successful_local_validation(ResourceId, Context) ->
+ case lists:any(fun is_registering_gateway/1
+ ,cb_context:req_value(Context, <<"gateways">>, [])
+ )
+ of
+ 'true' ->
+ check_if_peer(ResourceId, cb_context:store(Context, 'aggregate_resource', 'true'));
+ 'false' ->
+ check_if_peer(ResourceId, Context)
+ end.
-spec on_successful_job_validation('undefined', cb_context:context()) -> cb_context:context().
on_successful_job_validation('undefined', Context) ->
@@ -526,7 +532,7 @@ collection_process(Context, Successes) ->
case cb_context:resp_status(Context1) of
'success' ->
(cb_context:account_db(Context1) =/= ?KZ_OFFNET_DB)
- andalso cb_local_resources:maybe_aggregate_resources(Resources),
+ andalso maybe_aggregate_resources(Resources),
summary(Context1);
_Status -> 'ok'
end.
@@ -539,9 +545,238 @@ is_global_resource_request(Context) ->
is_global_resource_request(_ReqNouns, 'undefined') ->
lager:debug("request is for global resources"),
'true';
-is_global_resource_request([{<<"global_resources">>, _}|_], _AccountId) ->
- lager:debug("request is for global resources"),
- 'true';
is_global_resource_request(_ReqNouns, _AccountId) ->
lager:debug("request is for local resources for account ~s", [_AccountId]),
'false'.
+
+%%%=============================================================================
+%%% Local Resources functions
+%%%=============================================================================
+
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec is_registering_gateway(kz_json:object()) -> boolean().
+is_registering_gateway(Gateway) ->
+ kz_json:is_true(<<"register">>, Gateway)
+ andalso kz_json:is_true(<<"enabled">>, Gateway).
+
+-spec check_if_peer(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
+check_if_peer(ResourceId, Context) ->
+ case {kz_term:is_true(cb_context:req_value(Context, <<"peer">>))
+ ,kapps_config:get_is_true(?MOD_CONFIG_CAT, <<"allow_peers">>, 'false')
+ }
+ of
+ {'true', 'true'} ->
+ check_if_gateways_have_ip(ResourceId, Context);
+ {'true', 'false'} ->
+ C = cb_context:add_validation_error([<<"peer">>]
+ ,<<"forbidden">>
+ ,kz_json:from_list([{<<"message">>, <<"Peers are currently disabled, please contact the system admin">>}])
+ ,Context
+ ),
+ on_successful_validation(ResourceId, C);
+ {_, _} ->
+ on_successful_validation(ResourceId, Context)
+ end.
+
+-spec check_if_gateways_have_ip(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
+check_if_gateways_have_ip(ResourceId, Context) ->
+ Gateways = cb_context:req_value(Context, <<"gateways">>, []),
+ IPs = extract_gateway_ips(Gateways, 0, []),
+ SIPAuth = get_all_sip_auth_ips(),
+ ACLs = get_all_acl_ips(),
+ validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, Context, cb_context:resp_status(Context)).
+
+-spec validate_gateway_ips(gateway_ips(), sip_auth_ips(), acl_ips(), kz_term:api_binary(), cb_context:context(), crossbar_status()) -> cb_context:context().
+validate_gateway_ips([], _, _, ResourceId, Context, 'error') ->
+ on_successful_validation(ResourceId, Context);
+validate_gateway_ips([], _, _, ResourceId, Context, 'success') ->
+ on_successful_validation(ResourceId, cb_context:store(Context, 'aggregate_resource', 'true'));
+validate_gateway_ips([{Idx, 'undefined', 'undefined'}|IPs], SIPAuth, ACLs, ResourceId, Context, 'success') ->
+ C = cb_context:add_validation_error([<<"gateways">>, Idx, <<"server">>]
+ ,<<"required">>
+ ,kz_json:from_list([{<<"message">>, <<"Gateway server must be an IP when peering with the resource">>}
+ ,{<<"cause">>, Idx}
+ ])
+ ,Context
+ ),
+ validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, C, cb_context:resp_status(C));
+validate_gateway_ips([{Idx, 'undefined', ServerIP}|IPs], SIPAuth, ACLs, ResourceId, Context, 'success') ->
+ case kz_network_utils:is_ipv4(ServerIP) of
+ 'true' ->
+ case validate_ip(ServerIP, SIPAuth, ACLs, ResourceId) of
+ 'true' ->
+ validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, Context, cb_context:resp_status(Context));
+ 'false' ->
+ C = cb_context:add_validation_error([<<"gateways">>, Idx, <<"server">>]
+ ,<<"unique">>
+ ,kz_json:from_list([{<<"message">>, <<"Gateway server ip is already in use">>}
+ ,{<<"cause">>, Idx}
+ ])
+ ,Context
+ ),
+ validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, C, cb_context:resp_status(C))
+ end;
+ 'false' ->
+ validate_gateway_ips([{Idx, 'undefined', 'undefined'}|IPs], SIPAuth, ACLs, ResourceId, Context, cb_context:resp_status(Context))
+ end;
+validate_gateway_ips([{Idx, InboundIP, ServerIP}|IPs], SIPAuth, ACLs, ResourceId, Context, 'success') ->
+ case kz_network_utils:is_ipv4(InboundIP) of
+ 'true' ->
+ case validate_ip(InboundIP, SIPAuth, ACLs, ResourceId) of
+ 'true' ->
+ validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, Context, cb_context:resp_status(Context));
+ 'false' ->
+ C = cb_context:add_validation_error([<<"gateways">>, Idx, <<"inbound_ip">>]
+ ,<<"unique">>
+ ,kz_json:from_list([{<<"message">>, <<"Gateway inbound ip is already in use">>}
+ ,{<<"cause">>, Idx}
+ ])
+ ,Context
+ ),
+ validate_gateway_ips(IPs, SIPAuth, ACLs, ResourceId, C, cb_context:resp_status(C))
+ end;
+ 'false' ->
+ validate_gateway_ips([{Idx, 'undefined', ServerIP}|IPs], SIPAuth, ACLs, ResourceId, Context, cb_context:resp_status(Context))
+ end.
+
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec aggregate_resource(kz_json:object()) -> 'ok'.
+aggregate_resource(Resource) ->
+ lager:debug("adding resource to the sip auth aggregate"),
+ Doc = kz_doc:delete_revision(Resource),
+ 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'.
+
+-spec remove_aggregate(kz_term:ne_binary()) -> boolean().
+remove_aggregate(ResourceId) ->
+ case kz_datamgr:del_doc(?KZ_SIP_DB, ResourceId) of
+ {'ok', _JObj} ->
+ _ = kapi_switch:publish_reload_gateways(),
+ _ = kapi_switch:publish_reload_acls(),
+ 'true';
+ {'error', 'not_found'} -> 'false'
+ end.
+
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-type sip_auth_ip() :: {kz_term:ne_binary(), kz_term:ne_binary()}.
+-type sip_auth_ips() :: [sip_auth_ip()].
+
+-spec get_all_sip_auth_ips() -> sip_auth_ips().
+get_all_sip_auth_ips() ->
+ ViewOptions = [],
+ case kz_datamgr:get_results(?KZ_SIP_DB, <<"credentials/lookup_by_ip">>, ViewOptions) of
+ {'ok', JObjs} -> lists:foldr(fun get_sip_auth_ip/2, [], JObjs);
+ {'error', _} -> []
+ end.
+
+-spec get_sip_auth_ip(kz_json:object(), sip_auth_ips()) -> sip_auth_ips().
+get_sip_auth_ip(JObj, IPs) ->
+ [{kz_json:get_value(<<"key">>, JObj), kz_doc:id(JObj)} | IPs].
+
+-type acl_ips() :: kz_term:ne_binaries().
+-spec get_all_acl_ips() -> acl_ips().
+get_all_acl_ips() ->
+ Req = [{<<"Category">>, <<"ecallmgr">>}
+ ,{<<"Key">>, <<"acls">>}
+ ,{<<"Node">>, <<"all">>}
+ ,{<<"Default">>, kz_json:new()}
+ ,{<<"Msg-ID">>, kz_binary:rand_hex(16)}
+ | kz_api:default_headers(?APP_NAME, ?APP_VERSION)
+ ],
+ Resp = kz_amqp_worker:call(props:filter_undefined(Req)
+ ,fun kapi_sysconf:publish_get_req/1
+ ,fun kapi_sysconf:get_resp_v/1
+ ),
+ case Resp of
+ {'error', _} -> [];
+ {'ok', JObj} ->
+ extract_all_ips(kz_json:get_value(<<"Value">>, JObj, kz_json:new()))
+ end.
+
+-spec extract_all_ips(kz_json:object()) -> acl_ips().
+extract_all_ips(JObj) ->
+ kz_json:foldl(fun extract_ips_fold/3, [], JObj).
+
+-spec extract_ips_fold(kz_json:path(), kz_json:object(), acl_ips()) -> acl_ips().
+extract_ips_fold(_K, JObj, IPs) ->
+ case kz_json:get_value(<<"cidr">>, JObj) of
+ 'undefined' -> IPs;
+ CIDR ->
+ AuthorizingId = kz_json:get_value(<<"authorizing_id">>, JObj),
+ [{CIDR, AuthorizingId} | IPs]
+ end.
+
+-type gateway_ip() :: {non_neg_integer(), kz_term:api_binary(), kz_term:api_binary()}.
+-type gateway_ips() :: [gateway_ip()].
+-spec extract_gateway_ips(kz_json:objects(), non_neg_integer(), gateway_ips()) -> gateway_ips().
+extract_gateway_ips([], _, IPs) -> IPs;
+extract_gateway_ips([Gateway|Gateways], Idx, IPs) ->
+ IP = {Idx
+ ,kz_json:get_ne_value(<<"inbound_ip">>, Gateway)
+ ,kz_json:get_ne_value(<<"server">>, Gateway)
+ },
+ extract_gateway_ips(Gateways, Idx + 1, [IP|IPs]).
+
+-spec validate_ip(kz_term:api_binary(), sip_auth_ips(), acl_ips(), kz_term:api_binary()) -> boolean().
+validate_ip(IP, SIPAuth, ACLs, ResourceId) ->
+ lists:all(fun({CIDR, AuthId}) ->
+ AuthId =:= ResourceId
+ orelse not (kz_network_utils:verify_cidr(IP, CIDR))
+ end, ACLs)
+ andalso lists:all(fun({AuthIp, Id}) ->
+ IP =/= AuthIp
+ orelse ResourceId =:= Id
+ end, SIPAuth).
+
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec maybe_aggregate_resources(kz_json:objects()) -> 'ok'.
+maybe_aggregate_resources([]) -> 'ok';
+maybe_aggregate_resources([Resource|Resources]) ->
+ 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, [])
+ )
+ of
+ 'true' ->
+ aggregate_resource(Resource),
+ _ = kapi_switch:publish_reload_gateways(),
+ _ = kapi_switch:publish_reload_acls(),
+ maybe_aggregate_resources(Resources);
+ 'false' ->
+ _ = maybe_remove_aggregates([Resource]),
+ maybe_aggregate_resources(Resources)
+ end.
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
+-spec maybe_remove_aggregates(kz_json:objects()) -> '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.
diff --git a/applications/crossbar/src/modules/cb_search.erl b/applications/crossbar/src/modules/cb_search.erl
index ed410867090..7581f9db82e 100644
--- a/applications/crossbar/src/modules/cb_search.erl
+++ b/applications/crossbar/src/modules/cb_search.erl
@@ -1,6 +1,6 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
+%%% @doc Crossbar API for search.
%%% @author Luis Azedo
%%%
%%% This Source Code Form is subject to the terms of the Mozilla Public
diff --git a/applications/crossbar/src/modules/cb_security.erl b/applications/crossbar/src/modules/cb_security.erl
index 72521219ece..7765f43c8d8 100644
--- a/applications/crossbar/src/modules/cb_security.erl
+++ b/applications/crossbar/src/modules/cb_security.erl
@@ -25,7 +25,6 @@
-define(DEFAULT_AUTH_METHODS, [<<"cb_api_auth">>
,<<"cb_auth">>
,<<"cb_ip_auth">>
- ,<<"cb_ubiquiti_auth">>
,<<"cb_user_auth">>
]).
@@ -216,7 +215,7 @@ maybe_flush_config(Context) ->
case cb_context:fetch(Context, 'flush', 'false') of
'true' ->
kapps_account_config:flush(cb_context:account_id(Context), ?AUTH_CONFIG_CAT, <<"hierarchy_merge">>);
- 'false' -> Context
+ 'false' -> 'ok'
end.
%%------------------------------------------------------------------------------
diff --git a/applications/crossbar/src/modules/cb_shared_auth.erl b/applications/crossbar/src/modules/cb_shared_auth.erl
deleted file mode 100644
index 43aff83d70b..00000000000
--- a/applications/crossbar/src/modules/cb_shared_auth.erl
+++ /dev/null
@@ -1,358 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Shared token auth module, this module validates the token
-%%% against a trusted central token server. If the token
-%%% is valid then it will create a local token. It will
-%%% also import the account/user from the central server.
-%%%
-%%% Used to propagate accounts amongst independent services.
-%%%
-%%% This is a non-standard module:
-%%% * it authenticates and authorizes itself
-%%% * it has a completely unique role
-%%% * it operates without an account id (or account db)
-%%% * it 'proxies' crossbar auth requests to an external URL
-%%%
-%%%
-%%% @author Karl Anderson
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_shared_auth).
-
--export([init/0
- ,allowed_methods/0
- ,resource_exists/0
- ,authorize/1
- ,authenticate/1
- ,validate/1
- ,put/1
- ]).
-
--include("crossbar.hrl").
-
--define(AUTHORITATIVE_CROSSBAR,
- kapps_config:get_string(<<"crossbar.shared_auth">>, <<"authoritative_crossbar">>)).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> ok.
-init() ->
- lager:debug("shared auth started up, using ~s as authoritative crossbar", [?AUTHORITATIVE_CROSSBAR]),
- _ = crossbar_bindings:bind(<<"*.authenticate">>, ?MODULE, 'authenticate'),
- _ = crossbar_bindings:bind(<<"*.authorize">>, ?MODULE, 'authorize'),
- _ = crossbar_bindings:bind(<<"*.allowed_methods.shared_auth">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"*.resource_exists.shared_auth">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"*.validate.shared_auth">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"*.execute.put.shared_auth">>, ?MODULE, 'put'),
- ok.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
--spec allowed_methods() -> http_methods().
-allowed_methods() ->
- [?HTTP_PUT, ?HTTP_GET].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
-
--spec authorize(cb_context:context()) -> boolean().
-authorize(Context) ->
- authorize(Context, cb_context:req_nouns(Context)).
-
--spec authorize(cb_context:context(), req_nouns()) -> boolean().
-authorize(_, [{<<"shared_auth">>, _}]) ->'true';
-authorize(_, _) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
-
--spec authenticate(cb_context:context()) -> boolean().
-authenticate(Context) ->
- authenticate(cb_context:req_verb(Context), cb_context:req_nouns(Context)).
-
--spec authenticate(http_method(), req_nouns()) -> boolean().
-authenticate(?HTTP_PUT, [{<<"shared_auth">>, []}]) -> 'true';
-authenticate(_, _) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function runs for each side of the shared auth request
-%% The Requestor (PUT):
-%% IE: Create (PUT) a local auth token
-%% This request bypasses authentication, test the 'shared_token' against our
-%% authoritative server. Basically preform a normal 'get' to this module with the
-%% shared token as the auth token. If it succeeds we will send 'ourselves' the
-%% account id, otherwise the token was not known to the auth server.
-%%
-%% The Authority (GET):
-%% IE: Fetch (GET) the account and user of a shared token
-%% If we are validating a 'get' request then we are the authoritative box. This means
-%% another box is using their 'shared_tokens' as our auth token and it validated.
-%% So lets figure out what account they belong to and return the complete account
-%% definition so they can import it.
-%%
-%% If the authoritative box is running with noauth[n|z] then just send back a 401 to the
-%% requestor because we wont know what account to fetch
-%%
-%% Failure here returns 400 or 401
-%% @end
-%%------------------------------------------------------------------------------
-
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- validate_request(Context, cb_context:req_verb(Context), cb_context:auth_doc(Context)).
-
--spec validate_request(cb_context:context(), http_method(), kz_term:api_object()) -> cb_context:context().
-validate_request(Context, ?HTTP_PUT, _) ->
- _ = cb_context:put_reqid(Context),
- SharedToken = kz_json:get_value(<<"shared_token">>, cb_context:req_data(Context)),
- case authenticate_shared_token(SharedToken, ?AUTHORITATIVE_CROSSBAR) of
- {'ok', Payload} ->
- lager:debug("authoritative shared auth request succeeded"),
- RemoteData = kz_json:get_value(<<"data">>, kz_json:decode(Payload)),
- case import_missing_data(RemoteData) of
- 'true' ->
- cb_context:setters(Context, [{fun cb_context:set_resp_status/2, 'success'}
- ,{fun cb_context:set_doc/2, RemoteData}
- ,{fun cb_context:set_auth_token/2, SharedToken}
- ]);
- 'false' ->
- cb_context:add_system_error('datastore_fault', Context)
- end;
- {'forbidden', _} ->
- lager:debug("authoritative shared auth request forbidden"),
- cb_context:add_system_error('invalid_credentials', Context);
- {'error', _}=E ->
- lager:debug("authoritative shared auth request error: ~p", [E]),
- cb_context:add_system_error('datastore_unreachable', Context)
- end;
-
-validate_request(Context, ?HTTP_GET, 'undefined') ->
- _ = cb_context:put_reqid(Context),
- lager:debug("valid shared auth request received but there is no authorizing doc (noauth running?)"),
- cb_context:add_system_error('invalid_credentials', Context);
-
-validate_request(Context, ?HTTP_GET, JObj) ->
- _ = cb_context:put_reqid(Context),
- lager:debug("valid shared auth request received, creating response"),
- AccountId = kz_json:get_value(<<"account_id">>, JObj),
- UserId = kz_json:get_value(<<"owner_id">>, JObj),
- case kzd_accounts:fetch(AccountId) of
- {'ok', Account} ->
- Db = kz_util:format_account_id(AccountId, 'encoded'),
- case kz_datamgr:open_doc(Db, UserId) of
- {'ok', User} ->
- RespData = kz_json:from_list([{<<"account">>, Account}
- ,{<<"user">>, User}
- ]),
- cb_context:setters(Context, [{fun cb_context:set_resp_status/2, 'success'}
- ,{fun cb_context:set_resp_data/2, RespData}
- ]);
- {'error', R} ->
- lager:debug("failed to get user for response ~p", [R]),
- cb_context:add_system_error('datastore_fault', Context)
- end;
- {'error', R} ->
- lager:debug("failed to get account for response ~p", [R]),
- cb_context:add_system_error('datastore_fault', Context)
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec put(cb_context:context()) -> cb_context:context().
-put(Context) ->
- _ = cb_context:put_reqid(Context),
- create_local_token(Context).
-
-%%%=============================================================================
-%%% Internal functions
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc Attempt to create a token and save it to the token db
-%% @end
-%%------------------------------------------------------------------------------
--spec create_local_token(cb_context:context()) -> cb_context:context().
-create_local_token(Context) ->
- JObj = cb_context:doc(Context),
- Token = kz_json:from_list([{<<"account_id">>, kz_json:get_value([<<"account">>, <<"_id">>], JObj, <<>>)}
- ,{<<"owner_id">>, kz_json:get_value([<<"user">>, <<"_id">>], JObj, <<>>)}
- ,{<<"created">>, kz_time:now_s()}
- ,{<<"modified">>, kz_time:now_s()}
- ,{<<"method">>, kz_term:to_binary(?MODULE)}
- ,{<<"shared_token">>, cb_context:auth_token(Context)}
- ]),
- case kz_datamgr:save_doc(?KZ_TOKEN_DB, Token) of
- {'ok', Doc} ->
- AuthToken = kz_doc:id(Doc),
- lager:debug("created new local auth token ~s", [AuthToken]),
- Context1 = cb_context:set_doc(cb_context:set_auth_token(Context, AuthToken)
- ,Doc),
- crossbar_util:response(crossbar_util:response_auth(JObj), Context1);
- {'error', R} ->
- lager:debug("could not create new local auth token, ~p", [R]),
- cb_context:add_system_error('invalid_credentials', Context)
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Make a crossbar request to the authoritative server to authorize
-%% the shared token and get the account/user for the token
-%% @end
-%%------------------------------------------------------------------------------
--spec authenticate_shared_token(kz_term:api_binary(), nonempty_string()) ->
- {'ok', string() | binary()} |
- {'error', atom()} |
- {'forbidden', atom()}.
-authenticate_shared_token('undefined', _) ->
- {'forbidden', 'missing_shared_token'};
-authenticate_shared_token(SharedToken, XBarUrl) ->
- Url = lists:flatten(XBarUrl, "/shared_auth"),
- Headers = [{"Accept", "application/json"}
- ,{"X-Auth-Token", kz_term:to_list(SharedToken)}
- ],
- lager:debug("validating shared token ~s via ~s", [SharedToken, Url]),
- case kz_http:get(Url, Headers) of
- {'ok', 200, _, Resp} -> {'ok', Resp};
- {'ok', 401, _, _} -> {'forbidden', 'shared_token_rejected'};
- Resp -> {'error', Resp}
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc If a remote host authenticates the shared token it will return
-%% an account and user, ensure those exist locally.
-%% @end
-%%------------------------------------------------------------------------------
--spec import_missing_data(kz_json:object()) -> boolean().
-import_missing_data(RemoteData) ->
- import_missing_data(kz_json:get_json_value(<<"account">>, RemoteData)
- ,kz_json:get_json_value(<<"user">>, RemoteData)
- ).
-
-import_missing_data('undefined', _User) -> 'false';
-import_missing_data(_Account, 'undefined') -> 'false';
-import_missing_data(Account, User) ->
- AccountId = kz_doc:account_id(Account),
- import_missing_account(AccountId, Account)
- andalso import_missing_user(AccountId, kz_doc:id(User), User).
-
-%%------------------------------------------------------------------------------
-%% @doc If a remote host authenticates the shared token it will return
-%% an account and user, ensure the account exists (creating if not)
-%% @end
-%%------------------------------------------------------------------------------
--spec import_missing_account(kz_term:api_ne_binary(), kz_json:object()) -> boolean().
-import_missing_account('undefined', _Account) ->
- lager:debug("shared auth reply did not define an account id"),
- 'false';
-import_missing_account(AccountId, Account) ->
- %% check if the account database exists
- Db = kz_util:format_account_db(AccountId),
- case kz_datamgr:db_exists(Db) of
- %% if the account database exists make sure it has the account
- %% definition, because when couch is acting up it can skip this
- 'true' ->
- lager:debug("remote account db ~s already exists locally", [AccountId]),
- %% make sure the account definition is in the account, if not
- %% use the one we got from shared auth
- case kzd_accounts:fetch(AccountId) of
- {'error', 'not_found'} ->
- lager:debug("missing local account definition, creating from shared auth response"),
- Doc = kz_doc:delete_revision(Account),
- Event = <<"*.execute.post.accounts">>,
-
- Context = cb_context:setters(cb_context:new()
- ,[{fun cb_context:set_account_db/2, Db}
- ,{fun cb_context:set_doc/2, Doc}
- ]),
- PostContext = crossbar_bindings:fold(Event, [Context, AccountId]),
-
- case cb_context:resp_status(PostContext) of
- 'success' ->
- lager:debug("updated account definition"),
- 'true';
- _ ->
- lager:debug("could not update account definition"),
- 'false'
- end;
- {'ok', _} ->
- lager:debug("account definition exists locally"),
- 'true'
- end;
- 'false' ->
- lager:debug("remote account db ~s does not exist locally, creating", [AccountId]),
- Doc = kz_doc:delete_revision(Account),
- Event = <<"*.execute.put.accounts">>,
- Context1 = crossbar_bindings:fold(Event, [cb_context:set_doc(cb_context:new(), Doc)]),
- case cb_context:resp_status(Context1) of
- 'success' ->
- lager:debug("imported account"),
- 'true';
- _ ->
- lager:debug("could not import account"),
- 'false'
- end
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc If a remote host authenticates the shared token it will return
-%% an account and user, ensure the user exists locally (creating if not)
-%% @end
-%%------------------------------------------------------------------------------
--spec import_missing_user(kz_term:ne_binary(), kz_term:api_ne_binary(), kz_json:object()) -> boolean().
-import_missing_user(_, 'undefined', _) ->
- lager:debug("shared auth reply did not define an user id"),
- 'false';
-import_missing_user(AccountId, UserId, User) ->
- Db = kz_util:format_account_db(AccountId),
- case kz_datamgr:lookup_doc_rev(Db, UserId) of
- {'ok', _} ->
- lager:debug("remote user ~s already exists locally in account ~s", [UserId, AccountId]),
- 'true';
- _Else ->
- Doc = kz_doc:delete_revision(User),
- Event = <<"*.execute.put.users">>,
- Context = cb_context:setters(cb_context:new()
- ,[{fun cb_context:set_account_db/2, Db}
- ,{fun cb_context:set_doc/2, Doc}
- ]),
- PostContext = crossbar_bindings:fold(Event, [Context, AccountId]),
-
- case cb_context:resp_status(PostContext) of
- 'success' ->
- lager:debug("imported user ~s in account ~s", [UserId, AccountId]),
- 'true';
- _ ->
- lager:debug("could not import user ~s in account ~s", [UserId, AccountId]),
- 'false'
- end
- end.
diff --git a/applications/crossbar/src/modules/cb_simple_authz.erl b/applications/crossbar/src/modules/cb_simple_authz.erl
index 74a5a84f34d..0a978ac7338 100644
--- a/applications/crossbar/src/modules/cb_simple_authz.erl
+++ b/applications/crossbar/src/modules/cb_simple_authz.erl
@@ -25,11 +25,8 @@
-define(SERVER, ?MODULE).
-define(VIEW_SUMMARY, <<"accounts/listing_by_id">>).
-define(SYS_ADMIN_MODS, [<<"acls">>
- ,<<"global_provisioner_templates">>
- ,<<"global_resources">>
,<<"rates">>
,<<"sup">>
- ,<<"templates">>
]).
%% Endpoints performing their own auth
@@ -56,8 +53,6 @@ authorize(Context) ->
authorize(Context, Verb, [{?KZ_ACCOUNTS_DB, []}]) ->
cb_context:is_superduper_admin(Context)
orelse Verb =:= ?HTTP_PUT;
-authorize(_Context, ?HTTP_GET, [{<<"global_provisioner_templates">>,_}|_]) ->
- 'true';
authorize(Context, Verb, _Nouns) ->
AuthAccountId = cb_context:auth_account_id(Context),
IsSysAdmin = cb_context:is_superduper_admin(AuthAccountId),
diff --git a/applications/crossbar/src/modules/cb_skels.erl b/applications/crossbar/src/modules/cb_skels.erl
index a67373d150b..a4993265900 100644
--- a/applications/crossbar/src/modules/cb_skels.erl
+++ b/applications/crossbar/src/modules/cb_skels.erl
@@ -1,6 +1,6 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
+%%% @doc Crossnar API for skel.
%%% @author Karl Anderson
%%% @author James Aimonetti
%%%
diff --git a/applications/crossbar/src/modules/cb_system_configs.erl b/applications/crossbar/src/modules/cb_system_configs.erl
index d9df51f48b9..98f2eedc198 100644
--- a/applications/crossbar/src/modules/cb_system_configs.erl
+++ b/applications/crossbar/src/modules/cb_system_configs.erl
@@ -1,6 +1,6 @@
%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Listing of all expected v1 callbacks
+%%% @doc Crossbar API for system configs.
%%% @author Karl Anderson
%%% @author James Aimonetti
%%%
diff --git a/applications/crossbar/src/modules/cb_templates.erl b/applications/crossbar/src/modules/cb_templates.erl
deleted file mode 100644
index 3dd7fc6e561..00000000000
--- a/applications/crossbar/src/modules/cb_templates.erl
+++ /dev/null
@@ -1,269 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2010-2019, 2600Hz
-%%% @doc Handle client requests for template documents
-%%% @author Karl Anderson
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_templates).
-
--export([init/0
- ,allowed_methods/0, allowed_methods/1
- ,resource_exists/0, resource_exists/1
- ,validate/1, validate/2
- ,put/2
- ,delete/2
- ,account_created/1
- ]).
-
--include("crossbar.hrl").
-
--define(DB_PREFIX, "template/").
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> ok.
-init() ->
- _ = crossbar_bindings:bind(<<"*.allowed_methods.templates">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"*.resource_exists.templates">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"*.validate.templates">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"*.execute.post.templates">>, ?MODULE, 'post'),
- _ = crossbar_bindings:bind(<<"*.execute.delete.templates">>, ?MODULE, 'delete'),
- _ = crossbar_bindings:bind(<<"account.created">>, ?MODULE, 'account_created'),
- ok.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
--spec allowed_methods() -> http_methods().
-allowed_methods() -> [?HTTP_GET].
-
--spec allowed_methods(path_token()) -> http_methods().
-allowed_methods(_TemplateName) -> [?HTTP_PUT, ?HTTP_DELETE].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
--spec resource_exists(path_token()) -> 'true'.
-resource_exists(_) -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- validate_request(Context, cb_context:req_verb(Context), cb_context:req_nouns(Context)).
-
--spec validate(cb_context:context(), path_token()) -> cb_context:context().
-validate(Context, TemplateName) ->
- validate_request(Context, cb_context:req_verb(Context), cb_context:req_nouns(Context), TemplateName).
-
--spec validate_request(cb_context:context(), http_method(), req_nouns()) -> cb_context:context().
-validate_request(Context, ?HTTP_GET, [{<<"templates">>, _}]) ->
- summary(Context).
-
--spec validate_request(cb_context:context(), http_method(), req_nouns(), path_token()) ->
- cb_context:context().
-validate_request(Context, ?HTTP_PUT, [{<<"templates">>, _}], TemplateName) ->
- case cb_context:resp_status(load_template_db(TemplateName, Context)) of
- 'success' -> cb_context:add_system_error('datastore_conflict', Context);
- _Else -> crossbar_util:response(kz_json:new(), Context)
- end;
-validate_request(Context, ?HTTP_DELETE, [{<<"templates">>, _}], TemplateName) ->
- load_template_db(TemplateName, Context);
-validate_request(Context, _, _, TemplateName) ->
- load_template_db(TemplateName, Context).
-
--spec put(cb_context:context(), path_token()) -> cb_context:context().
-put(Context, TemplateName) ->
- create_template_db(TemplateName, Context).
-
--spec delete(cb_context:context(), kz_term:ne_binary()) -> cb_context:context().
-delete(Context, TemplateName) ->
- DbName = format_template_name(TemplateName, 'encoded'),
- case kz_datamgr:db_delete(DbName) of
- 'true' -> crossbar_util:response(kz_json:new(), Context);
- 'false' -> cb_context:add_system_error('datastore_fault', Context)
- end.
-
--spec account_created(cb_context:context()) -> ok.
-account_created(Context) ->
- JObj = cb_context:doc(Context),
- AccountId = cb_context:account_id(Context),
- AccountDb = cb_context:account_db(Context),
- import_template(kz_json:get_value(<<"template">>, JObj), AccountId, AccountDb).
-
-%%%=============================================================================
-%%% Internal functions
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc Attempt to load a summarized listing of all instances of this
-%% resource.
-%% @end
-%%------------------------------------------------------------------------------
--spec summary(cb_context:context()) -> cb_context:context().
-summary(Context) ->
- case kz_datamgr:db_info() of
- {'ok', Dbs} ->
- RespData = [format_template_name(Db, 'raw') || <>=Db <- Dbs],
- cb_context:set_resp_status(cb_context:set_resp_data(Context, RespData)
- ,'success'
- );
- _ -> cb_context:add_system_error('datastore_missing_view', Context)
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc This function will attempt to load the context with the db name of
-%% for this account
-%% @end
-%%------------------------------------------------------------------------------
--spec load_template_db(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-load_template_db([TemplateName], Context) ->
- load_template_db(TemplateName, Context);
-load_template_db(TemplateName, Context) ->
- DbName = format_template_name(TemplateName, 'encoded'),
- case kz_datamgr:db_exists(DbName) of
- 'false' ->
- lager:debug("check failed for template db ~s", [DbName]),
- cb_context:add_system_error('datastore_missing', Context);
- 'true' ->
- lager:debug("check succeeded for template db ~s", [DbName]),
- cb_context:setters(Context, [{fun cb_context:set_resp_status/2, 'success'}
- ,{fun cb_context:set_account_id/2, TemplateName}
- ,{fun cb_context:set_account_db/2, DbName}
- ])
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Format the template/db name into a raw, unencoded or encoded form.
-%% @end
-%%------------------------------------------------------------------------------
--spec format_template_name(kz_term:ne_binary(), 'encoded' | 'raw') -> kz_term:ne_binary().
-format_template_name(<<"template%2F", _/binary>> = TemplateName, 'encoded') ->
- TemplateName;
-format_template_name(<<"template/", TemplateName/binary>>, 'encoded') ->
- <<"template%2F", TemplateName/binary>>;
-format_template_name(TemplateName, 'encoded') ->
- <<"template%2F", TemplateName/binary>>;
-format_template_name(<<"template%2F", TemplateName/binary>>, 'raw') ->
- TemplateName;
-format_template_name(<<"template/", TemplateName/binary>>, 'raw') ->
- TemplateName;
-format_template_name(TemplateName, 'raw') ->
- TemplateName.
-
-%%------------------------------------------------------------------------------
-%% @doc Create a new template database and load it with views so it can be
-%% used as an 'account'
-%% @end
-%%------------------------------------------------------------------------------
--spec create_template_db(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-create_template_db(TemplateName, Context) ->
- TemplateDb = format_template_name(TemplateName, 'encoded'),
- case kz_datamgr:db_create(TemplateDb) of
- 'false' ->
- lager:debug("failed to create database: ~s", [TemplateDb]),
- cb_context:add_system_error('datastore_fault', Context);
- 'true' ->
- lager:debug("created DB for template ~s", [TemplateName]),
- kz_datamgr:revise_docs_from_folder(TemplateDb, 'kazoo_apps', "account", 'false'),
- _ = kz_datamgr:revise_doc_from_file(TemplateDb, 'kazoo_apps', <<"views/maintenance.json">>),
- cb_context:set_resp_status(Context, 'success')
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc If a valid template database is provided import the non-design
-%% documents into the account
-%% @end
-%%------------------------------------------------------------------------------
--spec import_template(kz_term:api_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> 'ok'.
-import_template('undefined', _, _) -> 'ok';
-import_template(TemplateName, AccountId, AccountDb) ->
- %%TODO: use couch replication...
- TemplateDb = format_template_name(TemplateName, 'encoded'),
- case kz_datamgr:all_docs(TemplateDb) of
- {'ok', Docs} ->
- Ids = [Id || Doc <- Docs,
- begin
- Id = kz_doc:id(Doc),
- not is_design_doc_id(Id)
- end
- ],
- import_template_docs(Ids, TemplateDb, AccountId, AccountDb);
- _ -> 'ok'
- end.
-
--spec is_design_doc_id(kz_term:ne_binary()) -> boolean().
-is_design_doc_id(<<"_design/", _/binary>>) -> 'false';
-is_design_doc_id(_) -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc Given a list of IDs in the template database, import them into the
-%% account database, correcting the pvt fields.
-%% @end
-%%------------------------------------------------------------------------------
--spec import_template_docs(kz_term:ne_binaries(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> 'ok'.
-import_template_docs([], _, _, _) -> 'ok';
-import_template_docs([Id|Ids], TemplateDb, AccountId, AccountDb) ->
- case kz_datamgr:open_doc(TemplateDb, Id) of
- {'error', _} -> import_template_docs(Ids, TemplateDb, AccountId, AccountDb);
- {'ok', JObj} ->
- import_template_doc(Id, TemplateDb, AccountId, AccountDb, JObj),
- import_template_docs(Ids, TemplateDb, AccountId, AccountDb)
- end.
-
--spec import_template_doc(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_json:object()) -> 'ok'.
-import_template_doc(Id, TemplateDb, AccountId, AccountDb, JObj) ->
- AttachmentNames = kz_doc:attachment_names(JObj),
- Updates = [{kz_doc:path_account_id(), AccountId}
- ,{kz_doc:path_account_db(), AccountDb}
- | [{Key, 'null'} || Key <- AttachmentNames]
- ],
-
- UpdateOptions = [{'update', Updates}
- ,{'create', kz_json:to_proplist(kz_json:flatten(JObj))}
- ,{'ensure_saved', 'true'}
- ],
- _ = kz_datamgr:update_doc(AccountDb, Id, UpdateOptions),
-
- import_template_attachments(AttachmentNames, JObj, TemplateDb, AccountDb, Id).
-
--spec import_template_attachments(kz_term:ne_binaries(), kz_json:object(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> 'ok'.
-import_template_attachments([], _, _, _, _) -> 'ok';
-import_template_attachments([Attachment|Attachments], JObj, TemplateDb, AccountDb, Id) ->
- import_template_attachment(Attachment, JObj, TemplateDb, AccountDb, Id),
- import_template_attachments(Attachments, JObj, TemplateDb, AccountDb, Id).
-
--spec import_template_attachment(kz_term:ne_binary(), kz_json:object(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> 'ok'.
-import_template_attachment(Attachment, JObj, TemplateDb, AccountDb, Id) ->
- {'ok', Bin} = kz_datamgr:fetch_attachment(TemplateDb, Id, Attachment),
- ContentType = kz_doc:attachment_content_type(JObj, Attachment),
- Opts = [{'content_type', ContentType}],
- _ = kz_datamgr:put_attachment(AccountDb, Id, Attachment, Bin, Opts),
- 'ok'.
diff --git a/applications/crossbar/src/modules/cb_ubiquiti_auth.erl b/applications/crossbar/src/modules/cb_ubiquiti_auth.erl
deleted file mode 100644
index 6966ce85c7b..00000000000
--- a/applications/crossbar/src/modules/cb_ubiquiti_auth.erl
+++ /dev/null
@@ -1,214 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Ubiquiti SSO auth module
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_ubiquiti_auth).
-
--export([init/0
- ,allowed_methods/0
- ,resource_exists/0
- ,authorize/1
- ,authenticate/1
- ,validate/1
- ,put/1
- ]).
-
--include("crossbar.hrl").
-
--define(U_CONFIG_CAT, <<"crossbar.ubiquiti">>).
-
--define(UBIQUITI_AUTH_TOKENS, kapps_config:get_integer(?U_CONFIG_CAT, <<"tokens_per_request">>, 35)).
--define(UBIQUITI_PROVIDER_ID, kapps_config:get_binary(?U_CONFIG_CAT, <<"sso_provider_id">>)).
-
--define(SSO_STAGING_URI, <<"https://sso-stage.ubnt.com/api/sso/v1/">>).
--define(SSO_PROD_URI, <<"https://sso.ubnt.com/api/sso/v1/">>).
-
--define(SSO_STAGING_ENV, <<"staging">>).
--define(SSO_PROD_ENV, <<"production">>).
--define(SSO_URL_KEY, <<"sso_url">>).
-
--define(SSO_PROVIDER, <<"ubiquiti">>).
-
--define(SSO_ENV, kapps_config:get_binary(?U_CONFIG_CAT, <<"sso_environment">>, ?SSO_STAGING_ENV)).
--define(SSO_URL, kapps_config:get_binary(?U_CONFIG_CAT, [?SSO_ENV, ?SSO_URL_KEY])).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> ok.
-init() ->
- _ProdURI = kapps_config:get_ne_binary(?U_CONFIG_CAT, [?SSO_PROD_ENV, ?SSO_URL_KEY], ?SSO_PROD_URI),
- _StagURI = kapps_config:get_ne_binary(?U_CONFIG_CAT, [?SSO_STAGING_ENV, ?SSO_URL_KEY], ?SSO_STAGING_URI),
-
- lager:debug("SSO Environment: ~s", [?SSO_ENV]),
- lager:debug("SSO URI: ~s", [?SSO_URL]),
-
- case ?UBIQUITI_PROVIDER_ID of
- 'undefined' -> lager:error("no provider account id for Ubiquiti has been defined");
- _ProviderId -> lager:debug("SSO Provider Account ID: ~s", [_ProviderId])
- end,
-
- _ = crossbar_bindings:bind(<<"*.authenticate">>, ?MODULE, 'authenticate'),
- _ = crossbar_bindings:bind(<<"*.authorize">>, ?MODULE, 'authorize'),
- _ = crossbar_bindings:bind(<<"*.allowed_methods.ubiquiti_auth">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"*.resource_exists.ubiquiti_auth">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"*.validate.ubiquiti_auth">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"*.execute.put.ubiquiti_auth">>, ?MODULE, 'put'),
- ok.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
--spec allowed_methods() -> http_methods().
-allowed_methods() -> [?HTTP_PUT].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec authorize(cb_context:context()) -> boolean().
-authorize(Context) ->
- authorize_nouns(cb_context:req_nouns(Context)).
-
-authorize_nouns([{<<"ubiquiti_auth">>, _}]) -> 'true';
-authorize_nouns(_) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec authenticate(cb_context:context()) -> boolean().
-authenticate(Context) ->
- authenticate_nouns(cb_context:req_nouns(Context)).
-
-authenticate_nouns([{<<"ubiquiti_auth">>, _}]) -> 'true';
-authenticate_nouns([{<<"ubiquiti_auth">>, [<<"recovery">>]}]) -> 'true';
-authenticate_nouns(_Nouns) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- Context1 = consume_tokens(Context),
- case cb_context:resp_status(Context1) of
- 'success' ->
- cb_context:validate_request_data(<<"ubiquiti_auth">>, Context, fun maybe_authenticate_user/1);
- _Status -> Context1
- end.
-
--spec put(cb_context:context()) -> cb_context:context().
-put(Context) ->
- crossbar_auth:create_auth_token(Context, ?MODULE).
-
-%%%=============================================================================
-%%% Internal functions
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec maybe_authenticate_user(cb_context:context()) -> cb_context:context().
-maybe_authenticate_user(Context) ->
- LoginURL = crossbar_util:get_path(?SSO_URL, <<"login">>),
-
- case kz_http:post(kz_term:to_list(LoginURL)
- ,[{"content-type","application/json"}]
- ,kz_json:encode(login_req(Context))
- )
- of
- {'ok', 200, RespHeaders, RespBody} ->
- lager:debug("successfully authenticated to '~s'", [LoginURL]),
- cb_context:setters(Context, [{fun cb_context:set_doc/2, auth_response(RespHeaders, RespBody)}
- ,{fun cb_context:set_resp_status/2, 'success'}
- ,{fun cb_context:store/3, 'auth_type', <<"sso_auth">>}
- ]);
- {'ok', _RespCode, _RespHeaders, _RespBody} ->
- lager:debug("recv non-200(~p) code from '~s': ~s", [_RespCode, LoginURL, _RespBody]),
- crossbar_util:response('error', <<"invalid credentials">>, 401, Context);
- {'error', _Error} ->
- lager:debug("failed to query '~s': ~p", [LoginURL, _Error]),
- crossbar_util:response('error', <<"failed to query Ubiquiti SSO service">>, 500, Context)
- end.
-
--spec login_req(cb_context:context()) -> kz_json:object().
-login_req(Context) ->
- Data = cb_context:req_data(Context),
- kz_json:set_value(<<"user">>
- ,kz_json:get_value(<<"username">>, Data)
- ,kz_json:delete_key(<<"username">>, Data)
- ).
-
--spec auth_response(kz_term:proplist(), binary()) -> kz_json:object().
-auth_response(_RespHeaders, RespBody) ->
- RespJObj = kz_json:decode(RespBody),
- UUID = kz_json:get_value(<<"uuid">>, RespJObj),
-
- maybe_add_account_information(UUID
- ,kz_json:from_list(
- [{<<"sso">>, kz_json:set_value(<<"provider">>, ?SSO_PROVIDER, RespJObj)}]
- )
- ).
-
--spec maybe_add_account_information(kz_term:api_binary(), kz_json:object()) -> kz_json:object().
-maybe_add_account_information('undefined', AuthResponse) ->
- AuthResponse;
-maybe_add_account_information(UUID, AuthResponse) ->
- Options = [{'key', [?SSO_PROVIDER, UUID]}],
- case kz_datamgr:get_results(?KZ_ACCOUNTS_DB, <<"accounts/listing_by_sso">>, Options) of
- {'ok', []} -> AuthResponse;
- {'ok', [AccountJObj]} ->
- AccountId = kz_json:get_value(<<"account_id">>, AccountJObj),
- lager:debug("found account as ~s", [AccountId]),
-
- kz_json:set_values([{<<"account_id">>, AccountId}
- ,{<<"is_reseller">>, kz_services_reseller:is_reseller(AccountId)}
- ,{<<"reseller_id">>, kz_services_reseller:get_id(AccountId)}
- ]
- ,AuthResponse
- );
- {'error', _E} ->
- lager:debug("failed to query accounts for uuid ~s: ~p", [UUID, _E]),
- AuthResponse
- end.
-
--spec consume_tokens(cb_context:context()) -> cb_context:context().
-consume_tokens(Context) ->
- case kz_buckets:consume_tokens_until(?APP_NAME
- ,cb_modules_util:bucket_name(Context)
- ,cb_modules_util:token_cost(Context, ?UBIQUITI_AUTH_TOKENS)
- )
- of
- 'true' -> cb_context:set_resp_status(Context, 'success');
- 'false' ->
- cb_context:add_system_error('too_many_requests', Context)
- end.
diff --git a/applications/crossbar/src/modules/cb_ubiquiti_util.erl b/applications/crossbar/src/modules/cb_ubiquiti_util.erl
deleted file mode 100644
index a904c6b3803..00000000000
--- a/applications/crossbar/src/modules/cb_ubiquiti_util.erl
+++ /dev/null
@@ -1,84 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2014-2019, 2600Hz
-%%% @doc Ubiquiti SSO Utilities
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_ubiquiti_util).
-
--export([create_api_token/1, create_api_token/2
- ,make_api_token/4
- ,split_api_token/1
- ]).
-
--ifdef(TEST).
--export([auth_hash/4
- ,encode_timestamp/1
- ]).
--endif.
-
--include("crossbar.hrl").
--define(U_CONFIG_CAT, <<"crossbar.ubiquiti">>).
-
--define(VERSION, <<"1">>).
--define(EXPIRES, kapps_config:get_integer(?U_CONFIG_CAT, <<"api_token_expires_s">>, 1800)).
--define(SECRET, kapps_config:get_ne_binary(?U_CONFIG_CAT, <<"api_secret">>)).
--define(SALT_LENGTH, kapps_config:get_integer(?U_CONFIG_CAT, <<"salt_length">>, 20)).
-
--spec create_api_token(kz_term:ne_binary()) -> kz_term:ne_binary().
-create_api_token(ProviderId) ->
- create_api_token(ProviderId, ?SECRET).
-
--spec create_api_token(kz_term:ne_binary(), kz_term:ne_binary()) -> kz_term:ne_binary().
-create_api_token(ProviderId, <<_/binary>> = Secret) ->
- Salt = kz_binary:rand_hex(?SALT_LENGTH),
- ExpireTime = kz_time:current_unix_tstamp() + ?EXPIRES,
- make_api_token(ProviderId, ExpireTime, Salt, Secret);
-create_api_token(_ProviderId, 'undefined') ->
- throw({'error', 'no_api_secret'}).
-
--spec make_api_token(kz_term:ne_binary(), integer(), kz_term:ne_binary(), kz_term:ne_binary()) -> kz_term:ne_binary().
-make_api_token(ProviderId, Timestamp, Salt, Secret) ->
- TimestampHex = encode_timestamp(Timestamp),
- kz_binary:join([?VERSION % Version
- ,Salt
- ,TimestampHex
- ,auth_hash(ProviderId, TimestampHex, Salt, Secret)
- ]
- ,<<":">>
- ).
-
--spec encode_timestamp(integer()) -> kz_term:ne_binary().
-encode_timestamp(Timestamp) when is_integer(Timestamp) ->
- kz_term:to_lower_binary(integer_to_list(Timestamp, 16)).
-
--spec decode_timestamp(kz_term:ne_binary()) -> integer().
-decode_timestamp(<<_/binary>> = TimestampHex) ->
- list_to_integer(binary_to_list(TimestampHex), 16).
-
--spec auth_hash(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> kz_term:ne_binary().
-auth_hash(ProviderId, TimestampHex, Salt, Secret) ->
- Auth = kz_term:to_lower_binary(
- kz_binary:hexencode(
- crypto:hash('sha', [Salt, Secret])
- )
- ),
-
- PreHash = [ProviderId
- ,TimestampHex
- ,Auth
- ],
-
- Hash = crypto:hash('sha', PreHash),
-
- kz_binary:hexencode(Hash).
-
--spec split_api_token(kz_term:ne_binary()) -> {kz_term:ne_binary(), integer(), kz_term:ne_binary()}.
-split_api_token(Token) ->
- [?VERSION, Salt, TimestampHex, Auth] = binary:split(kz_term:to_lower_binary(Token), <<":">>, ['global']),
- {Salt, decode_timestamp(TimestampHex), Auth}.
diff --git a/applications/crossbar/src/modules_v2/cb_users_v2.erl b/applications/crossbar/src/modules/cb_users.erl
similarity index 96%
rename from applications/crossbar/src/modules_v2/cb_users_v2.erl
rename to applications/crossbar/src/modules/cb_users.erl
index 012844c5d4a..8507c47065d 100644
--- a/applications/crossbar/src/modules_v2/cb_users_v2.erl
+++ b/applications/crossbar/src/modules/cb_users.erl
@@ -14,11 +14,7 @@
%%%
%%% @end
%%%-----------------------------------------------------------------------------
--module(cb_users_v2).
-
--export([create_user/1
- ,user_devices/1
- ]).
+-module(cb_users).
-export([init/0
,allowed_methods/0, allowed_methods/1, allowed_methods/2
@@ -49,28 +45,23 @@
%%% API
%%%=============================================================================
-%% SUPPORT FOR THE DEPRECIATED CB_SIGNUPS...
--spec create_user(cb_context:context()) -> cb_context:context().
-create_user(Context) ->
- Context1 = validate_request('undefined', cb_context:set_req_verb(Context, ?HTTP_PUT)),
- case cb_context:resp_status(Context1) of
- 'success' -> put(Context1);
- _Status -> Context1
- end.
-
+%%------------------------------------------------------------------------------
+%% @doc
+%% @end
+%%------------------------------------------------------------------------------
-spec init() -> 'ok'.
init() ->
- _ = crossbar_bindings:bind(<<"v2_resource.allowed_methods.users">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"v2_resource.content_types_provided.users">>, ?MODULE, 'content_types_provided'),
- _ = crossbar_bindings:bind(<<"v2_resource.resource_exists.users">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"v2_resource.authenticate.users">>, ?MODULE, 'authenticate'),
- _ = crossbar_bindings:bind(<<"v2_resource.authorize.users">>, ?MODULE, 'authorize'),
- _ = crossbar_bindings:bind(<<"v2_resource.validate_resource.users">>, ?MODULE, 'validate_resource'),
- _ = crossbar_bindings:bind(<<"v2_resource.validate.users">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"v2_resource.execute.put.users">>, ?MODULE, 'put'),
- _ = crossbar_bindings:bind(<<"v2_resource.execute.post.users">>, ?MODULE, 'post'),
- _ = crossbar_bindings:bind(<<"v2_resource.execute.delete.users">>, ?MODULE, 'delete'),
- _ = crossbar_bindings:bind(<<"v2_resource.execute.patch.users">>, ?MODULE, 'patch'),
+ _ = crossbar_bindings:bind(<<"*.allowed_methods.users">>, ?MODULE, 'allowed_methods'),
+ _ = crossbar_bindings:bind(<<"*.content_types_provided.users">>, ?MODULE, 'content_types_provided'),
+ _ = crossbar_bindings:bind(<<"*.resource_exists.users">>, ?MODULE, 'resource_exists'),
+ _ = crossbar_bindings:bind(<<"*.authenticate.users">>, ?MODULE, 'authenticate'),
+ _ = crossbar_bindings:bind(<<"*.authorize.users">>, ?MODULE, 'authorize'),
+ _ = crossbar_bindings:bind(<<"*.validate_resource.users">>, ?MODULE, 'validate_resource'),
+ _ = crossbar_bindings:bind(<<"*.validate.users">>, ?MODULE, 'validate'),
+ _ = crossbar_bindings:bind(<<"*.execute.put.users">>, ?MODULE, 'put'),
+ _ = crossbar_bindings:bind(<<"*.execute.post.users">>, ?MODULE, 'post'),
+ _ = crossbar_bindings:bind(<<"*.execute.delete.users">>, ?MODULE, 'delete'),
+ _ = crossbar_bindings:bind(<<"*.execute.patch.users">>, ?MODULE, 'patch'),
'ok'.
%%------------------------------------------------------------------------------
diff --git a/applications/crossbar/src/modules_v1/cb_devices_v1.erl b/applications/crossbar/src/modules_v1/cb_devices_v1.erl
deleted file mode 100644
index 241114f0904..00000000000
--- a/applications/crossbar/src/modules_v1/cb_devices_v1.erl
+++ /dev/null
@@ -1,660 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Devices module
-%%% Handle client requests for device documents
-%%%
-%%%
-%%% @author Karl Anderson
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_devices_v1).
-
--export([init/0
- ,allowed_methods/0, allowed_methods/1, allowed_methods/2
- ,resource_exists/0, resource_exists/1, resource_exists/2
- ,authenticate/1
- ,authorize/1
- ,validate/1, validate/2, validate/3
- ,put/1, put/2
- ,post/2, post/3
- ,delete/2
- ,lookup_regs/1
- ]).
-
--include("crossbar.hrl").
-
--define(STATUS_PATH_TOKEN, <<"status">>).
--define(CHECK_SYNC_PATH_TOKEN, <<"sync">>).
-
--define(MOD_CONFIG_CAT, <<(?CONFIG_CAT)/binary, ".devices">>).
-
--define(CB_LIST, <<"devices/crossbar_listing">>).
--define(OWNER_LIST, <<"devices/listing_by_owner">>).
--define(CB_LIST_MAC, <<"devices/listing_by_macaddress">>).
-
--define(KEY_MAC_ADDRESS, <<"mac_address">>).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> 'ok'.
-init() ->
- _ = crossbar_bindings:bind(<<"v1_resource.allowed_methods.devices">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"v1_resource.resource_exists.devices">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"v1_resource.authenticate">>, ?MODULE, 'authenticate'),
- _ = crossbar_bindings:bind(<<"v1_resource.authorize">>, ?MODULE, 'authorize'),
- _ = crossbar_bindings:bind(<<"v1_resource.validate.devices">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.put.devices">>, ?MODULE, 'put'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.post.devices">>, ?MODULE, 'post'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.delete.devices">>, ?MODULE, 'delete'),
- 'ok'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec allowed_methods() -> http_methods().
-allowed_methods() ->
- [?HTTP_GET, ?HTTP_PUT].
-
--spec allowed_methods(path_token()) -> http_methods().
-allowed_methods(?STATUS_PATH_TOKEN) ->
- [?HTTP_GET];
-allowed_methods(_) ->
- [?HTTP_GET, ?HTTP_POST, ?HTTP_PUT, ?HTTP_DELETE].
-
--spec allowed_methods(path_token(), path_token()) -> http_methods().
-allowed_methods(_DeviceId, ?CHECK_SYNC_PATH_TOKEN) ->
- [?HTTP_POST].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
--spec resource_exists(path_token()) -> 'true'.
-resource_exists(_) -> 'true'.
-
--spec resource_exists(path_token(), path_token()) -> 'true'.
-resource_exists(_DeviceId, ?CHECK_SYNC_PATH_TOKEN) -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec authenticate(cb_context:context()) -> 'true'.
-authenticate(Context) ->
- authenticate(cb_context:req_nouns(Context), cb_context:req_verb(Context)).
-authenticate(?DEVICES_QCALL_NOUNS(_DeviceId, _Number), ?HTTP_GET) ->
- lager:debug("authenticating request"),
- 'true';
-authenticate(_Nouns, _Verb) -> 'false'.
-
--spec authorize(cb_context:context()) -> 'true'.
-authorize(Context) ->
- authorize(cb_context:req_nouns(Context), cb_context:req_verb(Context)).
-authorize(?DEVICES_QCALL_NOUNS(_DeviceId, _Number), ?HTTP_GET) ->
- lager:debug("authorizing request"),
- 'true';
-authorize(_Nouns, _Verb) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- validate_devices(Context, cb_context:req_verb(Context)).
-
-validate_devices(Context, ?HTTP_GET) ->
- load_device_summary(Context);
-validate_devices(Context, ?HTTP_PUT) ->
- validate_request('undefined', Context).
-
--spec validate(cb_context:context(), path_token()) -> cb_context:context().
-validate(Context, ?STATUS_PATH_TOKEN) ->
- validate_device(Context, ?STATUS_PATH_TOKEN, cb_context:req_verb(Context));
-validate(Context, DeviceId) ->
- validate_device(Context, DeviceId, cb_context:req_verb(Context)).
-
--spec validate(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-validate(Context, DeviceId, ?CHECK_SYNC_PATH_TOKEN) ->
- load_device(DeviceId, Context).
-
-validate_device(Context, ?STATUS_PATH_TOKEN, ?HTTP_GET) ->
- load_device_status(Context);
-validate_device(Context, DeviceId, ?HTTP_GET) ->
- load_device(DeviceId, Context);
-validate_device(Context, DeviceId, ?HTTP_POST) ->
- validate_request(DeviceId, Context);
-validate_device(Context, DeviceId, ?HTTP_PUT) ->
- validate_action(Context, DeviceId, cb_context:req_value(Context, <<"action">>));
-validate_device(Context, DeviceId, ?HTTP_DELETE) ->
- load_device(DeviceId, Context).
-
--spec post(cb_context:context(), path_token()) -> cb_context:context().
-post(Context, DeviceId) ->
- case changed_mac_address(Context) of
- 'true' ->
- Context1 = cb_modules_util:take_sync_field(Context),
- Context2 = crossbar_doc:save(Context1),
- case cb_context:resp_status(Context2) of
- 'success' ->
- _ = kz_process:spawn(fun crossbar_util:flush_registration/1, [Context2]),
- _ = crossbar_util:maybe_refresh_fs_xml('device', Context2),
- _ = maybe_aggregate_device(DeviceId, Context2),
- _ = kz_process:spawn(fun update_device_provisioning/1, [Context2]),
- Context2;
- _ ->
- Context2
- end;
- 'false' ->
- error_used_mac_address(Context)
- end.
-
--spec update_device_provisioning(cb_context:context()) -> 'ok'.
-update_device_provisioning(Context) ->
- update_device_provisioning(Context, cb_context:resp_status(Context)).
-
--spec update_device_provisioning(cb_context:context(), crossbar_status()) -> 'ok'.
-update_device_provisioning(Context, 'success') ->
- _ = provisioner_util:provision_device(cb_context:doc(Context)
- ,cb_context:fetch(Context, 'db_doc')
- ,#{'req_verb' => cb_context:req_verb(Context)
- ,'auth_token' => cb_context:auth_token(Context)
- }
- ),
- sync_sip_data(Context);
-update_device_provisioning(_Context, _Status) -> 'ok'.
-
--spec sync_sip_data(cb_context:context()) -> 'ok'.
-sync_sip_data(Context) ->
- NewDoc = cb_context:doc(Context),
- OldDoc = cb_context:fetch(Context, 'db_doc'),
- AccountId = cb_context:account_id(Context),
-
- case cb_context:fetch(Context, 'sync') of
- 'false' -> 'ok';
- 'true' -> provisioner_util:sync_device(AccountId, OldDoc, NewDoc);
- 'force' -> provisioner_util:force_sync_device(AccountId, NewDoc)
- end.
-
--spec post(cb_context:context(), path_token(), path_token()) ->
- cb_context:context().
-post(Context, DeviceId, ?CHECK_SYNC_PATH_TOKEN) ->
- lager:debug("publishing check_sync for ~s", [DeviceId]),
- Context1 = cb_context:store(Context, 'sync', 'force'),
- sync_sip_data(Context1),
- crossbar_util:response_202(<<"sync request sent">>, Context).
-
--spec put(cb_context:context()) -> cb_context:context().
-put(Context) ->
- Context1 = crossbar_doc:save(Context),
- _ = maybe_aggregate_device('undefined', Context1),
- _ = kz_process:spawn(fun update_device_provisioning/1, [Context1]),
- Context1.
-
--spec put(cb_context:context(), path_token()) -> cb_context:context().
-put(Context, DeviceId) ->
- put_action(Context, DeviceId, cb_context:req_value(Context, <<"action">>)).
-
--spec delete(cb_context:context(), path_token()) -> cb_context:context().
-delete(Context, DeviceId) ->
- Context1 = crossbar_doc:delete(Context),
- case cb_context:resp_status(Context) of
- 'success' ->
- _ = crossbar_util:flush_registration(Context1),
- _ = crossbar_util:refresh_fs_xml(Context1),
- _ = kz_process:spawn(fun maybe_delete_provision/1, [Context1]),
- _ = maybe_remove_aggregate(DeviceId, Context1),
- Context1;
- _ ->
- Context1
- end.
-
--spec maybe_delete_provision(cb_context:context()) -> 'ok'.
-maybe_delete_provision(Context) ->
- maybe_delete_provision(Context, cb_context:resp_status(Context)).
-
--spec maybe_delete_provision(cb_context:context(), crossbar_status()) -> 'ok'.
-maybe_delete_provision(Context, 'success') ->
- DeviceDoc = cb_context:doc(Context),
- AuthToken = cb_context:auth_token(Context),
- _ = provisioner_util:delete_provision(DeviceDoc, AuthToken),
- 'ok';
-maybe_delete_provision(_Context, _Status) -> 'ok'.
-
-%%%=============================================================================
-%%% Internal functions
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc Attempt to load list of accounts, each summarized. Or a specific
-%% account summary.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec load_device_summary(cb_context:context()) ->
- cb_context:context().
-load_device_summary(Context) ->
- load_device_summary(Context, cb_context:req_nouns(Context)).
-
--spec load_device_summary(cb_context:context(), req_nouns()) ->
- cb_context:context().
-load_device_summary(Context, [{<<"devices">>, []}
- ,{<<"users">>, [UserId]}
- |_]
- ) ->
- load_users_device_summary(Context, UserId);
-load_device_summary(Context, _ReqNouns) ->
- crossbar_doc:load_view(?CB_LIST, [], Context, fun normalize_view_results/2).
-
--spec load_users_device_summary(cb_context:context(), kz_term:ne_binary()) ->
- cb_context:context().
-load_users_device_summary(Context, UserId) ->
- crossbar_doc:load_view(?OWNER_LIST
- ,[{'key', UserId}]
- ,Context
- ,fun normalize_view_results/2
- ).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec validate_request(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-validate_request('undefined', Context) ->
- check_mac_address('undefined', Context);
-validate_request(DeviceId, Context) ->
- prepare_outbound_flags(DeviceId, Context).
-
-%%------------------------------------------------------------------------------
-%% @doc Validate payloads for actions on a device.
-%% @end
-%%------------------------------------------------------------------------------
--spec validate_action(cb_context:context(), kz_term:ne_binary(), kz_term:api_binary()) ->
- cb_context:context().
-validate_action(Context, DeviceId, <<"notify">>) ->
- Context1 = cb_context:validate_request_data(<<"devices_notify">>, Context),
- case cb_context:resp_status(Context1) of
- 'success' -> load_device(DeviceId, Context);
- _ -> Context1
- end;
-validate_action(Context, _, 'undefined') ->
- crossbar_util:response_400(<<"action required">>, kz_json:new(), Context);
-validate_action(Context, _, _) ->
- crossbar_util:response_400(<<"invalid action">>, kz_json:new(), Context).
-
--spec changed_mac_address(cb_context:context()) -> boolean().
-changed_mac_address(Context) ->
- NewAddress = cb_context:req_value(Context, ?KEY_MAC_ADDRESS),
- OldAddress = kz_json:get_ne_value(?KEY_MAC_ADDRESS, cb_context:fetch(Context, 'db_doc')),
- NewAddress =:= OldAddress
- orelse unique_mac_address(NewAddress, Context).
-
--spec check_mac_address(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-check_mac_address(DeviceId, Context) ->
- MacAddress = cb_context:req_value(Context, ?KEY_MAC_ADDRESS),
- case unique_mac_address(MacAddress, Context) of
- 'true' ->
- prepare_outbound_flags(DeviceId, Context);
- 'false' ->
- error_used_mac_address(Context)
- end.
-
--spec unique_mac_address(kz_term:api_binary(), cb_context:context()) -> boolean().
-unique_mac_address('undefined', _Context) -> 'true';
-unique_mac_address(MacAddress, Context) ->
- DbName = cb_context:account_db(Context),
- not lists:member(MacAddress, get_mac_addresses(DbName))
- andalso not provisioner_util:is_mac_address_in_use(MacAddress, cb_context:auth_token(Context)).
-
--spec error_used_mac_address(cb_context:context()) -> cb_context:context().
-error_used_mac_address(Context) ->
- MacAddress = cb_context:req_value(Context, ?KEY_MAC_ADDRESS),
- cb_context:add_validation_error(?KEY_MAC_ADDRESS
- ,<<"unique">>
- ,kz_json:from_list(
- [{<<"message">>, <<"Mac address already in use">>}
- ,{<<"cause">>, MacAddress}
- ])
- ,Context
- ).
-
--spec get_mac_addresses(kz_term:ne_binary()) -> kz_term:ne_binaries().
-get_mac_addresses(DbName) ->
- case kz_datamgr:get_all_results(DbName, ?CB_LIST_MAC) of
- {'ok', AdJObj} -> kz_datamgr:get_result_keys(AdJObj);
- _ -> []
- end.
-
--spec prepare_outbound_flags(kz_term:api_binary(), cb_context:context()) ->
- cb_context:context().
-prepare_outbound_flags(DeviceId, Context) ->
- JObj =
- case cb_context:req_value(Context, <<"outbound_flags">>) of
- 'undefined' -> cb_context:req_data(Context);
- [] -> cb_context:req_data(Context);
- Flags when is_list(Flags) ->
- OutboundFlags = [kz_binary:strip(Flag) || Flag <- Flags],
- kz_json:set_value(<<"outbound_flags">>, OutboundFlags, cb_context:req_data(Context));
- _Else ->
- kz_json:set_value(<<"outbound_flags">>, [], cb_context:req_data(Context))
- end,
- prepare_device_realm(DeviceId, cb_context:set_req_data(Context, JObj)).
-
--spec prepare_device_realm(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-prepare_device_realm(DeviceId, Context) ->
- AccountRealm = kzd_accounts:fetch_realm(cb_context:account_id(Context)),
- Realm = cb_context:req_value(Context, [<<"sip">>, <<"realm">>], AccountRealm),
- case AccountRealm =:= Realm of
- 'true' ->
- JObj = kz_json:delete_key([<<"sip">>, <<"realm">>], cb_context:req_data(Context)),
- validate_device_creds(Realm, DeviceId, cb_context:set_req_data(Context, JObj));
- 'false' ->
- validate_device_creds(Realm, DeviceId, cb_context:store(Context, 'aggregate_device', 'true'))
- end.
-
--spec validate_device_creds(kz_term:ne_binary(), kz_term:api_binary(), cb_context:context()) ->
- cb_context:context().
-validate_device_creds(Realm, DeviceId, Context) ->
- case cb_context:req_value(Context, [<<"sip">>, <<"method">>], <<"password">>) of
- <<"password">> -> validate_device_password(Realm, DeviceId, Context);
- <<"ip">> ->
- IP = cb_context:req_value(Context, [<<"sip">>, <<"ip">>]),
- validate_device_ip(IP, DeviceId, Context);
- Else ->
- C = cb_context:add_validation_error([<<"sip">>, <<"method">>]
- ,<<"enum">>
- ,kz_json:from_list([{<<"message">>, <<"SIP authentication method is invalid">>}
- ,{<<"target">>, [<<"password">>, <<"ip">>]}
- ,{<<"cause">>, Else}
- ])
- ,Context
- ),
- check_emergency_caller_id(DeviceId, C)
- end.
-
--spec validate_device_password(kz_term:ne_binary(), kz_term:api_binary(), cb_context:context()) ->
- cb_context:context().
-validate_device_password(Realm, DeviceId, Context) ->
- Username = cb_context:req_value(Context, [<<"sip">>, <<"username">>]),
- case is_sip_creds_unique(cb_context:account_db(Context), Realm, Username, DeviceId) of
- 'true' -> check_emergency_caller_id(DeviceId, Context);
- 'false' ->
- C = cb_context:add_validation_error([<<"sip">>, <<"username">>]
- ,<<"unique">>
- ,kz_json:from_list([{<<"message">>, <<"SIP credentials already in use">>}
- ,{<<"cause">>, Username}
- ])
- ,Context
- ),
- check_emergency_caller_id(DeviceId, C)
- end.
-
--spec validate_device_ip(kz_term:ne_binary(), kz_term:api_binary(), cb_context:context()) ->
- cb_context:context().
-validate_device_ip(IP, DeviceId, Context) ->
- case kz_network_utils:is_ipv4(IP) of
- 'true' -> validate_device_ip_unique(IP, DeviceId, Context);
- 'false' ->
- C = cb_context:add_validation_error([<<"sip">>, <<"ip">>]
- ,<<"type">>
- ,kz_json:from_list([{<<"message">>, <<"Must be a valid IPv4 RFC 791">>}
- ,{<<"cause">>, IP}
- ])
- ,Context
- ),
- check_emergency_caller_id(DeviceId, C)
- end.
-
--spec validate_device_ip_unique(kz_term:ne_binary(), kz_term:api_binary(), cb_context:context()) ->
- cb_context:context().
-validate_device_ip_unique(IP, DeviceId, Context) ->
- case cb_devices_utils:is_ip_unique(IP, DeviceId) of
- 'true' ->
- check_emergency_caller_id(DeviceId, cb_context:store(Context, 'aggregate_device', 'true'));
- 'false' ->
- C = cb_context:add_validation_error([<<"sip">>, <<"ip">>]
- ,<<"unique">>
- ,kz_json:from_list([{<<"message">>, <<"SIP IP already in use">>}
- ,{<<"cause">>, IP}
- ])
- ,Context
- ),
- check_emergency_caller_id(DeviceId, C)
- end.
-
--spec check_emergency_caller_id(kz_term:api_binary(), cb_context:context()) ->
- cb_context:context().
-check_emergency_caller_id(DeviceId, Context) ->
- Context1 = crossbar_util:format_emergency_caller_id_number(Context),
- check_device_schema(DeviceId, Context1).
-
--spec check_device_schema(kz_term:api_binary(), cb_context:context()) ->
- cb_context:context().
-check_device_schema(DeviceId, Context) ->
- OnSuccess = fun(C) -> on_successful_validation(DeviceId, C) end,
- cb_context:validate_request_data(<<"devices">>, Context, OnSuccess).
-
--spec on_successful_validation(kz_term:api_binary(), cb_context:context()) ->
- cb_context:context().
-on_successful_validation('undefined', Context) ->
- Props = [{<<"pvt_type">>, <<"device">>}],
- cb_context:set_doc(Context, kz_json:set_values(Props, cb_context:doc(Context)));
-on_successful_validation(DeviceId, Context) ->
- crossbar_doc:load_merge(DeviceId, Context, ?TYPE_CHECK_OPTION(kzd_devices:type())).
-
-%%------------------------------------------------------------------------------
-%% @doc Load a device document from the database.
-%% @end
-%%------------------------------------------------------------------------------
--spec load_device(kz_term:ne_binary(), cb_context:context()) -> cb_context:context().
-load_device(DeviceId, Context) ->
- crossbar_doc:load(DeviceId, Context, ?TYPE_CHECK_OPTION(kzd_devices:type())).
-
-%%------------------------------------------------------------------------------
-%% @doc Retrieve the status of the devices linked to the account
-%% Reads registered devices in registrations, then map to devices of the account
-%% @end
-%%------------------------------------------------------------------------------
--spec load_device_status(cb_context:context()) -> cb_context:context().
-load_device_status(Context) ->
- AccountRealm = kzd_accounts:fetch_realm(cb_context:account_id(Context)),
- RegStatuses = lookup_regs(AccountRealm),
- lager:debug("reg statuses: ~p", [RegStatuses]),
- crossbar_util:response(RegStatuses, Context).
-
-%%------------------------------------------------------------------------------
-%% @doc Normalizes the results of a view.
-%% @end
-%%------------------------------------------------------------------------------
--spec normalize_view_results(kz_json:object(), kz_json:objects()) ->
- kz_json:objects().
-normalize_view_results(JObj, Acc) ->
- [kz_json:get_value(<<"value">>, JObj)|Acc].
-
-%%------------------------------------------------------------------------------
-%% @doc Returns the complete list of registrations in a the first registrar
-%% to respond for a given account realm. This is not 100% accurate
-%% as an endpoint might be stored in another registrar, but it is
-%% accurate enough for the status icons.
-%% @end
-%%------------------------------------------------------------------------------
--spec lookup_regs(kz_term:ne_binary()) -> kz_json:objects().
-lookup_regs(AccountRealm) ->
- Req = [{<<"Realm">>, AccountRealm}
- ,{<<"Fields">>, [<<"Authorizing-ID">>]}
- | kz_api:default_headers(?APP_NAME, ?APP_VERSION)
- ],
- case kz_amqp_worker:call_collect(Req
- ,fun kapi_registration:publish_query_req/1
- ,'ecallmgr'
- )
- of
- {'error', _E} ->
- lager:debug("error getting reg: ~p", [_E]),
- [];
- {_, JObjs} ->
- [kz_json:from_list([{<<"device_id">>, AuthorizingId}
- ,{<<"registered">>, 'true'}
- ])
- || AuthorizingId <- extract_device_registrations(JObjs)
- ]
- end.
-
--spec extract_device_registrations(kz_json:objects()) -> kz_term:ne_binaries().
-extract_device_registrations(JObjs) ->
- sets:to_list(extract_device_registrations(JObjs, sets:new())).
-
--spec extract_device_registrations(kz_json:objects(), sets:set()) -> sets:set().
-extract_device_registrations([], Set) -> Set;
-extract_device_registrations([JObj|JObjs], Set) ->
- S = lists:foldl(fun extract_device_registration/2
- ,Set
- ,kz_json:get_value(<<"Fields">>, JObj, [])
- ),
- extract_device_registrations(JObjs, S).
-
--spec extract_device_registration(kz_json:object(), sets:set()) -> sets:set().
-extract_device_registration(JObj, Set) ->
- case kz_json:get_ne_binary_value(<<"Authorizing-ID">>, JObj) of
- 'undefined' -> Set;
- AuthId -> sets:add_element(AuthId, Set)
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Check if the device sip creds are unique
-%% @end
-%%------------------------------------------------------------------------------
--spec is_sip_creds_unique(kz_term:api_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:api_binary()) ->
- boolean().
-
-%% no account id and no doc id (ie initial create with no account)
-is_sip_creds_unique('undefined', _, _, 'undefined') -> 'true';
-is_sip_creds_unique(AccountDb, Realm, Username, DeviceId) ->
- is_creds_locally_unique(AccountDb, Username, DeviceId)
- andalso is_creds_global_unique(Realm, Username, DeviceId).
-
--spec is_creds_locally_unique(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> boolean().
-is_creds_locally_unique(AccountDb, Username, DeviceId) ->
- ViewOptions = [{'key', kz_term:to_lower_binary(Username)}],
- case kz_datamgr:get_results(AccountDb, <<"devices/sip_credentials">>, ViewOptions) of
- {'ok', []} -> 'true';
- {'ok', [JObj]} -> kz_doc:id(JObj) =:= DeviceId;
- {'error', 'not_found'} -> 'true';
- _ -> 'false'
- end.
-
--spec is_creds_global_unique(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> boolean().
-is_creds_global_unique(Realm, Username, DeviceId) ->
- ViewOptions = [{'key', [kz_term:to_lower_binary(Realm)
- ,kz_term:to_lower_binary(Username)
- ]
- }],
- case kz_datamgr:get_results(?KZ_SIP_DB, <<"credentials/lookup">>, ViewOptions) of
- {'ok', []} -> 'true';
- {'ok', [JObj]} -> kz_doc:id(JObj) =:= DeviceId;
- {'error', 'not_found'} -> 'true';
- _ -> 'false'
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
-
--spec maybe_aggregate_device(kz_term:api_binary(), cb_context:context()) -> boolean().
-maybe_aggregate_device(DeviceId, Context) ->
- maybe_aggregate_device(DeviceId, Context, cb_context:resp_status(Context)).
-
--spec maybe_aggregate_device(kz_term:api_binary(), cb_context:context(), crossbar_status()) -> boolean().
-maybe_aggregate_device(DeviceId, Context, 'success') ->
- case kz_term:is_true(cb_context:fetch(Context, 'aggregate_device'))
- andalso ?DEVICES_ALLOW_AGGREGATES
- of
- 'false' ->
- maybe_remove_aggregate(DeviceId, Context);
- 'true' ->
- aggregate_device(cb_context:doc(Context)),
- _ = kz_amqp_worker:cast([], fun(_) -> kapi_switch:publish_reload_acls() end),
- 'true'
- end;
-maybe_aggregate_device(_, _, _) -> 'false'.
-
--spec aggregate_device(kz_json:object()) -> 'ok'.
-aggregate_device(Device) ->
- lager:debug("adding device to the sip auth aggregate"),
- Doc = kz_doc:delete_revision(Device),
- 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(Device), UpdateOptions),
- 'ok'.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
-
--spec maybe_remove_aggregate(kz_term:api_binary(), cb_context:context()) -> boolean().
-maybe_remove_aggregate(DeviceId, Context) ->
- maybe_remove_aggregate(DeviceId, Context, cb_context:resp_status(Context)).
-
--spec maybe_remove_aggregate(kz_term:api_binary(), cb_context:context(), crossbar_status()) -> boolean().
-maybe_remove_aggregate('undefined', _Context, _RespStatus) -> 'false';
-maybe_remove_aggregate(DeviceId, _Context, 'success') ->
- case kz_datamgr:del_doc(?KZ_SIP_DB, DeviceId) of
- {'ok', _JObj} ->
- _ = kz_amqp_worker:cast([], fun(_) -> kapi_switch:publish_reload_acls() end),
- 'true';
- {'error', 'not_found'} -> 'false'
- end;
-maybe_remove_aggregate(_, _, _) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc Perform actions on a device
-%% @end
-%%------------------------------------------------------------------------------
--spec put_action(cb_context:context(), kz_term:ne_binary(), kz_term:api_binary()) ->
- cb_context:context().
-put_action(Context, DeviceId, <<"notify">>) ->
- lager:debug("publishing NOTIFY for ~s", [DeviceId]),
- Username = kzd_devices:sip_username(cb_context:doc(Context)),
- Realm = kzd_accounts:fetch_realm(cb_context:account_id(Context)),
- Req = props:filter_undefined(
- [{<<"Body">>, cb_context:req_value(Context, [<<"data">>, <<"body">>, <<"data">>])}
- ,{<<"Content-Type">>, cb_context:req_value(Context, [<<"data">>, <<"body">>, <<"content_type">>])}
- ,{<<"Event">>, cb_context:req_value(Context, [<<"data">>, <<"event">>])}
- ,{<<"Msg-ID">>, cb_context:req_id(Context)}
- ,{<<"Realm">>, Realm}
- ,{<<"Username">>, Username}
- | kz_api:default_headers(?APP_NAME, ?APP_VERSION)
- ]),
- kapi_switch:publish_notify(Req),
- crossbar_util:response_202(<<"NOTIFY sent">>, Context).
diff --git a/applications/crossbar/src/modules_v1/cb_limits_v1.erl b/applications/crossbar/src/modules_v1/cb_limits_v1.erl
deleted file mode 100644
index a316099d302..00000000000
--- a/applications/crossbar/src/modules_v1/cb_limits_v1.erl
+++ /dev/null
@@ -1,166 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_limits_v1).
-
--export([init/0
- ,allowed_methods/0
- ,resource_exists/0
- ,validate/1
- ,post/1
- ]).
-
--include("crossbar.hrl").
--include_lib("kazoo_stdlib/include/kazoo_json.hrl").
-
--define(CB_LIST, <<"limits/crossbar_listing">>).
--define(PVT_TYPE, <<"limits">>).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> 'ok'.
-init() ->
- _ = crossbar_bindings:bind(<<"v1_resource.allowed_methods.limits">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"v1_resource.resource_exists.limits">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"v1_resource.validate.limits">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.post.limits">>, ?MODULE, 'post'),
- 'ok'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
--spec allowed_methods() -> http_methods().
-allowed_methods() ->
- [?HTTP_GET, ?HTTP_POST].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- validate_limits(Context, cb_context:req_verb(Context)).
-
--spec validate_limits(cb_context:context(), http_method()) -> cb_context:context().
-validate_limits(Context, ?HTTP_GET) ->
- load_limit(Context);
-validate_limits(Context, ?HTTP_POST) ->
- case is_allowed(Context) of
- 'false' ->
- Message = <<"Please contact your phone provider to add limits.">>,
- cb_context:add_system_error('forbidden'
- ,kz_json:from_list([{<<"message">>, Message}])
- ,Context
- );
- 'true' -> update_limits(Context)
- end.
-
--spec post(cb_context:context()) -> cb_context:context().
-post(Context) -> crossbar_doc:save(Context).
-
--spec is_allowed(cb_context:context()) -> boolean().
-is_allowed(Context) ->
- AccountId = cb_context:account_id(Context),
- AuthAccountId = cb_context:auth_account_id(Context),
- IsSystemAdmin = kzd_accounts:is_superduper_admin(AuthAccountId),
- {'ok', MasterAccount} = kapps_util:get_master_account_id(),
- case kz_services_reseller:get_id(AccountId) of
- AuthAccountId ->
- lager:debug("allowing reseller to update limits"),
- 'true';
- MasterAccount ->
- lager:debug("allowing direct account to update limits"),
- 'true';
- _Else when IsSystemAdmin ->
- lager:debug("allowing system admin to update limits"),
- 'true';
- _Else ->
- lager:debug("sub-accounts of non-master resellers must contact the reseller to change their limits"),
- 'false'
- end.
-
-%%%=============================================================================
-%%% Internal functions
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc Load a Limit document from the database
-%% @end
-%%------------------------------------------------------------------------------
--spec load_limit(cb_context:context()) -> cb_context:context().
-load_limit(Context) ->
- maybe_handle_load_failure(crossbar_doc:load(?PVT_TYPE, Context, ?TYPE_CHECK_OPTION(?PVT_TYPE))).
-
-%%------------------------------------------------------------------------------
-%% @doc Update an existing device document with the data provided, if it is
-%% valid
-%% @end
-%%------------------------------------------------------------------------------
--spec update_limits(cb_context:context()) -> cb_context:context().
-update_limits(Context) ->
- cb_context:validate_request_data(<<"limits">>, Context, fun on_successful_validation/1).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec on_successful_validation(cb_context:context()) -> cb_context:context().
-on_successful_validation(Context) ->
- maybe_handle_load_failure(crossbar_doc:load_merge(?PVT_TYPE, Context, ?TYPE_CHECK_OPTION(?PVT_TYPE))).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
-
--spec maybe_handle_load_failure(cb_context:context()) ->
- cb_context:context().
-maybe_handle_load_failure(Context) ->
- maybe_handle_load_failure(Context, cb_context:resp_error_code(Context)).
-
--spec maybe_handle_load_failure(cb_context:context(), pos_integer()) ->
- cb_context:context().
-maybe_handle_load_failure(Context, 404) ->
- Data = cb_context:req_data(Context),
- NewLimits = kz_json:from_list([{<<"pvt_type">>, ?PVT_TYPE}
- ,{<<"_id">>, ?PVT_TYPE}
- ]),
- JObj = kz_json_schema:add_defaults(kz_json:merge_jobjs(NewLimits, kz_doc:public_fields(Data))
- ,<<"limits">>
- ),
-
- cb_context:setters(Context
- ,[{fun cb_context:set_resp_status/2, 'success'}
- ,{fun cb_context:set_resp_data/2, kz_doc:public_fields(JObj)}
- ,{fun cb_context:set_doc/2, crossbar_doc:update_pvt_parameters(JObj, Context)}
- ]);
-maybe_handle_load_failure(Context, _RespCode) -> Context.
diff --git a/applications/crossbar/src/modules_v1/cb_lists_v1.erl b/applications/crossbar/src/modules_v1/cb_lists_v1.erl
deleted file mode 100644
index dac1883cde0..00000000000
--- a/applications/crossbar/src/modules_v1/cb_lists_v1.erl
+++ /dev/null
@@ -1,283 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Match list module
-%%% Handle client requests for match list documents
-%%%
-%%%
-%%% @author Kozlov Yakov
-%%% @author SIPLABS, LLC (Maksim Krzhemenevskiy, Ilya Ashchepkov)
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_lists_v1).
-
--export([init/0
- ,allowed_methods/0, allowed_methods/1, allowed_methods/2
- ,resource_exists/0, resource_exists/1, resource_exists/2
- ,validate/1, validate/2, validate/3
- ,post/1, post/2, post/3
- ,put/1, put/2
- ,delete/2, delete/3
- ]).
-
--include("crossbar.hrl").
-
--define(CB_LIST, <<"lists/crossbar_listing">>).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> any().
-init() ->
- [crossbar_bindings:bind(Binding, ?MODULE, F)
- || {Binding, F} <- [{<<"v1_resource.allowed_methods.lists">>, 'allowed_methods'}
- ,{<<"v1_resource.resource_exists.lists">>, 'resource_exists'}
- ,{<<"v1_resource.validate.lists">>, 'validate'}
- ,{<<"v1_resource.execute.put.lists">>, 'put'}
- ,{<<"v1_resource.execute.post.lists">>, 'post'}
- ,{<<"v1_resource.execute.delete.lists">>, 'delete'}
- ]
- ].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec allowed_methods() -> http_methods().
-allowed_methods() ->
- [?HTTP_GET, ?HTTP_PUT].
-
--spec allowed_methods(path_token()) -> http_methods().
-allowed_methods(_ListId) ->
- [?HTTP_GET, ?HTTP_PUT, ?HTTP_POST, ?HTTP_DELETE].
-
--spec allowed_methods(path_token(), path_token()) -> http_methods().
-allowed_methods(_ListId, _EntryId) ->
- [?HTTP_GET, ?HTTP_POST, ?HTTP_DELETE].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
--spec resource_exists(path_token()) -> 'true'.
-resource_exists(_ListId) -> 'true'.
-
--spec resource_exists(path_token(), path_token()) -> 'true'.
-resource_exists(_ListId, _EntryId) -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- validate_lists(Context, cb_context:req_verb(Context)).
-
--spec validate(cb_context:context(), path_token()) -> cb_context:context().
-validate(Context, ListId) ->
- validate_list(Context, ListId, cb_context:req_verb(Context)).
-
--spec validate(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-validate(Context, ListId, EntryId) ->
- validate_list_entry(Context, ListId, EntryId, cb_context:req_verb(Context)).
-
--spec validate_lists(cb_context:context(), http_method()) -> cb_context:context().
-validate_lists(Context, ?HTTP_GET) ->
- load_lists(Context);
-validate_lists(Context, ?HTTP_PUT) ->
- check_list_schema('undefined', Context).
-
--spec validate_list(cb_context:context(), path_token(), http_method()) -> cb_context:context().
-validate_list(Context, ListId, ?HTTP_GET) ->
- load_list(Context, ListId);
-validate_list(Context, ListId, ?HTTP_POST) ->
- check_list_schema(ListId, Context);
-validate_list(Context, ListId, ?HTTP_PUT) ->
- check_list_entry_schema(ListId, 'undefined', Context);
-validate_list(Context, ListId, ?HTTP_DELETE) ->
- cb_lists_v2:validate(Context, ListId).
-
--spec validate_list_entry(cb_context:context(), path_token(), path_token(), http_method()) -> cb_context:context().
-validate_list_entry(Context, _ListId, EntryId, ?HTTP_GET) ->
- crossbar_doc:load(EntryId, Context, ?TYPE_CHECK_OPTION(<<"list_entry">>));
-validate_list_entry(Context, ListId, EntryId, ?HTTP_POST) ->
- check_list_entry_schema(ListId, EntryId, Context);
-validate_list_entry(Context, _ListId, EntryId, ?HTTP_DELETE) ->
- crossbar_doc:load(EntryId, Context, ?TYPE_CHECK_OPTION(<<"list_entry">>)).
-
--spec check_list_schema(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-check_list_schema(ListId, Context) ->
- case cb_context:req_value(Context, <<"entries">>) of
- 'undefined' ->
- OnSuccess = fun(C) -> on_successful_validation(ListId, C) end,
- NewReq = kz_json:filter(fun filter_list_req_data/1
- ,cb_context:req_data(Context)
- ),
- NewContext = cb_context:set_req_data(Context, NewReq),
- cb_context:validate_request_data(<<"lists">>, NewContext, OnSuccess);
- _ ->
- crossbar_util:response('error', <<"API changed: entries not acceptable">>, 406, Context)
- end.
-
--spec filter_list_req_data({kz_term:ne_binary(), any()}) -> boolean().
-filter_list_req_data({Key, _Val})
- when Key =:= <<"name">>;
- Key =:= <<"org">>;
- Key =:= <<"description">>
- -> 'true';
-filter_list_req_data(_) -> 'false'.
-
--spec on_successful_validation(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-on_successful_validation('undefined', Context) ->
- Props = [{<<"pvt_type">>, <<"list">>}],
- cb_context:set_doc(Context
- ,kz_json:set_values(Props, cb_context:doc(Context))
- );
-on_successful_validation(ListId, Context) ->
- crossbar_doc:load_merge(ListId, Context, ?TYPE_CHECK_OPTION(<<"list">>)).
-
--spec check_list_entry_schema(path_token(), kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-check_list_entry_schema(ListId, EntryId, Context) ->
- OnSuccess = fun(C) -> entry_schema_success(C, ListId, EntryId) end,
- ReqData = kz_json:set_value(<<"list_id">>, ListId, cb_context:req_data(Context)),
- cb_context:validate_request_data(<<"list_entries">>, cb_context:set_req_data(Context, ReqData), OnSuccess).
-
--spec entry_schema_success(cb_context:context(), kz_term:ne_binary(), kz_term:ne_binary()) -> cb_context:context().
-entry_schema_success(Context, ListId, EntryId) ->
- Pattern = kz_json:get_value(<<"pattern">>, cb_context:doc(Context)),
- case is_binary(Pattern)
- andalso re:compile(Pattern)
- of
- {'ok', _CompiledRe} ->
- on_entry_successful_validation(ListId, EntryId, Context);
- 'false' ->
- on_entry_successful_validation(ListId, EntryId, Context);
- {'error', {Reason0, Pos}} ->
- Reason = io_lib:format("Error: ~s in position ~p", [Reason0, Pos]),
- error_in_pattern(Context, Pattern, Reason)
- end.
-
--spec error_in_pattern(cb_context:context(), binary(), iolist()) ->
- cb_context:context().
-error_in_pattern(Context, Pattern, Reason) ->
- cb_context:add_validation_error(<<"pattern">>
- ,<<"type">>
- ,kz_json:from_list(
- [{<<"message">>, iolist_to_binary(Reason)}
- ,{<<"cause">>, Pattern}
- ])
- ,Context
- ).
-
--spec on_entry_successful_validation(path_token(), path_token() | 'undefined', cb_context:context()) ->
- cb_context:context().
-on_entry_successful_validation(_ListId, 'undefined', Context) ->
- cb_context:set_doc(Context
- ,kz_json:set_values([{<<"pvt_type">>, <<"list_entry">>}]
- ,cb_context:doc(Context)
- )
- );
-on_entry_successful_validation(_ListId, EntryId, Context) ->
- crossbar_doc:load_merge(EntryId, Context, ?TYPE_CHECK_OPTION(<<"list_entry">>)).
-
--spec post(cb_context:context()) -> cb_context:context().
-post(Context) ->
- crossbar_doc:save(Context).
-
--spec post(cb_context:context(), path_token()) -> cb_context:context().
-post(Context, _ListId) ->
- crossbar_doc:save(Context).
-
--spec post(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-post(Context, _ListId, _EntryId) ->
- crossbar_doc:save(Context).
-
--spec put(cb_context:context()) -> cb_context:context().
-put(Context) ->
- crossbar_doc:save(Context).
-
--spec put(cb_context:context(), path_token()) -> cb_context:context().
-put(Context, _ListId) ->
- crossbar_doc:save(Context).
-
--spec delete(cb_context:context(), path_token()) -> cb_context:context().
-delete(Context, ListId) ->
- cb_lists_v2:delete(Context, ListId).
-
--spec delete(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-delete(Context, _ListId, _EntryId) ->
- crossbar_doc:delete(Context).
-
-%%------------------------------------------------------------------------------
-%% @doc Normalizes the results of a view.
-%% @end
-%%------------------------------------------------------------------------------
--spec normalize_view_results(kz_json:object(), kz_json:objects()) ->
- kz_json:objects().
-normalize_view_results(JObj, Acc) ->
- [kz_json:get_value(<<"value">>, JObj)|Acc].
-
--spec load_lists(cb_context:context()) -> cb_context:context().
-load_lists(Context) ->
- Entries = cb_context:doc(crossbar_doc:load_view(<<"lists/entries">>
- ,[]
- ,cb_context:set_query_string(Context, kz_json:new())
- ,fun normalize_view_results/2)),
- crossbar_doc:load_view(?CB_LIST
- ,[]
- ,Context
- ,load_entries_and_normalize(Entries)).
-
--spec load_entries_and_normalize(kz_json:objects()) -> fun((kz_json:object(), kz_json:objects()) -> boolean()).
-load_entries_and_normalize(AllEntries) ->
- fun(JObj, Acc) ->
- Val = kz_json:get_value(<<"value">>, JObj),
- ListId = kz_json:get_value(<<"id">>, Val),
- ListEntries = lists:filter(filter_entries_by_list_id(ListId), AllEntries),
- [kz_json:set_value(<<"entries">>, entries_from_list(ListEntries), Val)|Acc]
- end.
-
--spec filter_entries_by_list_id(kz_term:ne_binary()) -> fun((kz_json:object()) -> boolean()).
-filter_entries_by_list_id(Id) ->
- fun(Entry) ->
- kz_json:get_value(<<"list_id">>, Entry) =:= Id
- end.
-
--spec entries_from_list(kz_json:objects()) -> kz_json:object().
-entries_from_list(Entries) ->
- kz_json:from_list([{kz_json:get_value(<<"_id">>, X), kz_doc:public_fields(X)}
- || X <- Entries
- ]).
-
--spec load_list(cb_context:context(), kz_term:ne_binary()) -> cb_context:context().
-load_list(Context, ListId) ->
- Entries = cb_context:doc(crossbar_doc:load_view(<<"lists/entries">>
- ,[{'key', ListId}]
- ,Context
- ,fun normalize_view_results/2)),
- Context1 = crossbar_doc:load(ListId, Context, ?TYPE_CHECK_OPTION(<<"list">>)),
- Doc = cb_context:doc(Context1),
- Doc1 = kz_doc:public_fields(kz_json:set_value(<<"entries">>, entries_from_list(Entries), Doc)),
- cb_context:set_resp_data(Context1, Doc1).
diff --git a/applications/crossbar/src/modules_v1/cb_phone_numbers_v1.erl b/applications/crossbar/src/modules_v1/cb_phone_numbers_v1.erl
deleted file mode 100644
index 48bb3962ce1..00000000000
--- a/applications/crossbar/src/modules_v1/cb_phone_numbers_v1.erl
+++ /dev/null
@@ -1,555 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Handle client requests for phone_number documents
-%%% @author Karl Anderson
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_phone_numbers_v1).
-
--export([init/0
- ,allowed_methods/0, allowed_methods/1, allowed_methods/2
- ,resource_exists/0, resource_exists/1, resource_exists/2
- ,validate/1, validate/2, validate/3
- ,validate_request/1
- ,authorize/1
- ,authenticate/1
- ,put/2, put/3
- ,post/2
- ,delete/2
- ,summary/1
- ]).
-
--include("crossbar.hrl").
--include_lib("kazoo_numbers/include/knm_phone_number.hrl").
-
--define(CB_LIST, <<"phone_numbers/crossbar_listing">>).
-
--define(ACTIVATE, <<"activate">>).
--define(RESERVE, <<"reserve">>).
--define(PORT, <<"port">>).
-
--define(CLASSIFIERS, <<"classifiers">>).
--define(IDENTIFY, <<"identify">>).
--define(COLLECTION, <<"collection">>).
--define(MIME_TYPES, [{<<"application">>, <<"pdf">>}
- ,{<<"application">>, <<"x-gzip">>}
- ,{<<"application">>, <<"zip">>}
- ,{<<"application">>, <<"x-rar-compressed">>}
- ,{<<"application">>, <<"x-tar">>}
- ,{<<"image">>, <<"*">>}
- ,{<<"text">>, <<"plain">>}
- ,{<<"application">>, <<"base64">>}
- ,{<<"application">>, <<"x-base64">>}
- ]).
--define(PHONE_NUMBERS_CONFIG_CAT, <<"crossbar.phone_numbers">>).
--define(FIND_NUMBER_SCHEMA, "{\"$schema\": \"http://json-schema.org/draft-03/schema#\", \"id\": \"http://json-schema.org/draft-03/schema#\", \"properties\": {\"prefix\": {\"required\": \"true\", \"type\": \"string\", \"minLength\": 3, \"maxLength\": 10}, \"quantity\": {\"default\": 1, \"type\": \"integer\", \"minimum\": 1}}}").
-
--define(PREFIX, <<"prefix">>).
--define(COUNTRY, <<"country">>).
--define(OFFSET, <<"offset">>).
--define(QUANTITY, <<"quantity">>).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec init() -> ok.
-init() ->
- _ = crossbar_bindings:bind(<<"v1_resource.content_types_accepted.phone_numbers">>, ?MODULE, 'content_types_accepted'),
- _ = crossbar_bindings:bind(<<"v1_resource.authenticate">>, ?MODULE, 'authenticate'),
- _ = crossbar_bindings:bind(<<"v1_resource.authorize">>, ?MODULE, 'authorize'),
- _ = crossbar_bindings:bind(<<"v1_resource.allowed_methods.phone_numbers">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"v1_resource.resource_exists.phone_numbers">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"v1_resource.validate.phone_numbers">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.put.phone_numbers">>, ?MODULE, 'put'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.post.phone_numbers">>, ?MODULE, 'post'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.delete.phone_numbers">>, ?MODULE, 'delete'),
- ok.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec allowed_methods() -> http_methods().
-allowed_methods() ->
- [?HTTP_GET].
-
--spec allowed_methods(path_token()) -> http_methods().
-allowed_methods(?CLASSIFIERS) ->
- [?HTTP_GET];
-allowed_methods(?COLLECTION) ->
- [?HTTP_PUT, ?HTTP_POST, ?HTTP_DELETE];
-allowed_methods(_) ->
- [?HTTP_GET, ?HTTP_PUT, ?HTTP_POST, ?HTTP_DELETE].
-
--spec allowed_methods(path_token(), path_token()) -> http_methods().
-allowed_methods(_, ?ACTIVATE) ->
- [?HTTP_PUT];
-allowed_methods(_, ?RESERVE) ->
- [?HTTP_PUT];
-allowed_methods(_, ?PORT) ->
- [?HTTP_PUT];
-allowed_methods(_, ?IDENTIFY) ->
- [?HTTP_GET];
-allowed_methods(?COLLECTION, ?ACTIVATE) ->
- [?HTTP_PUT].
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
--spec resource_exists(path_token()) -> 'true'.
-resource_exists(_) -> 'true'.
-
--spec resource_exists(path_token(), path_token()) -> boolean().
-resource_exists(_, ?ACTIVATE) -> 'true';
-resource_exists(_, ?RESERVE) -> 'true';
-resource_exists(_, ?PORT) -> 'true';
-resource_exists(_, ?IDENTIFY) -> 'true';
-resource_exists(_, _) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc Authenticates the incoming request, returning true if the requestor is
-%% known, or false if not.
-%% @end
-%%------------------------------------------------------------------------------
--spec authenticate(cb_context:context()) -> 'true'.
-authenticate(Context) ->
- authenticate(cb_context:req_verb(Context), cb_context:req_nouns(Context)).
-
--spec authenticate(http_method(), req_nouns()) -> 'true'.
-authenticate(?HTTP_GET, [{<<"phone_numbers">>, []}]) -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc Authorizes the incoming request, returning true if the requestor is
-%% allowed to access the resource, or false if not.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec authorize(cb_context:context()) -> 'true'.
-authorize(Context) ->
- authorize(cb_context:req_verb(Context), cb_context:req_nouns(Context)).
-
--spec authorize(http_method(), req_nouns()) -> 'true'.
-authorize(?HTTP_GET, [{<<"phone_numbers">>,[]}]) -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- validate_1(Context, cb_context:req_verb(Context)).
-
--spec validate_1(cb_context:context(), http_method()) -> cb_context:context().
-validate_1(Context, ?HTTP_GET) ->
- case cb_context:account_id(Context) of
- 'undefined' -> find_numbers(Context);
- _ -> cb_modules_util:maybe_convert_numbers_to_list(summary(Context))
- end.
-
--spec validate(cb_context:context(), path_token()) -> cb_context:context().
-validate(Context, PathToken1) ->
- validate_2(Context, cb_context:req_verb(Context), PathToken1).
-
--spec validate_2(cb_context:context(), http_method(), path_token()) -> cb_context:context().
-validate_2(Context, ?HTTP_PUT, ?COLLECTION) ->
- validate_request(Context);
-validate_2(Context, ?HTTP_POST, ?COLLECTION) ->
- validate_request(Context);
-validate_2(Context, ?HTTP_DELETE, ?COLLECTION) ->
- validate_delete(Context);
-validate_2(Context, ?HTTP_GET, ?CLASSIFIERS) ->
- cb_context:set_resp_data(cb_context:set_resp_status(Context, 'success')
- ,knm_converters:available_classifiers()
- );
-validate_2(Context, ?HTTP_GET, Number) ->
- read(Context, Number);
-validate_2(Context, ?HTTP_POST, _Number) ->
- validate_request(Context);
-validate_2(Context, ?HTTP_PUT, _Number) ->
- validate_request(Context);
-validate_2(Context, ?HTTP_DELETE, _Number) ->
- validate_delete(Context).
-
--spec validate(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-validate(Context, PathToken1, PathToken2) ->
- validate_3(Context, cb_context:req_verb(Context), PathToken1, PathToken2).
-
--spec validate_3(cb_context:context(), http_method(), path_token(), path_token()) -> cb_context:context().
-validate_3(Context, ?HTTP_PUT, ?COLLECTION, ?ACTIVATE) ->
- validate_request(Context);
-validate_3(Context, ?HTTP_PUT, _Number, ?ACTIVATE) ->
- case has_tokens(Context) of
- 'true' -> validate_request(Context);
- 'false' -> cb_context:add_system_error('too_many_requests', Context)
- end;
-validate_3(Context, ?HTTP_PUT, _Number, ?RESERVE) ->
- validate_request(Context);
-validate_3(Context, ?HTTP_PUT, _Number, ?PORT) ->
- validate_request(Context);
-validate_3(Context, ?HTTP_GET, Number, ?IDENTIFY) ->
- identify(Context, Number).
-
--spec post(cb_context:context(), path_token()) -> cb_context:context().
-post(Context, ?COLLECTION) ->
- set_response(collection_process(Context), Context);
-post(Context, Number) ->
- Options = default_knm_options(Context),
- JObj = cb_context:doc(Context),
- Result = knm_number:update(Number, [{fun knm_phone_number:reset_doc/2, JObj}], Options),
- set_response(Result, Context).
-
--spec put(cb_context:context(), path_token()) -> cb_context:context().
-put(Context, ?COLLECTION) ->
- set_response(collection_process(Context), Context);
-put(Context, Number) ->
- Options = [{'assign_to', cb_context:account_id(Context)}
- ,{'public_fields', cb_context:doc(Context)}
- | default_knm_options(Context)
- ],
- Result = knm_number:create(Number, Options),
- set_response(Result, Context).
-
--spec put(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-put(Context, ?COLLECTION, ?ACTIVATE) ->
- set_response(collection_process(Context, ?ACTIVATE), Context);
-put(Context, Number, ?ACTIVATE) ->
- Options = [{'public_fields', cb_context:doc(Context)}
- | default_knm_options(Context)
- ],
- Result = case knm_number:move(Number, cb_context:account_id(Context), Options) of
- {'ok', KNum} ->
- {'ok', kz_json:delete_key(<<"numbers">>, knm_number:to_public_json(KNum))};
- _Else -> _Else
- end,
- set_response(Result, Context);
-put(Context, Number, ?RESERVE) ->
- Options = [{'assign_to', cb_context:account_id(Context)}
- ,{'public_fields', cb_context:doc(Context)}
- | default_knm_options(Context)
- ],
- Result = knm_number:reserve(Number, Options),
- set_response(Result, Context);
-put(Context, Number, ?PORT) ->
- Options = [{'assign_to', cb_context:account_id(Context)}
- ,{'public_fields', cb_context:doc(Context)}
- ,{'state', ?NUMBER_STATE_PORT_IN}
- | default_knm_options(Context)
- ],
- Result = knm_number:create(Number, Options),
- set_response(Result, Context).
-
--spec delete(cb_context:context(), path_token()) -> cb_context:context().
-delete(Context, ?COLLECTION) ->
- set_response(collection_process(Context), Context);
-delete(Context, Number) ->
- Options = default_knm_options(Context),
- Result = knm_number:release(Number, Options),
- set_response(Result, Context).
-
--spec summary(cb_context:context()) -> cb_context:context().
-summary(Context) ->
- Context1 = crossbar_doc:load_view(?CB_LIST, [], rename_qs_filters(Context), fun normalize_view_results/2),
- ListOfNumProps = cb_context:resp_data(Context1),
- NumbersJObj = lists:foldl(fun kz_json:merge_jobjs/2, kz_json:new(), ListOfNumProps),
- Services = kz_services:fetch(cb_context:account_id(Context)),
- Quantity = kz_services_quantities:cascade_category(Services, <<"phone_numbers">>),
- NewRespData = kz_json:from_list([{<<"numbers">>, NumbersJObj}
- ,{<<"cascade_quantity">>, Quantity}
- ]),
- cb_context:set_resp_data(Context1, NewRespData).
-
--spec rename_qs_filters(cb_context:context()) -> cb_context:context().
-rename_qs_filters(Context) ->
- Renamer = fun (<<"filter_state">>, Value) -> {<<"filter_pvt_state">>, Value};
- (<<"filter_assigned_to">>, Value) -> {<<"filter_pvt_assigned_to">>, Value};
- (<<"filter_locality">>, Value) -> {<<"filter_pvt_locality">>, Value};
- (K, V) -> {K, V}
- end,
- NewQS = kz_json:map(Renamer, cb_context:query_string(Context)),
- cb_context:set_query_string(Context, NewQS).
-
--spec normalize_view_results(kz_json:object(), kz_json:objects()) -> kz_json:objects().
-normalize_view_results(JObj, Acc) ->
- Number = kz_json:get_value(<<"key">>, JObj),
- Properties = kz_json:get_value(<<"value">>, JObj),
- [kz_json:set_value(Number, Properties, kz_json:new())
- | Acc
- ].
-
-%%%=============================================================================
-%%% Internal functions
-%%%=============================================================================
-
-%%------------------------------------------------------------------------------
-%% @doc Attempt to load a summarized listing of all instances of this
-%% resource.
-%% @end
-%%------------------------------------------------------------------------------
--spec identify(cb_context:context(), kz_term:ne_binary()) -> cb_context:context().
-identify(Context, Number) ->
- case knm_number:lookup_account(Number) of
- {'error', 'not_reconcilable'} ->
- cb_context:add_system_error('bad_identifier'
- ,kz_json:from_list([{<<"cause">>, Number}])
- ,Context
- );
- {'error', E} ->
- set_response({kz_term:to_binary(E), <<>>}, Context);
- {'ok', AccountId, Options} ->
- JObj = kz_json:set_values([{<<"account_id">>, AccountId}
- ,{<<"number">>, knm_number_options:number(Options)}
- ]
- ,kz_json:new()
- ),
- set_response({'ok', JObj}, Context)
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Load an instance from the database.
-%% @end
-%%------------------------------------------------------------------------------
--spec read(cb_context:context(), kz_term:ne_binary()) -> cb_context:context().
-read(Context, Number) ->
- Options = [{'auth_by', cb_context:auth_account_id(Context)}],
- Result = case knm_number:get(Number, Options) of
- {'ok', KNum} -> {'ok', knm_number:to_public_json(KNum)};
- {'error', _R}=Error -> Error
- end,
- set_response(Result, Context).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec find_numbers(cb_context:context()) -> cb_context:context().
-find_numbers(Context) ->
- AuthAccountId = cb_context:auth_account_id(Context),
- QS = cb_context:query_string(Context),
- Country = kz_json:get_ne_value(?COUNTRY, QS, ?KNM_DEFAULT_COUNTRY),
- Prefix = kz_binary:remove_white_spaces(kz_json:get_ne_value(?PREFIX, QS)),
- Offset = kz_json:get_integer_value(?OFFSET, QS, 0),
- Token = cb_context:auth_token(Context),
- HashKey = <>,
- Hash = kz_base64url:encode(crypto:hash(sha, HashKey)),
- QueryId = list_to_binary([Country, "-", Prefix, "-", Hash]),
- Dialcode = knm_util:prefix_for_country(Country),
- NormalizedPrefix = <>,
- Options = props:filter_undefined(
- [{'quantity', max(1, kz_json:get_integer_value(?QUANTITY, QS, 1))}
- ,{'prefix', Prefix}
- ,{'normalized_prefix', NormalizedPrefix}
- ,{'country', Country}
- ,{'dialcode', Dialcode}
- ,{'offset', Offset}
- ,{'account_id', AuthAccountId}
- ,{'reseller_id', kz_services_reseller:get_id(AuthAccountId)}
- ,{'query_id', QueryId}
- ]),
- OnSuccess =
- fun(C) ->
- Found = knm_search:find(Options),
- cb_context:setters(C
- ,[{fun cb_context:set_resp_data/2, Found}
- ,{fun cb_context:set_resp_status/2, 'success'}
- ])
- end,
- Schema = kz_json:decode(?FIND_NUMBER_SCHEMA),
- Context1 = cb_context:set_req_data(Context, kz_json:from_list(Options)),
- cb_context:validate_request_data(Schema, Context1, OnSuccess).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec validate_request(cb_context:context()) -> cb_context:context().
-validate_request(Context) ->
- cb_context:validate_request_data(<<"phone_numbers">>, Context).
-
-%%------------------------------------------------------------------------------
-%% @doc Load an instance from the database
-%% @end
-%%------------------------------------------------------------------------------
--spec validate_delete(cb_context:context()) -> cb_context:context().
-validate_delete(Context) ->
- cb_context:set_doc(cb_context:set_resp_status(Context, 'success')
- ,'undefined'
- ).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--type result() :: {'ok', kz_json:object()} |
- kz_json:object() |
- knm_number_return() |
- {binary(), binary()}.
-
--spec set_response(result(), cb_context:context()) -> cb_context:context().
-set_response({'ok', {'ok', Doc}}, Context) ->
- crossbar_util:response(Doc, Context);
-set_response({'ok', Doc}, Context) ->
- case knm_number:is_number(Doc) of
- 'true' -> crossbar_util:response(knm_number:to_public_json(Doc), Context);
- 'false' -> crossbar_util:response(Doc, Context)
- end;
-set_response({'error', 'not_found'}, Context) ->
- Msg = kz_json:from_list([{<<"message">>, <<"bad identifier">>}
- ,{<<"not_found">>, <<"The number could not be found">>}
- ]),
- cb_context:add_system_error('bad_identifier', Msg, Context);
-set_response({'error', Data}, Context) ->
- case kz_json:is_json_object(Data) of
- 'true' ->
- Code = knm_errors:code(Data),
- Msg = knm_errors:error(Data),
- lager:debug("error ~p: ~p", [Code, Msg]),
- cb_context:add_system_error(Code, Msg, Data, Context);
- 'false' ->
- lager:debug("error: ~p", [Data]),
- crossbar_util:response_400(<<"client error">>, Data, Context)
- end;
-set_response({Error, Reason}, Context) ->
- crossbar_util:response('error', kz_term:to_binary(Error), 500, Reason, Context);
-set_response(CollectionJObjOrUnkown, Context) ->
- case kz_json:is_json_object(CollectionJObjOrUnkown) of
- 'true' -> crossbar_util:response(CollectionJObjOrUnkown, Context);
- 'false' ->
- lager:debug("unexpected response: ~p", [CollectionJObjOrUnkown]),
- cb_context:add_system_error('unspecified_fault', Context)
- end.
-
--spec collection_process(cb_context:context()) -> kz_json:object().
-collection_process(Context) ->
- Numbers = kz_json:get_value(<<"numbers">>, cb_context:req_data(Context), []),
- collection_process(Context, Numbers).
-
--spec collection_process(cb_context:context(), kz_term:ne_binary() | kz_term:ne_binaries()) -> kz_json:object().
-collection_process(Context, ?ACTIVATE) ->
- Numbers = kz_json:get_value(<<"numbers">>, cb_context:req_data(Context), []),
- collection_process(Context, Numbers, ?ACTIVATE);
-collection_process(Context, Numbers) ->
- Temp = kz_json:from_list([{<<"success">>, kz_json:new()}
- ,{<<"error">>, kz_json:new()}
- ]),
- lists:foldl(fun(Number, Acc) ->
- collection_process_fold(Number, Acc, Context)
- end
- ,Temp
- ,Numbers
- ).
-
--spec collection_process(cb_context:context(), kz_term:ne_binary() | kz_term:ne_binaries(), kz_term:ne_binary()) -> kz_json:object().
-collection_process(Context, Numbers, Action) ->
- Base = kz_json:from_list([{<<"success">>, kz_json:new()}
- ,{<<"error">>, kz_json:new()}
- ]
- ),
- lists:foldl(fun(Number, Acc) -> collection_process_action_fold(Number, Acc, Context, Action) end
- ,Base
- ,Numbers
- ).
-
--spec collection_process_action_fold(kz_term:ne_binary(), kz_json:object(), cb_context:context(), kz_term:ne_binary()) ->
- kz_json:object().
-collection_process_action_fold(Number, Acc, Context, Action) ->
- case collection_action(Context, cb_context:req_verb(Context), Number, Action) of
- {'ok', JObj} ->
- kz_json:set_value([<<"success">>, Number], JObj, Acc);
- {'error', KNMError} ->
- JObj = kz_json:set_value(<<"reason">>, knm_errors:cause(KNMError), kz_json:new()),
- kz_json:set_value([<<"error">>, Number], JObj, Acc)
- end.
-
--spec collection_process_fold(kz_term:ne_binary(), kz_json:object(), cb_context:context()) ->
- kz_json:object().
-collection_process_fold(Number, Acc, Context) ->
- case collection_action(Context, cb_context:req_verb(Context), Number) of
- {'ok', KNum} ->
- JObj = knm_number:to_public_json(KNum),
- kz_json:set_value([<<"success">>, Number], JObj, Acc);
- {'error', KNMError} ->
- JObj = kz_json:set_value(<<"reason">>, knm_errors:cause(KNMError), kz_json:new()),
- kz_json:set_value([<<"error">>, Number], JObj, Acc)
- end.
-
-
--spec collection_action(cb_context:context(), http_method(), kz_term:ne_binary()) -> knm_number_return().
-collection_action(Context, ?HTTP_PUT, Number) ->
- Options = [{'assign_to', cb_context:account_id(Context)}
- ,{'public_fields', kz_json:delete_key(<<"numbers">>, cb_context:doc(Context))}
- | default_knm_options(Context)
- ],
- knm_number:create(Number, Options);
-collection_action(Context, ?HTTP_POST, Number) ->
- Options = [{'assign_to', cb_context:account_id(Context)}
- | default_knm_options(Context)
- ],
- JObj = kz_json:delete_key(<<"numbers">>, cb_context:doc(Context)),
- knm_number:update(Number, [{fun knm_phone_number:reset_doc/2, JObj}], Options);
-collection_action(Context, ?HTTP_DELETE, Number) ->
- Options = default_knm_options(Context),
- knm_number:release(Number, Options).
-
--spec collection_action(cb_context:context(), http_method(), kz_term:ne_binary(), kz_term:ne_binary()) ->
- knm_number_return() |
- {'ok', kz_json:object()}.
-collection_action(Context, ?HTTP_PUT, Number, ?ACTIVATE) ->
- Options = [{'public_fields', kz_json:delete_key(<<"numbers">>, cb_context:doc(Context))}
- | default_knm_options(Context)
- ],
- case knm_number:move(Number, cb_context:account_id(Context), Options) of
- {'ok', KNum} ->
- {'ok', kz_json:delete_key(<<"numbers">>, knm_number:to_public_json(KNum))};
- _Else -> _Else
- end.
-
--spec has_tokens(cb_context:context()) -> boolean().
-has_tokens(Context) -> has_tokens(Context, 1).
-
--spec has_tokens(cb_context:context(), pos_integer()) -> boolean().
-has_tokens(Context, Count) ->
- Name = <<(cb_context:account_id(Context))/binary, "/", ?PHONE_NUMBERS_CONFIG_CAT/binary>>,
- Cost = cb_modules_util:token_cost(Context, Count),
- case kz_buckets:consume_tokens(?APP_NAME, Name, Cost) of
- 'true' -> 'true';
- 'false' ->
- lager:warning("rate limiting activation limit reached, rejecting"),
- 'false'
- end.
-
--spec default_knm_options(cb_context:context()) -> kz_term:proplist().
-default_knm_options(Context) ->
- AuthAccountId = cb_context:auth_account_id(Context),
- [{'crossbar', [{'services', kz_services:fetch(AuthAccountId)}
- ,{'account_id', cb_context:account_id(Context)}
- ,{'reseller_id', cb_context:reseller_id(Context)}
- ]
- }
- ,{'auth_by', AuthAccountId}
- ,{'dry_run', not cb_context:accepting_charges(Context)}
- ].
diff --git a/applications/crossbar/src/modules_v1/cb_users_v1.erl b/applications/crossbar/src/modules_v1/cb_users_v1.erl
deleted file mode 100644
index cdfb6a3f83a..00000000000
--- a/applications/crossbar/src/modules_v1/cb_users_v1.erl
+++ /dev/null
@@ -1,704 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2011-2019, 2600Hz
-%%% @doc Users module
-%%% Handle client requests for user documents
-%%%
-%%%
-%%% @author Karl Anderson
-%%% @author James Aimonetti
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_users_v1).
-
--export([create_user/1]).
--export([init/0
- ,allowed_methods/0, allowed_methods/1, allowed_methods/2
- ,content_types_provided/1, content_types_provided/2, content_types_provided/3
- ,resource_exists/0, resource_exists/1, resource_exists/2
- ,validate_resource/1, validate_resource/2, validate_resource/3
- ,authenticate/1
- ,authorize/1
- ,validate/1, validate/2, validate/3
- ,put/1
- ,post/2, post/3
- ,delete/2
- ,patch/2
- ]).
-
--include("crossbar.hrl").
-
--define(SERVER, ?MODULE).
--define(CB_LIST, <<"users/crossbar_listing">>).
--define(CHANNELS, <<"channels">>).
--define(VCARD, <<"vcard">>).
--define(PHOTO, <<"photo">>).
-
-%%%=============================================================================
-%%% API
-%%%=============================================================================
-
-%% SUPPORT FOR THE DEPRECIATED CB_SIGNUPS...
--spec create_user(cb_context:context()) -> cb_context:context().
-create_user(Context) ->
- Context1 = validate_request('undefined', cb_context:set_req_verb(Context, ?HTTP_PUT)),
- case cb_context:resp_status(Context1) of
- 'success' -> put(Context1);
- _Status -> Context1
- end.
-
--spec init() -> 'ok'.
-init() ->
- _ = crossbar_bindings:bind(<<"v1_resource.allowed_methods.users">>, ?MODULE, 'allowed_methods'),
- _ = crossbar_bindings:bind(<<"v1_resource.content_types_provided.users">>, ?MODULE, 'content_types_provided'),
- _ = crossbar_bindings:bind(<<"v1_resource.resource_exists.users">>, ?MODULE, 'resource_exists'),
- _ = crossbar_bindings:bind(<<"v1_resource.validate_resource.users">>, ?MODULE, 'validate_resource'),
- _ = crossbar_bindings:bind(<<"v1_resource.authenticate">>, ?MODULE, 'authenticate'),
- _ = crossbar_bindings:bind(<<"v1_resource.authorize">>, ?MODULE, 'authorize'),
- _ = crossbar_bindings:bind(<<"v1_resource.validate.users">>, ?MODULE, 'validate'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.put.users">>, ?MODULE, 'put'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.post.users">>, ?MODULE, 'post'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.delete.users">>, ?MODULE, 'delete'),
- _ = crossbar_bindings:bind(<<"v1_resource.execute.patch.users">>, ?MODULE, 'patch'),
- 'ok'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines the verbs that are appropriate for the
-%% given Nouns. For example `/accounts/' can only accept `GET' and `PUT'.
-%%
-%% Failure here returns `405 Method Not Allowed'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec allowed_methods() -> http_methods().
-allowed_methods() ->
- [?HTTP_GET, ?HTTP_PUT].
-
--spec allowed_methods(path_token()) -> http_methods().
-allowed_methods(_) ->
- [?HTTP_GET, ?HTTP_POST, ?HTTP_DELETE, ?HTTP_PATCH].
-
--spec allowed_methods(path_token(), path_token()) -> http_methods().
-allowed_methods(_, ?CHANNELS) ->
- [?HTTP_GET];
-allowed_methods(_, ?PHOTO) ->
- [?HTTP_POST];
-allowed_methods(_, ?VCARD) ->
- [?HTTP_GET].
-
--spec content_types_provided(cb_context:context()) ->
- cb_context:context().
-content_types_provided(Context) ->
- Context.
-
--spec content_types_provided(cb_context:context(), path_token()) ->
- cb_context:context().
-content_types_provided(Context, _) ->
- Context.
-
--spec content_types_provided(cb_context:context(), path_token(), path_token()) ->
- cb_context:context().
-content_types_provided(Context, _, ?VCARD) ->
- cb_context:set_content_types_provided(Context, [{'to_binary', [{<<"text">>, <<"x-vcard">>}
- ,{<<"text">>, <<"directory">>}
- ]
- }
- ]);
-content_types_provided(Context, _, _) ->
- Context.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns are valid.
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec resource_exists() -> 'true'.
-resource_exists() -> 'true'.
-
--spec resource_exists(path_token()) -> 'true'.
-resource_exists(_) -> 'true'.
-
--spec resource_exists(path_token(), path_token()) -> 'true'.
-resource_exists(_, ?CHANNELS) -> 'true';
-resource_exists(_, ?VCARD) -> 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the provided list of Nouns and Resource Ids are valid.
-%% If valid, updates Context with userId
-%%
-%% Failure here returns `404 Not Found'.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec validate_resource(cb_context:context()) -> cb_context:context().
-validate_resource(Context) -> Context.
-
--spec validate_resource(cb_context:context(), path_token()) -> cb_context:context().
-validate_resource(Context, UserId) -> validate_user_id(UserId, Context).
-
--spec validate_resource(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-validate_resource(Context, UserId, _) -> validate_user_id(UserId, Context).
-
--spec validate_user_id(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-validate_user_id(UserId, Context) ->
- case kz_datamgr:open_cache_doc(cb_context:account_db(Context), UserId) of
- {'ok', Doc} -> validate_user_id(UserId, Context, Doc);
- {'error', 'not_found'} ->
- cb_context:add_system_error('bad_identifier'
- ,kz_json:from_list([{<<"cause">>, UserId}])
- ,Context
- );
- {'error', _R} -> crossbar_util:response_db_fatal(Context)
- end.
-
--spec validate_user_id(kz_term:api_binary(), cb_context:context(), kz_json:object()) -> cb_context:context().
-validate_user_id(UserId, Context, Doc) ->
- case kz_doc:is_soft_deleted(Doc) of
- 'true' ->
- cb_context:add_system_error('bad_identifier'
- ,kz_json:from_list([{<<"cause">>, UserId}])
- ,Context
- );
- 'false'->
- cb_context:setters(Context
- ,[{fun cb_context:set_user_id/2, UserId}
- ,{fun cb_context:set_resp_status/2, 'success'}
- ])
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec authenticate(cb_context:context()) -> 'true'.
-authenticate(Context) ->
- authenticate_users(cb_context:req_nouns(Context), cb_context:req_verb(Context)).
-
-authenticate_users(?USERS_QCALL_NOUNS(_UserId, _Number), ?HTTP_GET) ->
- lager:debug("authenticating request"),
- 'true';
-authenticate_users(_Nouns, _Verb) -> 'false'.
-
--spec authorize(cb_context:context()) -> 'true'.
-authorize(Context) ->
- authorize_users(cb_context:req_nouns(Context), cb_context:req_verb(Context)).
-
-authorize_users(?USERS_QCALL_NOUNS(_UserId, _Number), ?HTTP_GET) ->
- lager:debug("authorizing request"),
- 'true';
-authorize_users(_Nouns, _Verb) -> 'false'.
-
-%%------------------------------------------------------------------------------
-%% @doc This function determines if the parameters and content are correct
-%% for this request
-%%
-%% Failure here returns 400.
-%% @end
-%%------------------------------------------------------------------------------
-
--spec validate(cb_context:context()) -> cb_context:context().
-validate(Context) ->
- validate_users(Context, cb_context:req_verb(Context)).
-
--spec validate(cb_context:context(), path_token()) -> cb_context:context().
-validate(Context, UserId) ->
- validate_user(Context, UserId, cb_context:req_verb(Context)).
-
--spec validate(cb_context:context(), path_token(), path_token()) -> cb_context:context().
-validate(Context, UserId, ?CHANNELS) ->
- Options = [{'key', [UserId, <<"device">>]}
- ,'include_docs'
- ],
- Context1 = crossbar_doc:load_view(<<"attributes/owned">>, Options, Context),
- case cb_context:has_errors(Context1) of
- 'true' -> Context1;
- 'false' -> get_channels(Context1)
- end;
-validate(Context, UserId, ?VCARD) ->
- Context1 = load_user(UserId, Context),
- case cb_context:has_errors(Context1) of
- 'true' -> Context1;
- 'false' -> convert_to_vcard(Context1)
- end.
-
--spec validate_users(cb_context:context(), http_method()) -> cb_context:context().
-validate_users(Context, ?HTTP_GET) ->
- load_user_summary(Context);
-validate_users(Context, ?HTTP_PUT) ->
- validate_request('undefined', Context).
-
--spec validate_user(cb_context:context(), kz_term:ne_binary(), http_method()) -> cb_context:context().
-validate_user(Context, UserId, ?HTTP_GET) ->
- load_user(UserId, Context);
-validate_user(Context, UserId, ?HTTP_POST) ->
- validate_request(UserId, Context);
-validate_user(Context, UserId, ?HTTP_DELETE) ->
- load_user(UserId, Context);
-validate_user(Context, UserId, ?HTTP_PATCH) ->
- validate_patch(UserId, Context).
-
--spec post(cb_context:context(), path_token()) -> cb_context:context().
-post(Context, _) ->
- _ = crossbar_util:maybe_refresh_fs_xml('user', Context),
- Context1 = cb_modules_util:take_sync_field(Context),
- sync_sip_data(Context1),
- crossbar_doc:save(cb_modules_util:remove_plaintext_password(Context1)).
-
--spec sync_sip_data(cb_context:context()) -> 'ok'.
-sync_sip_data(Context) ->
- NewDoc = cb_context:doc(Context),
- AccountId = cb_context:account_id(Context),
-
- case cb_context:fetch(Context, 'sync') of
- 'false' -> 'ok';
- 'true' -> provisioner_util:sync_user(AccountId);
- 'force' -> provisioner_util:force_sync_user(AccountId, NewDoc)
- end.
-
--spec post(cb_context:context(), kz_term:ne_binary(), path_token()) -> cb_context:context().
-post(Context, UserId, ?PHOTO) ->
- [{_FileName, FileObj}] = cb_context:req_files(Context),
- Headers = kz_json:get_value(<<"headers">>, FileObj),
- CT = kz_json:get_value(<<"content_type">>, Headers),
- Content = kz_json:get_value(<<"contents">>, FileObj),
- Opts = [{'content_type', CT} | ?TYPE_CHECK_OPTION(kzd_users:type())],
- crossbar_doc:save_attachment(UserId, ?PHOTO, Content, Context, Opts).
-
--spec put(cb_context:context()) -> cb_context:context().
-put(Context) ->
- crossbar_doc:save(Context).
-
--spec delete(cb_context:context(), path_token()) -> cb_context:context().
-delete(Context, _Id) ->
- crossbar_doc:delete(Context).
-
--spec patch(cb_context:context(), path_token()) -> cb_context:context().
-patch(Context, Id) ->
- post(Context, Id).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec get_channels(cb_context:context()) -> cb_context:context().
-get_channels(Context) ->
- Realm = kzd_accounts:fetch_realm(cb_context:account_id(Context)),
- Usernames = [Username
- || JObj <- cb_context:doc(Context),
- Username <- [kzd_devices:sip_username(kz_json:get_value(<<"doc">>, JObj))],
- Username =/= undefined
- ],
- Req = [{<<"Realm">>, Realm}
- ,{<<"Usernames">>, Usernames}
- | kz_api:default_headers(?APP_NAME, ?APP_VERSION)
- ],
- case kz_amqp_worker:call_collect(Req
- ,fun kapi_call:publish_query_user_channels_req/1
- ,{'ecallmgr', 'true'}
- )
- of
- {'error', _R} ->
- lager:error("could not reach ecallmgr channels: ~p", [_R]),
- crossbar_util:response('error', <<"could not reach ecallmgr channels">>, Context);
- {_, Resp} ->
- Channels = merge_user_channels_jobjs(Resp),
- crossbar_util:response(Channels, Context)
- end.
-
-%% Card related code should be placed somewhere else.
-%% We also want to extend 'lists' to be vcard-compatible.
-%% And we want to use it for XMPP (for xCards).
--spec convert_to_vcard(cb_context:context()) -> cb_context:context().
-convert_to_vcard(Context) ->
- JObj = cb_context:doc(Context),
- JProfile = kz_json:get_value(<<"profile">>, JObj, kz_json:new()),
- JObj1 = kz_json:merge_jobjs(JObj, JProfile),
- JObj2 = set_photo(JObj1, Context),
- JObj3 = set_org(JObj2, Context),
- %% TODO add SOUND, AGENT (X-ASSISTANT), X-MANAGER
- Fields = [
- <<"BEGIN">>
- ,<<"VERSION">>
- ,<<"FN">>
- ,<<"N">>
- ,<<"ORG">>
- ,<<"PHOTO">>
- ,<<"EMAIL">>
- ,<<"BDAY">>
- ,<<"NOTE">>
- ,<<"TITLE">>
- ,<<"ROLE">>
- ,<<"TZ">>
- ,<<"NICKNAME">>
- ,<<"TEL">>
- ,<<"ADR">>
- ,<<"END">>
- ],
- NotEmptyFields = lists:foldl(fun vcard_fields_acc/2, [], [card_field(Key, JObj3) || Key <- Fields]),
- PackedFields = lists:reverse([iolist_join(<<":">>, [X, Y]) || {X, Y} <- NotEmptyFields]),
- DividedFields = lists:reverse(lists:foldl(fun vcard_field_divide_by_length/2, [], PackedFields)),
- RespData = iolist_join(<<"\n">>, DividedFields),
- cb_context:set_resp_data(Context, [RespData, <<"\n">>]).
-
--spec set_photo(kz_json:object(), cb_context:context()) -> kz_json:object().
-set_photo(JObj, Context) ->
- UserId = kz_doc:id(cb_context:doc(Context)),
- Attach = crossbar_doc:load_attachment(UserId, ?PHOTO, ?TYPE_CHECK_OPTION(kzd_users:type()), Context),
- case cb_context:resp_status(Attach) of
- 'error' -> JObj;
- 'success' ->
- Data = cb_context:resp_data(Attach),
- CT = kz_doc:attachment_content_type(cb_context:doc(Context), ?PHOTO),
- kz_json:set_value(?PHOTO, kz_json:from_list([{CT, Data}]), JObj)
- end.
-
--spec set_org(kz_json:object(), cb_context:context()) -> kz_json:object().
-set_org(JObj, Context) ->
- LoadedContent = crossbar_doc:load(cb_context:account_id(Context)
- ,Context
- ,?TYPE_CHECK_OPTION(kzd_users:type())
- ),
-
- case 'success' =:= cb_context:resp_status(LoadedContent)
- andalso kz_json:get_value(<<"org">>, cb_context:doc(LoadedContent))
- of
- 'false' -> JObj;
- 'undefined' -> JObj;
- Val -> kz_json:set_value(<<"org">>, Val, JObj)
- end.
-
--spec vcard_escape_chars(binary()) -> binary().
-vcard_escape_chars(Val) ->
- Val1 = re:replace(Val, "(:|;|,)", "\\\\&", [global, {return, binary}]),
- re:replace(Val1, "\n", "\\\\n", [global, {return, binary}]).
-
-vcard_fields_acc({_, Val}, Acc) when Val =:= 'undefined'; Val =:= []; Val =:= <<>> ->
- Acc;
-vcard_fields_acc({Type, Val}, Acc) ->
- case vcard_normalize_val(Val) of
- <<>> -> Acc;
- ValN ->
- TypeN = vcard_normalize_type(Type),
- [{TypeN, ValN} | Acc]
- end;
-vcard_fields_acc([X | Rest], Acc) ->
- vcard_fields_acc(Rest, vcard_fields_acc(X, Acc));
-vcard_fields_acc([], Acc) ->
- Acc.
-
--spec vcard_normalize_val(binary() | {char(), kz_term:binaries()}) -> binary().
-vcard_normalize_val({Divider, Vals}) when is_list(Vals) ->
- iolist_join(Divider, [vcard_escape_chars(X) || X <- Vals, X =/= 'undefined', X =/= [], X =/= <<>>]);
-vcard_normalize_val(Val) when is_binary(Val) ->
- vcard_escape_chars(Val).
-
--spec vcard_normalize_type(list() | {kz_term:ne_binary(), kz_term:ne_binary()} | kz_term:ne_binary()) -> kz_term:ne_binary().
-vcard_normalize_type(T) when is_list(T) -> iolist_join(<<";">>, [vcard_normalize_type(X) || X <- T]);
-vcard_normalize_type({T, V}) -> iolist_join(<<"=">>, [T, V]);
-vcard_normalize_type(T) -> T.
-
-%%-spec card_field(kz_term:ne_binary(), kz_json:object()) -> {vcard_type_spec(), vcard_val()}.
-card_field(Key, _)
- when Key =:= <<"BEGIN">> ->
- {Key, <<"VCARD">>};
-card_field(Key, _)
- when Key =:= <<"VERSION">> ->
- {Key, <<"3.0">>};
-card_field(Key, _)
- when Key =:= <<"END">> ->
- {Key, <<"VCARD">>};
-card_field(Key, JObj)
- when Key =:= <<"FN">> ->
- FirstName = kz_json:get_value(<<"first_name">>, JObj),
- LastName = kz_json:get_value(<<"last_name">>, JObj),
- MiddleName = kz_json:get_value(<<"middle_name">>, JObj),
- {Key, iolist_join(<<" ">>, [X || X <- [FirstName, MiddleName, LastName], X =/= undefined, X =/= [], X =/= <<>>])};
-card_field(Key, JObj) when Key =:= <<"N">> ->
- FirstName = kz_json:get_value(<<"first_name">>, JObj),
- LastName = kz_json:get_value(<<"last_name">>, JObj),
- MiddleName = kz_json:get_value(<<"middle_name">>, JObj),
- {Key, {$;, [LastName, FirstName, MiddleName]}};
-card_field(Key, JObj) when Key =:= <<"ORG">> ->
- {Key, element(2, card_field(<<"org">>, JObj))};
-card_field(Key, JObj) when Key =:= <<"PHOTO">> ->
- case card_field(?PHOTO, JObj) of
- {?PHOTO, 'undefined'} -> {Key, 'undefined'};
- {?PHOTO, PhotoJObj} ->
- [{CT, PhotoBin}] = kz_json:to_proplist(PhotoJObj),
- <<"image/jpeg">> = CT,
- TypeType = <<"JPEG">>,
- Data = base64:encode(PhotoBin),
- {[Key, {<<"ENCODING">>, <<"B">>}, {<<"TYPE">>, TypeType}], Data}
- end;
-card_field(Key, JObj) when Key =:= <<"ADR">> ->
- Addresses = kz_json:get_value(<<"addresses">>, JObj, []),
- [{Key, X} || X <- Addresses];
-card_field(Key, JObj) when Key =:= <<"TEL">> ->
- CallerId = kz_json:get_value(<<"caller_id">>, JObj, kz_json:new()),
- Internal = kz_json:get_value(<<"internal">>, CallerId),
- External = kz_json:get_value(<<"external">>, CallerId),
- [
- {Key, Internal}
- ,{Key, External}
- ];
-card_field(Key = <<"EMAIL">>, JObj) ->
- {Key, element(2, card_field(<<"email">>, JObj))};
-card_field(Key = <<"BDAY">>, JObj) ->
- {Key, element(2, card_field(<<"birthday">>, JObj))};
-card_field(Key = <<"NOTE">>, JObj) ->
- {Key, element(2, card_field(<<"note">>, JObj))};
-card_field(Key = <<"TITLE">>, JObj) ->
- {Key, element(2, card_field(<<"title">>, JObj))};
-card_field(Key = <<"ROLE">>, JObj) ->
- {Key, element(2, card_field(<<"role">>, JObj))};
-card_field(Key = <<"TZ">>, JObj) ->
- {Key, element(2, card_field(<<"timezone">>, JObj))};
-card_field(Key = <<"NICKNAME">>, JObj) ->
- Val = case element(2, card_field(<<"nicknames">>, JObj)) of
- 'undefined' -> [];
- V -> V
- end,
- {Key, {$,, Val}};
-card_field(Key, JObj) ->
- {Key, kz_json:get_value(Key, JObj)}.
-
--spec iolist_join(char() | binary(), kz_term:binaries()) -> binary().
-iolist_join(Divider, List) ->
- case lists:foldl(fun iolist_join_acc/2, {Divider, []}, List) of
- {_, [_ | Reversed]} -> iolist_to_binary(lists:reverse(Reversed));
- {_, []} -> <<>>
- end.
-
--spec iolist_join_acc(binary(), {char() | binary(), kz_term:binaries()}) -> {char() | binary(), kz_term:binaries()}.
-iolist_join_acc(E, {Divider, Acc}) ->
- {Divider, [Divider, E | Acc]}.
-
--spec vcard_field_divide_by_length(binary(), kz_term:binaries()) -> kz_term:binaries().
-vcard_field_divide_by_length(<>, Acc) ->
- vcard_field_divide_by_length(Rest, [Row | Acc]);
-vcard_field_divide_by_length(Row, Acc) ->
- [Row | Acc].
-
--spec merge_user_channels_jobjs(kz_json:objects()) -> kz_json:objects().
-merge_user_channels_jobjs(JObjs) ->
- merge_user_channels_jobjs(JObjs, dict:new()).
-
--spec merge_user_channels_jobjs(kz_json:objects(), dict:dict()) -> kz_json:objects().
-merge_user_channels_jobjs([], Dict) ->
- [Channel || {_, Channel} <- dict:to_list(Dict)];
-merge_user_channels_jobjs([JObj|JObjs], Dict) ->
- merge_user_channels_jobjs(JObjs, merge_user_channels_jobj(JObj, Dict)).
-
--spec merge_user_channels_jobj(kz_json:object(), dict:dict()) -> dict:dict().
-merge_user_channels_jobj(JObj, Dict) ->
- lists:foldl(fun merge_user_channels_fold/2, Dict, kz_json:get_value(<<"Channels">>, JObj, [])).
-
--spec merge_user_channels_fold(kz_json:object(), dict:dict()) -> dict:dict().
-merge_user_channels_fold(Channel, D) ->
- UUID = kz_json:get_value(<<"uuid">>, Channel),
- dict:store(UUID, Channel, D).
-
-%%------------------------------------------------------------------------------
-%% @doc Attempt to load list of accounts, each summarized. Or a specific
-%% account summary.
-%% @end
-%%------------------------------------------------------------------------------
--spec load_user_summary(cb_context:context()) -> cb_context:context().
-load_user_summary(Context) ->
- crossbar_doc:load_view(?CB_LIST, [], Context, fun normalize_view_results/2).
-
-%%------------------------------------------------------------------------------
-%% @doc Load a user document from the database
-%% @end
-%%------------------------------------------------------------------------------
--spec load_user(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-load_user(UserId, Context) -> crossbar_doc:load(UserId, Context, ?TYPE_CHECK_OPTION(kzd_users:type())).
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec validate_request(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-validate_request(UserId, Context) ->
- prepare_username(UserId, Context).
-
--spec validate_patch(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-validate_patch(UserId, Context) ->
- crossbar_doc:patch_and_validate(UserId, Context, fun validate_request/2).
-
--spec prepare_username(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-prepare_username(UserId, Context) ->
- JObj = cb_context:req_data(Context),
- case kz_json:get_ne_value(<<"username">>, JObj) of
- 'undefined' -> check_user_name(UserId, Context);
- Username ->
- JObj1 = kz_json:set_value(<<"username">>, kz_term:to_lower_binary(Username), JObj),
- check_user_name(UserId, cb_context:set_req_data(Context, JObj1))
- end.
-
--spec check_user_name(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-check_user_name(UserId, Context) ->
- JObj = cb_context:req_data(Context),
- UserName = kz_json:get_ne_value(<<"username">>, JObj),
- AccountDb = cb_context:account_db(Context),
- case is_username_unique(AccountDb, UserId, UserName) of
- 'true' ->
- lager:debug("user name ~s is unique", [UserName]),
- check_emergency_caller_id(UserId, Context);
- 'false' ->
- lager:error("user name ~s is already in use", [UserName]),
- Msg = kz_json:from_list(
- [{<<"message">>, <<"User name already in use">>}
- ,{<<"cause">>, UserName}
- ]),
- Context1 = cb_context:add_validation_error([<<"username">>], <<"unique">>, Msg, Context),
- check_emergency_caller_id(UserId, Context1)
- end.
-
--spec check_emergency_caller_id(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-check_emergency_caller_id(UserId, Context) ->
- Context1 = crossbar_util:format_emergency_caller_id_number(Context),
- check_user_schema(UserId, Context1).
-
--spec is_username_unique(kz_term:api_binary(), kz_term:api_binary(), kz_term:ne_binary()) -> boolean().
-is_username_unique(AccountDb, UserId, UserName) ->
- ViewOptions = [{'key', UserName}],
- case kz_datamgr:get_results(AccountDb, ?LIST_BY_USERNAME, ViewOptions) of
- {'ok', []} -> 'true';
- {'ok', [JObj|_]} -> kz_doc:id(JObj) =:= UserId;
- _Else ->
- lager:error("error ~p checking view ~p in ~p", [_Else, ?LIST_BY_USERNAME, AccountDb]),
- 'false'
- end.
-
--spec check_user_schema(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-check_user_schema(UserId, Context) ->
- OnSuccess = fun(C) -> on_successful_validation(UserId, C) end,
- cb_context:validate_request_data(<<"users">>, Context, OnSuccess).
-
--spec on_successful_validation(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-on_successful_validation('undefined', Context) ->
- Props = [{<<"pvt_type">>, <<"user">>}],
- maybe_import_credintials('undefined'
- ,cb_context:set_doc(Context
- ,kz_json:set_values(Props, cb_context:doc(Context))
- )
- );
-on_successful_validation(UserId, Context) ->
- maybe_import_credintials(UserId, crossbar_doc:load_merge(UserId, Context, ?TYPE_CHECK_OPTION(kzd_users:type()))).
-
--spec maybe_import_credintials(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-maybe_import_credintials(UserId, Context) ->
- JObj = cb_context:doc(Context),
- case kz_json:get_ne_value(<<"credentials">>, JObj) of
- 'undefined' -> maybe_validate_username(UserId, Context);
- Creds ->
- RemoveKeys = [<<"credentials">>, <<"pvt_sha1_auth">>],
- C = cb_context:set_doc(Context
- ,kz_json:set_value(<<"pvt_md5_auth">>, Creds
- ,kz_json:delete_keys(RemoveKeys, JObj)
- )
- ),
- maybe_validate_username(UserId, C)
- end.
-
--spec maybe_validate_username(kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-maybe_validate_username(UserId, Context) ->
- NewUsername = kz_json:get_ne_value(<<"username">>, cb_context:doc(Context)),
- CurrentUsername = case cb_context:fetch(Context, 'db_doc') of
- 'undefined' -> NewUsername;
- CurrentJObj ->
- kz_json:get_ne_value(<<"username">>, CurrentJObj, NewUsername)
- end,
- case kz_term:is_empty(NewUsername)
- orelse CurrentUsername =:= NewUsername
- orelse username_doc_id(NewUsername, Context)
- of
- %% user name is unchanged
- 'true' -> maybe_rehash_creds(UserId, NewUsername, Context);
- %% updated user name that doesn't exist
- 'undefined' ->
- manditory_rehash_creds(UserId, NewUsername, Context);
- %% updated user name to existing, collect any further errors...
- _Else ->
- Msg = kz_json:from_list(
- [{<<"message">>, <<"User name is not unique for this account">>}
- ,{<<"cause">>, NewUsername}
- ]),
- C = cb_context:add_validation_error(<<"username">>, <<"unique">>, Msg, Context),
- manditory_rehash_creds(UserId, NewUsername, C)
- end.
-
--spec maybe_rehash_creds(kz_term:api_binary(), kz_term:api_binary(), cb_context:context()) -> cb_context:context().
-maybe_rehash_creds(UserId, Username, Context) ->
- case kz_json:get_ne_value(<<"password">>, cb_context:doc(Context)) of
- %% No user name or hash, no creds for you!
- 'undefined' when Username =:= 'undefined' ->
- HashKeys = [<<"pvt_md5_auth">>, <<"pvt_sha1_auth">>],
- cb_context:set_doc(Context, kz_json:delete_keys(HashKeys, cb_context:doc(Context)));
- %% User name without password, creds status quo
- 'undefined' -> Context;
- %% Got a password, hope you also have a user name...
- Password -> rehash_creds(UserId, Username, Password, Context)
- end.
-
--spec manditory_rehash_creds(kz_term:api_binary(), kz_term:api_binary(), cb_context:context()) ->
- cb_context:context().
-manditory_rehash_creds(UserId, Username, Context) ->
- case kz_json:get_ne_value(<<"password">>, cb_context:doc(Context)) of
- 'undefined' ->
- Msg = kz_json:from_list(
- [{<<"message">>, <<"The password must be provided when updating the user name">>}
- ]),
- cb_context:add_validation_error(<<"password">>, <<"required">>, Msg, Context);
- Password -> rehash_creds(UserId, Username, Password, Context)
- end.
-
--spec rehash_creds(kz_term:api_binary(), kz_term:api_binary(), kz_term:ne_binary(), cb_context:context()) ->
- cb_context:context().
-rehash_creds(_UserId, 'undefined', _Password, Context) ->
- Msg = kz_json:from_list(
- [{<<"message">>, <<"The user name must be provided when updating the password">>}
- ]),
- cb_context:add_validation_error(<<"username">>, <<"required">>, Msg, Context);
-rehash_creds(_UserId, Username, Password, Context) ->
- lager:debug("password set on doc, updating hashes for ~s", [Username]),
- {MD5, SHA1} = cb_modules_util:pass_hashes(Username, Password),
- JObj1 = kz_json:set_values([{<<"pvt_md5_auth">>, MD5}
- ,{<<"pvt_sha1_auth">>, SHA1}
- ], cb_context:doc(Context)),
- crossbar_auth:reset_identity_secret(
- cb_context:set_doc(Context, kz_json:delete_key(<<"password">>, JObj1))
- ).
-
-%%------------------------------------------------------------------------------
-%% @doc This function will determine if the username in the request is
-%% unique or belongs to the request being made
-%% @end
-%%------------------------------------------------------------------------------
--spec username_doc_id(kz_term:api_binary(), cb_context:context()) -> kz_term:api_binary().
-username_doc_id(Username, Context) ->
- username_doc_id(Username, Context, cb_context:account_db(Context)).
-username_doc_id(_, _, 'undefined') ->
- 'undefined';
-username_doc_id(Username, Context, _AccountDb) ->
- Username = kz_term:to_lower_binary(Username),
- Context1 = crossbar_doc:load_view(?LIST_BY_USERNAME, [{'key', Username}], Context),
- case cb_context:resp_status(Context1) =:= 'success'
- andalso cb_context:doc(Context1)
- of
- [JObj] -> kz_doc:id(JObj);
- _ -> 'undefined'
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Normalizes the results of a view.
-%% @end
-%%------------------------------------------------------------------------------
--spec(normalize_view_results(kz_json:object(), kz_json:objects()) -> kz_json:objects()).
-normalize_view_results(JObj, Acc) -> [kz_json:get_value(<<"value">>, JObj)|Acc].
diff --git a/applications/crossbar/test/cb_ubiquiti_util_tests.erl b/applications/crossbar/test/cb_ubiquiti_util_tests.erl
deleted file mode 100644
index 0154c51ba59..00000000000
--- a/applications/crossbar/test/cb_ubiquiti_util_tests.erl
+++ /dev/null
@@ -1,45 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2010-2019, 2600Hz
-%%% @doc
-%%% @author James Aimonetti
-%%% @author Karl Anderson
-%%%
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(cb_ubiquiti_util_tests).
-
--include_lib("eunit/include/eunit.hrl").
-
-make_api_token_test() ->
- ProviderId = <<"2600hz">>,
- Secret = <<"f1986434eb540c8c956eb0a21094c38c6f9f12bf">>,
- Salt = <<"966d1579e4c0c324c0d95c266adce307bd1e7e08">>,
- Epoch = 1400080558,
- Expiration = 7200,
- Timestamp = Epoch + Expiration,
-
- ApiToken = <<"1:966d1579e4c0c324c0d95c266adce307bd1e7e08:5373a4ce:edd438990c1fc47a8c780d11fb4bbb0c49b35731">>,
- Generated = cb_ubiquiti_util:make_api_token(ProviderId, Timestamp, Salt, Secret),
-
- ?assertEqual(ApiToken, Generated).
-
-split_api_token_test_() ->
- ProviderId = <<"2600hz">>,
- Secret = <<"f1986434eb540c8c956eb0a21094c38c6f9f12bf">>,
- Salt = <<"966d1579e4c0c324c0d95c266adce307bd1e7e08">>,
- Epoch = 1400080558,
- Expiration = 7200,
- Timestamp = Epoch + Expiration,
- Auth = cb_ubiquiti_util:auth_hash(ProviderId, cb_ubiquiti_util:encode_timestamp(Timestamp), Salt, Secret),
-
- Generated = cb_ubiquiti_util:make_api_token(ProviderId, Timestamp, Salt, Secret),
- {Salt1, Timestamp1, Auth1} = cb_ubiquiti_util:split_api_token(Generated),
-
- [?_assertEqual(Salt, Salt1)
- ,?_assertEqual(Timestamp, Timestamp1)
- ,?_assertEqual(Auth, Auth1)
- ].
diff --git a/applications/konami/doc/transfer.md b/applications/konami/doc/transfer.md
index 93c7048eddd..7a7bdba2bb6 100644
--- a/applications/konami/doc/transfer.md
+++ b/applications/konami/doc/transfer.md
@@ -110,7 +110,7 @@ The *transfer* module requires being used with Metaflow "patterns". In the examp
This requires the cb_channels module to be started: `sup crossbar_maintenance start_module cb_channels`
```json
- POST v1/accounts/{ACCOUNT_ID}/channels/{CALL_ID}
+ POST v2/accounts/{ACCOUNT_ID}/channels/{CALL_ID}
{
"data": {
"action": "transfer",
diff --git a/applications/media_mgr/doc/create_ssl_certs.txt b/applications/media_mgr/doc/create_ssl_certs.txt
index efecbca21ec..70b3a93586b 100644
--- a/applications/media_mgr/doc/create_ssl_certs.txt
+++ b/applications/media_mgr/doc/create_ssl_certs.txt
@@ -90,7 +90,7 @@ Now modify the "media_mgr" doc in the "system_config" database with the followin
Start media_mgr. You can now test your new SSL-enabled APIs via:
-$ curl -v --cacert media_mgr.crt https://api.2600hz.com:8443/v1/accounts
+$ curl -v --cacert media_mgr.crt https://api.2600hz.com:8443/v2/accounts
* About to connect() to api.2600hz.com port 8443 (#0)
* Trying 127.0.0.1... connected
* successfully set certificate verify locations:
@@ -114,7 +114,7 @@ $ curl -v --cacert media_mgr.crt https://api.2600hz.com:8443/v1/accounts
* common name: api.2600hz.com (matched)
* issuer: C=US; ST=California; L=San Francisco; O=2600Hz; CN=api.2600hz.com
* SSL certificate verify ok.
-> GET /v1/accounts HTTP/1.1
+> GET /v2/accounts HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: api.2600hz.com:8443
> Accept: */*
diff --git a/applications/notify/src/notify_voicemail_to_email.erl b/applications/notify/src/notify_voicemail_to_email.erl
index fb162cd6118..f4c32fc3e1b 100644
--- a/applications/notify/src/notify_voicemail_to_email.erl
+++ b/applications/notify/src/notify_voicemail_to_email.erl
@@ -156,7 +156,7 @@ magic_hash(Event) ->
VMBoxId = kz_json:get_value(<<"Voicemail-Box">>, Event),
MessageId = kz_json:get_value(<<"Voicemail-ID">>, Event),
- try list_to_binary([<<"/v1/accounts/">>, AccountId, <<"/vmboxes/">>, VMBoxId
+ try list_to_binary([<<"/v2/accounts/">>, AccountId, <<"/vmboxes/">>, VMBoxId
,<<"/messages/">>, MessageId, <<"/raw">>
])
of
diff --git a/core/kazoo_apps/src/kapps_config.erl b/core/kazoo_apps/src/kapps_config.erl
index 7a61bddbb28..eff32f68aed 100644
--- a/core/kazoo_apps/src/kapps_config.erl
+++ b/core/kazoo_apps/src/kapps_config.erl
@@ -1155,6 +1155,9 @@ fetch_category(Category, 'false') ->
,'undefined'
}
,{<<"stepswitch.cnam">>, <<"cnam">>}
+ ,{{<<"crossbar.local_resources">>, <<"allow_peers">>}
+ ,{<<"crossbar.resources">>, <<"allow_peers">>}
+ }
]).
-spec migrate() -> 'ok'.
diff --git a/core/kazoo_ast/src/cb_api_endpoints.erl b/core/kazoo_ast/src/cb_api_endpoints.erl
index d8d596c9add..a797601c406 100644
--- a/core/kazoo_ast/src/cb_api_endpoints.erl
+++ b/core/kazoo_ast/src/cb_api_endpoints.erl
@@ -762,13 +762,10 @@ path_name(Module) ->
{'match', [<<"ip_auth">>=Name]} -> Name;
{'match', [<<"rates">>=Name]} -> Name;
{'match', [<<"schemas">>=Name]} -> Name;
- {'match', [<<"shared_auth">>=Name]} -> Name;
{'match', [<<"sup">>=Name]} -> Name;
{'match', [<<"system_configs">>=Name]} -> Name;
{'match', [<<"system_status">>=Name]} -> Name;
- {'match', [<<"templates">>=Name]} -> Name;
{'match', [<<"token_auth">>=Name]} -> Name;
- {'match', [<<"ubiquiti_auth">>=Name]} -> Name;
{'match', [<<"user_auth">>=Name]} -> Name;
{'match', [<<"quickcall">>=Name]} -> <>;
{'match', [Name]} -> <>;
@@ -958,10 +955,6 @@ find_methods_in_clause(?FUN_ARGS('content_types_provided_for_domain_attachments'
[kz_binary:join([Type, SubType], <<"/">>)
|| {Type, SubType, _} <- cb_whitelabel:acceptable_content_types()
] ++ Acc;
-find_methods_in_clause(?FUN_ARGS('content_types_provided_for_provisioner', _Args), Acc) ->
- [kz_binary:join([Type, SubType], <<"/">>)
- || {Type, SubType, _} <- cb_global_provisioner_templates:acceptable_content_types()
- ] ++ Acc;
find_methods_in_clause(?FUN_ARGS('content_types_provided_for_vm_download', _Args), Acc) ->
[kz_binary:join([Type, SubType], <<"/">>)
|| {Type, SubType, _} <- cb_vmboxes:acceptable_content_types()
diff --git a/core/kazoo_ast/src/pqc_builder.erl b/core/kazoo_ast/src/pqc_builder.erl
index 055a01fd9f0..9abb6271cba 100644
--- a/core/kazoo_ast/src/pqc_builder.erl
+++ b/core/kazoo_ast/src/pqc_builder.erl
@@ -281,7 +281,6 @@ maybe_remove_version(<>) ->
Split = binary:split(Endpoint, <<"_">>, ['global']),
case lists:last(Split) of
<<"v2">> -> kz_binary:join(lists:droplast(Split), $_);
- <<"v1">> -> kz_binary:join(lists:droplast(Split), $_);
_ -> Endpoint
end.
@@ -329,41 +328,34 @@ process_module(Module) ->
%% @doc these excluded modules are not CRUD-y or deprecated
-spec start_module(module(), acc()) -> acc() | {'skip', acc()}.
start_module('cb_about', Acc) -> {'skip', Acc};
+start_module('cb_access_lists', Acc) -> {'skip', Acc};
+start_module('cb_acdc_call_stats', Acc) -> {'skip', Acc};
+start_module('cb_acls', Acc) -> {'skip', Acc};
+start_module('cb_agents', Acc) -> {'skip', Acc};
+start_module('cb_alerts', Acc) -> {'skip', Acc};
+start_module('cb_allotments', Acc) -> {'skip', Acc};
start_module('cb_api_auth', Acc) -> {'skip', Acc};
start_module('cb_apps_link', Acc) -> {'skip', Acc};
start_module('cb_apps_store', Acc) -> {'skip', Acc};
+start_module('cb_att_handlers_errors', Acc) -> {'skip', Acc};
start_module('cb_auth', Acc) -> {'skip', Acc};
start_module('cb_basic_auth', Acc) -> {'skip', Acc};
start_module('cb_braintree', Acc) -> {'skip', Acc};
-start_module('cb_bulk', Acc) -> {'skip', Acc};
start_module('cb_call_inspector', Acc) -> {'skip', Acc};
+start_module('cb_configs', Acc) -> {'skip', Acc};
start_module('cb_contact_list', Acc) -> {'skip', Acc};
start_module('cb_ip_auth', Acc) -> {'skip', Acc};
-start_module('cb_shared_auth', Acc) -> {'skip', Acc};
+start_module('cb_migrations', Acc) -> {'skip', Acc};
+start_module('cb_multi_factor', Acc) -> {'skip', Acc};
+start_module('cb_presence', Acc) -> {'skip', Acc};
+start_module('cb_quickcall', Acc) -> {'skip', Acc};
+start_module('cb_security', Acc) -> {'skip', Acc};
start_module('cb_sup', Acc) -> {'skip', Acc};
+start_module('cb_system_status', Acc) -> {'skip', Acc};
start_module('cb_token_auth', Acc) -> {'skip', Acc};
-start_module('cb_ubiquiti_auth', Acc) -> {'skip', Acc};
-start_module('cb_user_auth', Acc) -> {'skip', Acc};
-start_module('cb_global_provisioner_templates', Acc) -> {'skip', Acc};
-start_module('cb_local_provisioner_templates', Acc) -> {'skip', Acc};
-start_module('cb_att_handlers_errors', Acc) -> {'skip', Acc};
start_module('cb_token_restrictions', Acc) -> {'skip', Acc};
+start_module('cb_user_auth', Acc) -> {'skip', Acc};
start_module('cb_websockets', Acc) -> {'skip', Acc};
-start_module('cb_system_status', Acc) -> {'skip', Acc};
-start_module('cb_security', Acc) -> {'skip', Acc};
-start_module('cb_quickcall', Acc) -> {'skip', Acc};
-start_module('cb_presence', Acc) -> {'skip', Acc};
-start_module('cb_onboard', Acc) -> {'skip', Acc};
-start_module('cb_multi_factor', Acc) -> {'skip', Acc};
-start_module('cb_migrations', Acc) -> {'skip', Acc};
-start_module('cb_freeswitch', Acc) -> {'skip', Acc};
-start_module('cb_configs', Acc) -> {'skip', Acc};
-start_module('cb_access_lists', Acc) -> {'skip', Acc};
-start_module('cb_acdc_call_stats', Acc) -> {'skip', Acc};
-start_module('cb_acls', Acc) -> {'skip', Acc};
-start_module('cb_agents', Acc) -> {'skip', Acc};
-start_module('cb_alerts', Acc) -> {'skip', Acc};
-start_module('cb_allotments', Acc) -> {'skip', Acc};
start_module(Module, {_MFA, Dict}) ->
{{Module, 'undefined', 0}, Dict}.
diff --git a/core/kazoo_data/src/kzs_util.erl b/core/kazoo_data/src/kzs_util.erl
index 12e07786a73..010d858ebe0 100644
--- a/core/kazoo_data/src/kzs_util.erl
+++ b/core/kazoo_data/src/kzs_util.erl
@@ -44,7 +44,6 @@ db_classification(<<"registrations">>) -> 'deprecated';
db_classification(<<"crossbar%2Fsessions">>) -> 'deprecated';
db_classification(<<"sms">>) -> 'deprecated';
db_classification(<<"cccps">>) -> 'system';
-db_classification(<<"signups">>) -> 'deprecated';
db_classification(?KZ_RATES_DB) -> 'ratedeck';
db_classification(?MATCH_RATEDECK_DB_ENCODED(_)) -> 'ratedeck';
db_classification(?MATCH_RATEDECK_DB_encoded(_)) -> 'ratedeck';
@@ -61,7 +60,6 @@ db_classification(?KZ_AUTH_DB) -> 'system';
db_classification(?KZ_DATA_DB) -> 'system';
db_classification(?KZ_TASKS_DB) -> 'system';
db_classification(?KZ_PENDING_NOTIFY_DB) -> 'system';
-db_classification(?KZ_PROVISIONER_DB) -> 'system'; %% Soon to be deprecated
db_classification(?KZ_ACCOUNTS_DB) -> 'aggregate';
db_classification(?KZ_TOKEN_DB) -> 'aggregate';
db_classification(?KZ_SIP_DB) -> 'aggregate';
diff --git a/core/kazoo_documents/include/kazoo_documents.hrl b/core/kazoo_documents/include/kazoo_documents.hrl
index bd5487e0c2a..5cb46da25cd 100644
--- a/core/kazoo_documents/include/kazoo_documents.hrl
+++ b/core/kazoo_documents/include/kazoo_documents.hrl
@@ -14,7 +14,7 @@
-define(VERSION_1, <<"v1">>).
-define(VERSION_2, <<"v2">>).
--define(VERSION_SUPPORTED, [?VERSION_1, ?VERSION_2]).
+-define(VERSION_SUPPORTED, [?VERSION_2]).
-define(CURRENT_VERSION, ?VERSION_2).
-define(KAZOO_DOCUMENTS_HRL, 'true').
diff --git a/core/kazoo_documents/src/kzd_shared_auth.erl b/core/kazoo_documents/src/kzd_shared_auth.erl
deleted file mode 100644
index f5c5c60a61f..00000000000
--- a/core/kazoo_documents/src/kzd_shared_auth.erl
+++ /dev/null
@@ -1,37 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2010-2019, 2600Hz
-%%% @doc
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(kzd_shared_auth).
-
--export([new/0]).
--export([shared_auth/1, shared_auth/2, set_shared_auth/2]).
-
-
--include("kz_documents.hrl").
-
--type doc() :: kz_json:object().
--export_type([doc/0]).
-
--define(SCHEMA, <<"shared_auth">>).
-
--spec new() -> doc().
-new() ->
- kz_json_schema:default_object(?SCHEMA).
-
--spec shared_auth(doc()) -> kz_term:api_ne_binary().
-shared_auth(Doc) ->
- shared_auth(Doc, 'undefined').
-
--spec shared_auth(doc(), Default) -> kz_term:ne_binary() | Default.
-shared_auth(Doc, Default) ->
- kz_json:get_ne_binary_value([<<"shared_auth">>], Doc, Default).
-
--spec set_shared_auth(doc(), kz_term:ne_binary()) -> doc().
-set_shared_auth(Doc, SharedAuthentication) ->
- kz_json:set_value([<<"shared_auth">>], SharedAuthentication, Doc).
diff --git a/core/kazoo_documents/src/kzd_shared_auth.erl.src b/core/kazoo_documents/src/kzd_shared_auth.erl.src
deleted file mode 100644
index 41df0113745..00000000000
--- a/core/kazoo_documents/src/kzd_shared_auth.erl.src
+++ /dev/null
@@ -1,33 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2010-2019, 2600Hz
-%%% @doc Accessors for `shared_auth' document.
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(kzd_shared_auth).
-
--export([new/0]).
--export([shared_auth/1, shared_auth/2, set_shared_auth/2]).
-
-
--include("kz_documents.hrl").
-
--type doc() :: kz_json:object().
--export_type([doc/0]).
-
--define(SCHEMA, <<"shared_auth">>).
-
--spec new() -> doc().
-new() ->
- kz_json_schema:default_object(?SCHEMA).
-
--spec shared_auth(doc()) -> kz_term:api_ne_binary().
-shared_auth(Doc) ->
- shared_auth(Doc, 'undefined').
-
--spec shared_auth(doc(), Default) -> kz_term:ne_binary() | Default.
-shared_auth(Doc, Default) ->
- kz_json:get_ne_binary_value([<<"shared_auth">>], Doc, Default).
-
--spec set_shared_auth(doc(), kz_term:ne_binary()) -> doc().
-set_shared_auth(Doc, SharedAuthentication) ->
- kz_json:set_value([<<"shared_auth">>], SharedAuthentication, Doc).
diff --git a/core/kazoo_documents/src/kzd_ubiquiti_auth.erl b/core/kazoo_documents/src/kzd_ubiquiti_auth.erl
deleted file mode 100644
index 736c8c013ed..00000000000
--- a/core/kazoo_documents/src/kzd_ubiquiti_auth.erl
+++ /dev/null
@@ -1,50 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2010-2019, 2600Hz
-%%% @doc
-%%% This Source Code Form is subject to the terms of the Mozilla Public
-%%% License, v. 2.0. If a copy of the MPL was not distributed with this
-%%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
-%%%
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(kzd_ubiquiti_auth).
-
--export([new/0]).
--export([password/1, password/2, set_password/2]).
--export([username/1, username/2, set_username/2]).
-
-
--include("kz_documents.hrl").
-
--type doc() :: kz_json:object().
--export_type([doc/0]).
-
--define(SCHEMA, <<"ubiquiti_auth">>).
-
--spec new() -> doc().
-new() ->
- kz_json_schema:default_object(?SCHEMA).
-
--spec password(doc()) -> kz_term:api_ne_binary().
-password(Doc) ->
- password(Doc, 'undefined').
-
--spec password(doc(), Default) -> kz_term:ne_binary() | Default.
-password(Doc, Default) ->
- kz_json:get_ne_binary_value([<<"password">>], Doc, Default).
-
--spec set_password(doc(), kz_term:ne_binary()) -> doc().
-set_password(Doc, Password) ->
- kz_json:set_value([<<"password">>], Password, Doc).
-
--spec username(doc()) -> kz_term:api_ne_binary().
-username(Doc) ->
- username(Doc, 'undefined').
-
--spec username(doc(), Default) -> kz_term:ne_binary() | Default.
-username(Doc, Default) ->
- kz_json:get_ne_binary_value([<<"username">>], Doc, Default).
-
--spec set_username(doc(), kz_term:ne_binary()) -> doc().
-set_username(Doc, Username) ->
- kz_json:set_value([<<"username">>], Username, Doc).
diff --git a/core/kazoo_documents/src/kzd_ubiquiti_auth.erl.src b/core/kazoo_documents/src/kzd_ubiquiti_auth.erl.src
deleted file mode 100644
index af6d6ae8882..00000000000
--- a/core/kazoo_documents/src/kzd_ubiquiti_auth.erl.src
+++ /dev/null
@@ -1,46 +0,0 @@
-%%%-----------------------------------------------------------------------------
-%%% @copyright (C) 2010-2019, 2600Hz
-%%% @doc Accessors for `ubiquiti_auth' document.
-%%% @end
-%%%-----------------------------------------------------------------------------
--module(kzd_ubiquiti_auth).
-
--export([new/0]).
--export([password/1, password/2, set_password/2]).
--export([username/1, username/2, set_username/2]).
-
-
--include("kz_documents.hrl").
-
--type doc() :: kz_json:object().
--export_type([doc/0]).
-
--define(SCHEMA, <<"ubiquiti_auth">>).
-
--spec new() -> doc().
-new() ->
- kz_json_schema:default_object(?SCHEMA).
-
--spec password(doc()) -> kz_term:api_ne_binary().
-password(Doc) ->
- password(Doc, 'undefined').
-
--spec password(doc(), Default) -> kz_term:ne_binary() | Default.
-password(Doc, Default) ->
- kz_json:get_ne_binary_value([<<"password">>], Doc, Default).
-
--spec set_password(doc(), kz_term:ne_binary()) -> doc().
-set_password(Doc, Password) ->
- kz_json:set_value([<<"password">>], Password, Doc).
-
--spec username(doc()) -> kz_term:api_ne_binary().
-username(Doc) ->
- username(Doc, 'undefined').
-
--spec username(doc(), Default) -> kz_term:ne_binary() | Default.
-username(Doc, Default) ->
- kz_json:get_ne_binary_value([<<"username">>], Doc, Default).
-
--spec set_username(doc(), kz_term:ne_binary()) -> doc().
-set_username(Doc, Username) ->
- kz_json:set_value([<<"username">>], Username, Doc).
diff --git a/applications/crossbar/src/modules/phonebook.erl b/core/kazoo_numbers/src/knm_phonebook.erl
similarity index 81%
rename from applications/crossbar/src/modules/phonebook.erl
rename to core/kazoo_numbers/src/knm_phonebook.erl
index 2534593d276..2379f7b3f51 100644
--- a/applications/crossbar/src/modules/phonebook.erl
+++ b/core/kazoo_numbers/src/knm_phonebook.erl
@@ -9,19 +9,24 @@
%%%
%%% @end
%%%-----------------------------------------------------------------------------
--module(phonebook).
+-module(knm_phonebook).
--export([maybe_create_port_in/1
- ,maybe_add_comment/2
+-export([maybe_create_port_in/2
+ ,maybe_add_comment/3
,should_send_to_phonebook/1
]).
--include("crossbar.hrl").
--include_lib("kazoo_numbers/include/knm_port_request.hrl").
-
-define(MOD_CONFIG_CAT, <<"crossbar.phonebook">>).
+-type phonebook_options() :: [{'auth_token', kz_term:ne_binary()} | %% Crossbar auth token
+ {'port_authority_id', kz_term:ne_binary()} |
+ {'master_account_id', kz_term:ne_binary()} |
+ %% Crossbar User-Agent header, to check if request is from project phonebook or not.
+ {'user_agent', kz_term:ne_binary()}
+ ].
+
+
-type req_type() :: 'add_comment' | 'port_in'.
-type reason() :: 'bad_phonebook' | 'bad_http'.
@@ -43,19 +48,19 @@
%% @end
%%------------------------------------------------------------------------------
--spec maybe_create_port_in(cb_context:context()) -> response().
-maybe_create_port_in(Context) ->
- case should_send_to_phonebook(Context) of
+-spec maybe_create_port_in(kz_json:object(), phonebook_options()) -> response().
+maybe_create_port_in(JObj, Options) ->
+ case should_send_to_phonebook(Options) of
'true' ->
- create_port_in(cb_context:doc(Context), cb_context:auth_token(Context));
+ create_port_in(JObj, props:get_value('auth_token', Options));
'false' -> {'ok', 'disabled'}
end.
--spec maybe_add_comment(cb_context:context(), kz_json:objects()) -> response().
-maybe_add_comment(Context, Comment) ->
- case should_send_to_phonebook(Context) of
+-spec maybe_add_comment(kz_json:object(), kz_json:objects(), phonebook_options()) -> response().
+maybe_add_comment(JObj, Comments, Options) ->
+ case should_send_to_phonebook(Options) of
'true' ->
- add_comment(cb_context:doc(Context), cb_context:auth_token(Context), Comment);
+ add_comment(JObj, props:get_value('auth_token', Options), Comments);
'false' -> {'ok', 'disabled'}
end.
@@ -63,22 +68,11 @@ maybe_add_comment(Context, Comment) ->
%% @doc
%% @end
%%------------------------------------------------------------------------------
--spec should_send_to_phonebook(cb_context:context()) -> boolean().
-should_send_to_phonebook(Context) ->
- phonebook_enabled()
- andalso cb_context:fetch(Context, 'port_authority_id') =:= cb_context:master_account_id(Context)
- andalso not req_from_phonebook(Context).
-
--spec phonebook_enabled() -> boolean().
-phonebook_enabled() ->
- kapps_config:get_is_true(?MOD_CONFIG_CAT, <<"enabled">>, 'false').
-
--spec req_from_phonebook(cb_context:context()) -> boolean().
-req_from_phonebook(Context) ->
- case cb_context:req_header(Context, <<"User-Agent">>) of
- <<"phonebook">> -> 'true';
- _ -> 'false'
- end.
+-spec should_send_to_phonebook(phonebook_options()) -> boolean().
+should_send_to_phonebook(Options) ->
+ kapps_config:get_is_true(?MOD_CONFIG_CAT, <<"enabled">>, 'false')
+ andalso props:get_value('port_authority_id', Options) =:= props:get_value('master_account_id', Options)
+ andalso props:get_value('user_agent', Options) =/= <<"phonebook">>.
%%------------------------------------------------------------------------------
%% @doc
diff --git a/core/kazoo_numbers/src/knm_port_request.erl b/core/kazoo_numbers/src/knm_port_request.erl
index 4ca7d59c8de..b09d89860c2 100644
--- a/core/kazoo_numbers/src/knm_port_request.erl
+++ b/core/kazoo_numbers/src/knm_port_request.erl
@@ -706,8 +706,8 @@ maybe_send_request(JObj) ->
end.
-spec maybe_send_request(kz_json:object(), kz_term:api_binary()) -> 'ok'.
-maybe_send_request(JObj, 'undefined') ->
- lager:debug("'submitted_port_requests_url' is not set for account ~s", [kz_doc:account_id(JObj)]);
+maybe_send_request(_, 'undefined') ->
+ 'ok';
maybe_send_request(JObj, Url)->
case send_request(JObj, Url) of
'error' -> 'ok';
diff --git a/core/kazoo_proper/src/pqc_cb_devices_v2.erl b/core/kazoo_proper/src/pqc_cb_devices.erl
similarity index 98%
rename from core/kazoo_proper/src/pqc_cb_devices_v2.erl
rename to core/kazoo_proper/src/pqc_cb_devices.erl
index 51113cab1d2..dbe917c81d9 100644
--- a/core/kazoo_proper/src/pqc_cb_devices_v2.erl
+++ b/core/kazoo_proper/src/pqc_cb_devices.erl
@@ -9,7 +9,7 @@
%%%
%%% @end
%%%-----------------------------------------------------------------------------
--module(pqc_cb_devices_v2).
+-module(pqc_cb_devices).
-export([summary/2]).
-export([create/3]).
@@ -66,7 +66,7 @@ device_url(AccountId, DeviceId) ->
-spec seq() -> 'ok'.
seq() ->
- API = pqc_cb_api:init_api(['crossbar'], ['cb_devices_v2']),
+ API = pqc_cb_api:init_api(['crossbar'], ['cb_devices']),
AccountId = create_account(API),
EmptySummaryResp = summary(API, AccountId),
diff --git a/core/kazoo_proper/src/pqc_cb_lists_v2.erl b/core/kazoo_proper/src/pqc_cb_lists.erl
similarity index 98%
rename from core/kazoo_proper/src/pqc_cb_lists_v2.erl
rename to core/kazoo_proper/src/pqc_cb_lists.erl
index 6fb9160fd1e..dca19f7069d 100644
--- a/core/kazoo_proper/src/pqc_cb_lists_v2.erl
+++ b/core/kazoo_proper/src/pqc_cb_lists.erl
@@ -9,7 +9,7 @@
%%%
%%% @end
%%%-----------------------------------------------------------------------------
--module(pqc_cb_lists_v2).
+-module(pqc_cb_lists).
-export([summary/2]).
-export([create/3]).
@@ -66,7 +66,7 @@ list_url(AccountId, ListId) ->
-spec seq() -> 'ok'.
seq() ->
- API = pqc_cb_api:init_api(['crossbar'], ['cb_lists_v2']),
+ API = pqc_cb_api:init_api(['crossbar'], ['cb_lists']),
AccountId = create_account(API),
EmptySummaryResp = summary(API, AccountId),
diff --git a/core/kazoo_proper/src/pqc_cb_users.erl b/core/kazoo_proper/src/pqc_cb_users.erl
index c7677cc56fa..ac43f51aa05 100644
--- a/core/kazoo_proper/src/pqc_cb_users.erl
+++ b/core/kazoo_proper/src/pqc_cb_users.erl
@@ -123,7 +123,7 @@ user_url(AccountId, UserId) ->
-spec seq() -> 'ok'.
seq() ->
- API = pqc_cb_api:init_api(['crossbar'], ['cb_users_v2']),
+ API = pqc_cb_api:init_api(['crossbar'], ['cb_users']),
AccountId = create_account(API),
'ok' = create_simple_user(API, AccountId),
diff --git a/core/kazoo_proper/src/pqc_cb_users_v2.erl b/core/kazoo_proper/src/pqc_cb_users_v2.erl
index a929c62f4cf..531ef55d036 100644
--- a/core/kazoo_proper/src/pqc_cb_users_v2.erl
+++ b/core/kazoo_proper/src/pqc_cb_users_v2.erl
@@ -66,7 +66,7 @@ user_url(AccountId, UserId) ->
-spec seq() -> 'ok'.
seq() ->
- API = pqc_cb_api:init_api(['crossbar'], ['cb_users_v2']),
+ API = pqc_cb_api:init_api(['crossbar'], ['cb_users']),
AccountId = create_account(API),
EmptySummaryResp = summary(API, AccountId),
diff --git a/core/kazoo_proper/src/pqc_j5_channels.erl b/core/kazoo_proper/src/pqc_j5_channels.erl
index 3e08d8e608c..70f00c365c7 100644
--- a/core/kazoo_proper/src/pqc_j5_channels.erl
+++ b/core/kazoo_proper/src/pqc_j5_channels.erl
@@ -22,7 +22,7 @@
-spec seq() -> 'ok'.
seq() ->
API = pqc_cb_api:init_api(['crossbar', 'jonny5']
- ,['cb_accounts', 'cb_limits_v2']
+ ,['cb_accounts', 'cb_limits']
),
AccountId = create_account(API),
ResellerId = reseller_id(API, AccountId),
diff --git a/core/kazoo_provisioner/src/provisioner_util.erl b/core/kazoo_provisioner/src/provisioner_util.erl
index 1a6066c31f4..bf09607acd0 100644
--- a/core/kazoo_provisioner/src/provisioner_util.erl
+++ b/core/kazoo_provisioner/src/provisioner_util.erl
@@ -86,40 +86,12 @@ ensure_mac_cleansed(DeviceDoc) ->
-spec do_provision_device(kzd_devices:doc(), kzd_devices:doc(), provisioner_options()) -> boolean().
do_provision_device(NewDeviceDoc, OldDeviceDoc, ProvisionerOptions) ->
- MacAddress = kzd_devices:mac_address(NewDeviceDoc),
case get_provisioning_type() of
- <<"super_awesome_provisioner">> ->
- do_full_provision(NewDeviceDoc, OldDeviceDoc, MacAddress);
- <<"awesome_provisioner">> when MacAddress =/= 'undefined' ->
- do_awesome_provision(NewDeviceDoc);
- <<"simple_provisioner">> when MacAddress =/= 'undefined' ->
- do_simple_provision(MacAddress, NewDeviceDoc);
<<"provisioner_v5">> ->
do_provision_v5(NewDeviceDoc, OldDeviceDoc, ProvisionerOptions);
_ -> 'false'
end.
--spec do_full_provision(kzd_devices:doc(), kzd_devices:doc(), kz_term:api_ne_binary()) -> boolean().
-do_full_provision(NewDeviceDoc, OldDeviceDoc, 'undefined') ->
- case kzd_devices:mac_address(OldDeviceDoc) of
- 'undefined' -> 'ok';
- OldMACAddress -> delete_full_provision(OldMACAddress, NewDeviceDoc)
- end,
- 'false';
-do_full_provision(NewDeviceDoc, OldDeviceDoc, MACAddress) ->
- _ = do_full_provisioner_provider(kz_doc:account_id(NewDeviceDoc)),
- _ = full_provision(NewDeviceDoc, OldDeviceDoc, MACAddress),
- 'true'.
-
--spec do_awesome_provision(kzd_devices:doc()) -> boolean().
-do_awesome_provision(NewDeviceDoc) ->
- case get_template(NewDeviceDoc) of
- {'error', _} -> 'false';
- {'ok', Template} ->
- send_provisioning_template(NewDeviceDoc, Template),
- 'true'
- end.
-
-spec do_provision_v5(kzd_devices:doc(), kzd_devices:doc(), provisioner_options()) -> boolean().
do_provision_v5(NewDeviceDoc, _OldDeviceDoc, #{'req_verb' := ?HTTP_PUT
,'auth_token' := AuthToken
@@ -149,16 +121,9 @@ do_provision_v5(NewDevice, OldDevice, #{'req_verb' := ?HTTP_POST
%% @doc
%% @end
%%------------------------------------------------------------------------------
-
-spec delete_provision(kzd_devices:doc(), kz_term:ne_binary()) -> boolean().
delete_provision(NewDeviceDoc, AuthToken) ->
- MACAddress = kzd_devices:mac_address(NewDeviceDoc),
- case MACAddress =/= 'undefined'
- andalso get_provisioning_type()
- of
- <<"super_awesome_provisioner">> ->
- _ = delete_full_provision(MACAddress, NewDeviceDoc),
- 'true';
+ case get_provisioning_type() of
<<"provisioner_v5">> ->
_ = provisioner_v5:delete_device(NewDeviceDoc, AuthToken),
'true';
@@ -186,9 +151,6 @@ maybe_update_account(AccountId, AuthToken, Doc) ->
-spec maybe_delete_account(kz_term:ne_binary(), kz_term:ne_binary()) -> boolean().
maybe_delete_account(AccountId, AuthToken) ->
case get_provisioning_type() of
- <<"super_awesome_provisioner">> ->
- _ = delete_account(AccountId),
- 'true';
<<"provisioner_v5">> ->
_ = provisioner_v5:delete_account(AccountId, AuthToken),
'true';
@@ -196,64 +158,14 @@ maybe_delete_account(AccountId, AuthToken) ->
end.
-spec maybe_send_contact_list(kz_term:ne_binary(), kz_term:ne_binary(), kz_json:object(), kz_json:object()) -> 'ok'.
-maybe_send_contact_list(AccountId, AuthToken, NewDoc, OldDoc) ->
+maybe_send_contact_list(AccountId, AuthToken, NewDoc, _OldDoc) ->
_ = case get_provisioning_type() of
- <<"super_awesome_provisioner">> ->
- do_full_provision_contact_list(AccountId, NewDoc, OldDoc);
<<"provisioner_v5">> ->
provisioner_v5:update_user(AccountId, NewDoc, AuthToken);
_ -> 'ok'
end,
'ok'.
--spec do_full_provisioner_provider(kz_term:ne_binary()) -> boolean().
-do_full_provisioner_provider(AccountId) ->
- do_full_provision_contact_list(AccountId).
-
--spec do_full_provision_contact_list(kz_term:ne_binary()) -> boolean().
-do_full_provision_contact_list(?NE_BINARY = AccountId) ->
- case kzd_accounts:fetch(AccountId) of
- {'ok', JObj} ->
- Routines = [fun kz_doc:public_fields/1
- ,fun(J) ->
- ResellerId = kz_services_reseller:get_id(AccountId),
- kz_json:set_value(<<"provider_id">>, ResellerId, J)
- end
- ,fun(J) -> kz_json:delete_key(<<"available_apps">>, J) end
- ,fun(J) ->
- AccountDb = kz_util:format_account_id(AccountId, 'encoded'),
- ContactList = provisioner_contact_list:build(AccountDb),
- kz_json:set_value(<<"directory">>, ContactList, J)
- end
- ],
- Provider = lists:foldl(fun(F, J) -> F(J) end, JObj, Routines),
- PartialURL = <>,
- maybe_send_to_full_provisioner(PartialURL, Provider);
- {'error', _R} ->
- lager:warning("failed to get account definition for ~s: ~p", [AccountId, _R]),
- 'false'
- end.
-
-do_full_provision_contact_list(AccountId, NewDoc, OldDoc) ->
- case should_build_contact_list(NewDoc, OldDoc) of
- 'true' -> do_full_provision_contact_list(AccountId);
- 'false' -> 'ok'
- end.
-
--spec should_build_contact_list(kz_json:object(), kz_json:objec()) -> boolean().
-should_build_contact_list(JObj, OriginalJObj) ->
- case kz_json:is_json_object(OriginalJObj) of
- 'false' ->
- kz_doc:type(JObj) =:= <<"callflow">>;
- 'true' ->
- kz_doc:type(JObj) =:= <<"callflow">>
- orelse kz_json:get_value(<<"name">>, JObj) =/= kz_json:get_value(<<"name">>, OriginalJObj)
- orelse kz_json:get_value(<<"first_name">>, JObj) =/= kz_json:get_value(<<"first_name">>, OriginalJObj)
- orelse kz_json:get_value(<<"last_name">>, JObj) =/= kz_json:get_value(<<"last_name">>, OriginalJObj)
- orelse kz_json:get_value([<<"contact_list">>, <<"exclude">>], JObj) =/=
- kz_json:get_value([<<"contact_list">>, <<"exclude">>], OriginalJObj)
- end.
-
%%------------------------------------------------------------------------------
%% @doc This doesn't belong here, needs to be in an external library. Make request to
%% get provisioning defaults
@@ -301,351 +213,6 @@ is_mac_address_in_use(MacAddress, AuthToken) ->
_ -> 'false'
end.
-%%------------------------------------------------------------------------------
-%% @doc post data to a provisioning server
-%% @end
-%%------------------------------------------------------------------------------
--spec do_simple_provision(kz_term:ne_binary(), kzd_devices:doc()) -> boolean().
-do_simple_provision(MACAddress, NewDeviceDoc) ->
- do_simple_provision(MACAddress, NewDeviceDoc, kapps_config:get_string(?MOD_CONFIG_CAT, <<"provisioning_url">>)).
-
-do_simple_provision(_MACAddress, _NewDeviceDoc, 'undefined') -> 'false';
-do_simple_provision(MACAddress, NewDeviceDoc, URL) ->
- AccountRealm = kzd_accounts:fetch_realm(kz_doc:account_id(NewDeviceDoc)),
- Body =
- kz_json:from_list(
- [{<<"device[mac]">>, MACAddress}
- ,{<<"device[label]">>, kzd_devices:name(NewDeviceDoc)}
- ,{<<"sip[realm]">>, kzd_devices:sip_realm(NewDeviceDoc, AccountRealm)}
- ,{<<"sip[username]">>, kzd_devices:sip_username(NewDeviceDoc)}
- ,{<<"sip[password]">>, kzd_devices:sip_password(NewDeviceDoc)}
- ,{<<"submit">>, <<"true">>}
- ]),
- Encoded = kz_http_util:json_to_querystring(Body),
- lager:debug("posting to ~s with: ~-300s", [URL, Encoded]),
- _Res = kz_http:post(URL, ?FORM_HEADERS, Encoded),
- lager:debug("response from server: ~p", [_Res]),
- 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc post data to a provisioning server
-%% @end
-%%------------------------------------------------------------------------------
--spec delete_account(kz_term:ne_binary()) -> boolean().
-delete_account(<<_/binary>> = AccountId) ->
- maybe_send_to_full_provisioner(AccountId).
-
--spec delete_full_provision(kz_term:ne_binary(), kzd_devices:doc()) -> boolean().
-delete_full_provision(MACAddress, NewDeviceDoc) ->
- AccountId = kz_doc:account_id(NewDeviceDoc),
- PartialURL = <>,
- maybe_send_to_full_provisioner(PartialURL).
-
--spec full_provision(kzd_devices:doc(), kzd_devices:doc(), kz_term:ne_binary()) -> boolean().
-full_provision(NewDeviceDoc, OldDevice, MACAddress) ->
- {'ok', Data} = get_merged_device(MACAddress, NewDeviceDoc),
- case kzd_devices:mac_address(OldDevice) of
- 'undefined' -> 'ok';
- MACAddress -> 'ok';
- OldMACAddress ->
- delete_full_provision(OldMACAddress, Data)
- end,
-
- AccountId = kz_doc:account_id(NewDeviceDoc),
- PartialURL = <>,
- maybe_send_to_full_provisioner(PartialURL, Data).
-
--spec maybe_send_to_full_provisioner(kz_term:ne_binary()) -> boolean().
-maybe_send_to_full_provisioner(PartialURL) ->
- case kapps_config:get_binary(?MOD_CONFIG_CAT, <<"provisioning_url">>) of
- 'undefined' -> 'false';
- Url ->
- FullUrl = kz_term:to_lower_string(<>),
- send_to_full_provisioner(FullUrl)
- end.
-
--spec maybe_send_to_full_provisioner(kz_term:ne_binary(), kz_json:object()) -> boolean().
-maybe_send_to_full_provisioner(PartialURL, JObj) ->
- case kapps_config:get_binary(?MOD_CONFIG_CAT, <<"provisioning_url">>) of
- 'undefined' -> 'false';
- Url ->
- FullUrl = kz_term:to_lower_string(<>),
- {'ok', _, _, RawJObj} = kz_http:get(FullUrl, ?JSON_HEADERS, [{'timeout', 10 * ?MILLISECONDS_IN_SECOND}]),
- case kz_json:get_integer_value([<<"error">>, <<"code">>], kz_json:decode(RawJObj)) of
- 'undefined' -> send_to_full_provisioner('post', FullUrl, JObj);
- 404 -> send_to_full_provisioner('put', FullUrl, JObj);
- _ -> 'false'
- end
- end.
-
--spec send_to_full_provisioner(string()) -> boolean().
-send_to_full_provisioner(FullUrl) ->
- lager:debug("making ~s request to ~s", ['delete', FullUrl]),
- Res = kz_http:delete(FullUrl, ?JSON_HEADERS, [], [{'timeout', 10 * ?MILLISECONDS_IN_SECOND}]),
- lager:debug("response from server: ~p", [Res]),
- 'true'.
-
--spec send_to_full_provisioner('put' | 'post', string(), kz_json:object()) -> boolean().
-send_to_full_provisioner('put', FullUrl, JObj) ->
- Body = kz_term:to_list(kz_json:encode(JObj)),
- lager:debug("making put request to ~s with: ~-300p", [FullUrl, Body]),
- Res = kz_http:put(FullUrl, ?JSON_HEADERS, Body, [{'timeout', 10 * ?MILLISECONDS_IN_SECOND}]),
- lager:debug("response from server: ~p", [Res]),
- 'true';
-send_to_full_provisioner('post', FullUrl, JObj) ->
- J = kz_json:from_list(
- [{<<"provider_id">>, kz_json:get_value(<<"provider_id">>, JObj)}
- ,{<<"name">>, kz_json:get_value(<<"name">>, JObj)}
- ,{<<"settings">>, JObj}
- ]),
- Body = kz_term:to_list(kz_json:encode(J)),
- lager:debug("making post request to ~s with: ~-300p", [FullUrl, Body]),
- Res = kz_http:post(FullUrl, ?JSON_HEADERS, Body, [{'timeout', 10 * ?MILLISECONDS_IN_SECOND}]),
- lager:debug("response from server: ~p", [Res]),
- 'true'.
-
-%%------------------------------------------------------------------------------
-%% @doc
-%% @end
-%%------------------------------------------------------------------------------
--spec get_merged_device(kz_term:ne_binary(), kzd_devices:doc()) ->
- {'ok', kz_json:object()}.
-get_merged_device(MACAddress, NewDeviceDoc) ->
- {'ok', _Data} = merge_device(MACAddress, NewDeviceDoc).
-
--spec merge_device(kz_term:ne_binary(), kzd_devices:doc()) ->
- {'ok', kz_json:object()}.
-merge_device(MACAddress, NewDeviceDoc) ->
- AccountId = kz_doc:account_id(NewDeviceDoc),
-
- Routines = [fun(J) -> kzd_devices:set_mac_address(J, MACAddress) end
- ,fun(J) ->
- OwnerId = kzd_devices:owner_id(NewDeviceDoc),
- Owner = get_owner(OwnerId, AccountId),
- kz_json:merge(J, Owner)
- end
- ,fun(J) -> kz_json:delete_key(<<"apps">>, J) end
- ,fun(J) -> kz_json:set_value(<<"account_id">>, AccountId, J) end
- ],
- MergedDevice = lists:foldl(fun(F, J) -> F(J) end, NewDeviceDoc, Routines),
- {'ok', kz_doc:public_fields(MergedDevice)}.
-
--spec get_owner(kz_term:api_binary(), kz_term:ne_binary()) -> kz_json:object().
-get_owner('undefined', _) -> kz_json:new();
-get_owner(OwnerId, AccountId) ->
- AccountDb = kz_util:format_account_id(AccountId, 'encoded'),
- case kz_datamgr:open_cache_doc(AccountDb, OwnerId) of
- {'ok', Owner} -> Owner;
- {'error', _R} ->
- lager:debug("unable to open user definition ~s/~s: ~p", [AccountDb, OwnerId, _R]),
- kz_json:new()
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Do awesome provisioning
-%% @end
-%%------------------------------------------------------------------------------
--spec send_provisioning_template(kzd_devices:doc(), kz_json:object()) -> 'ok'.
-send_provisioning_template(NewDeviceDoc, _DeviceTemplate) ->
- %% TODO: theoretically this is the start of multiple line support....
- Line = <<"lineloop|line_1">>,
- MACAddress = kz_term:to_list(kzd_devices:mac_address(NewDeviceDoc, "")),
- MAC = re:replace(MACAddress
- ,"[^0-9a-fA-F]", "", [{'return', 'list'}, 'global']
- ),
- LineGenerators = [fun set_device_line_defaults/1
- ,fun set_account_line_defaults/1
- ],
- TmplGenerators = [fun set_account_id/1
- ,fun set_account_overrides/1
- ,fun set_user_overrides/1
- ,fun set_device_overrides/1
- ,fun set_global_overrides/1
- ],
- LineUpdaters = lists:foldr(fun(F, U) -> F(NewDeviceDoc) ++ U end, [], LineGenerators),
- TmplUpdaters = lists:foldr(fun(F, U) -> F(NewDeviceDoc) ++ U end, [], TmplGenerators),
- DefaultTemplate = lists:foldr(fun(F, J) -> F(J) end, NewDeviceDoc, TmplUpdaters),
- LineLoop = kz_json:get_value([<<"data">>, <<"globals">>, <<"globals">>, Line], DefaultTemplate),
- LineTemplate = lists:foldr(fun(F, J) -> F(J) end, LineLoop, LineUpdaters),
-
- Template = kz_json:set_value([<<"data">>, <<"globals">>, <<"globals">>, Line], LineTemplate, DefaultTemplate),
- send_provisioning_request(Template, MAC).
-
-%%------------------------------------------------------------------------------
-%% @doc If the device specifies a local template id then return that
-%% template
-%% @end
-%%------------------------------------------------------------------------------
--spec get_template(kzd_devices:doc()) ->
- {'ok', kz_json:object()} |
- {'error', any()}.
-get_template(NewDeviceDoc) ->
- get_template(NewDeviceDoc, kzd_devices:provision_id(NewDeviceDoc)).
-
-get_template(NewDeviceDoc, 'undefined') ->
- lager:debug("unknown template id for device ~s", [kz_doc:id(NewDeviceDoc)]),
- {'error', 'not_found'};
-get_template(NewDeviceDoc, TemplateId) ->
- case kz_datamgr:fetch_attachment(kz_doc:account_db(NewDeviceDoc), TemplateId, ?TEMPLATE_ATTCH) of
- {'error', _R}=E ->
- lager:debug("could not fetch template doc ~s: ~p", [TemplateId, _R]),
- E;
- {'ok', Attachment} ->
- {'ok', kz_json:decode(Attachment)}
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc add the account_id to the root of the provisioning json
-%% @end
-%%------------------------------------------------------------------------------
--spec set_account_id(kzd_devices:doc()) ->
- [fun((kz_json:object()) -> kz_json:object()),...].
-set_account_id(_NewDeviceDoc) ->
- [fun(J) ->
- kz_json:set_value(<<"account_id">>, kz_doc:account_id(J), J)
- end
- ].
-
-%%------------------------------------------------------------------------------
-%% @doc get the settings from the account doc that should be used in the
-%% base properties for the line
-%% @end
-%%------------------------------------------------------------------------------
--spec set_account_line_defaults(kzd_devices:doc()) ->
- [fun((kz_json:object()) -> kz_json:object()),...].
-set_account_line_defaults(NewDeviceDoc) ->
- Account = case kzd_accounts:fetch(kz_doc:id(NewDeviceDoc)) of
- {'ok', AccountJObj} -> AccountJObj;
- {'error', _} -> kz_json:new()
- end,
-
- [fun(J) ->
- set_if_defined(J, Account, fun kzd_accounts:realm/1, [<<"server_host">>, <<"value">>])
- end
- ,fun(J) ->
- set_if_defined(J, Account, fun kzd_accounts:name/1, [<<"displayname">>, <<"value">>])
- end
- ].
-
--spec set_if_defined(kz_json:object(), kz_json:object(), fun((kz_json:object()) -> kz_json:api_json_term()), kz_json:path()) -> kz_json:object().
-set_if_defined(Acc, JObj, Getter, SetPath) ->
- case Getter(JObj) of
- 'undefined' -> Acc;
- Value -> kz_json:set_value(SetPath, Value, Acc)
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc get the settings from the device doc that should be used in the
-%% base properties for the line
-%% @end
-%%------------------------------------------------------------------------------
--spec set_device_line_defaults(kzd_devices:doc()) ->
- [fun((kz_json:object()) -> kz_json:object()),...].
-set_device_line_defaults(Device) ->
- [fun(J) ->
- set_if_defined(J, Device, fun kzd_devices:sip_username/1, [<<"authname">>, <<"value">>])
- end
- ,fun(J) ->
- set_if_defined(J, Device, fun kzd_devices:sip_username/1, [<<"username">>, <<"value">>])
- end
- ,fun(J) ->
- set_if_defined(J, Device, fun kzd_devices:sip_password/1, [<<"secret">>, <<"value">>])
- end
- ,fun(J) ->
- set_if_defined(J, Device, fun kzd_devices:sip_realm/1, [<<"server_host">>, <<"value">>])
- end
- ,fun(J) ->
- set_if_defined(J, Device, fun kzd_devices:name/1, [<<"displayname">>, <<"value">>])
- end
- ].
-
-%%------------------------------------------------------------------------------
-%% @doc merge in any overrides from the global provisioning db
-%% @end
-%%------------------------------------------------------------------------------
--spec set_global_overrides(kzd_devices:doc()) ->
- [fun((kz_json:object()) -> kz_json:object()),...].
-set_global_overrides(_) ->
- GlobalDefaults = case kz_datamgr:open_cache_doc(?KZ_PROVISIONER_DB, <<"base_properties">>) of
- {'ok', JObj} -> JObj;
- {'error', _} -> kz_json:new()
- end,
-
- case kz_json:get_json_value(<<"defaults">>, GlobalDefaults) of
- 'undefined' -> [fun kz_term:identity/1];
- Overrides -> [fun(J) -> kz_json:merge(J, Overrides) end]
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc merge in any overrides from the account doc
-%% @end
-%%------------------------------------------------------------------------------
--spec set_account_overrides(kzd_devices:doc()) ->
- [fun((kz_json:object()) -> kz_json:object()),...].
-set_account_overrides(DeviceDoc) ->
- AccountJObj = case kzd_accounts:fetch(kz_doc:account_id(DeviceDoc)) of
- {'ok', JObj} -> JObj;
- {'error', _} -> kz_json:new()
- end,
-
- case kz_json:get_json_value([<<"provision">>, <<"overrides">>], AccountJObj) of
- 'undefined' -> [fun kz_term:identity/1];
- Overrides -> [fun(J) -> kz_json:merge(J, Overrides) end]
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc merge in any overrides from the user doc
-%% @end
-%%------------------------------------------------------------------------------
--spec set_user_overrides(kzd_devices:doc()) ->
- [fun((kz_json:object()) -> kz_json:object()),...].
-set_user_overrides(DeviceDoc) ->
- set_user_overrides(DeviceDoc, kzd_devices:owner_id(DeviceDoc)).
-
-set_user_overrides(_DeviceDoc, 'undefined') ->
- [fun kz_term:identity/1];
-set_user_overrides(DeviceDoc, OwnerId) ->
- set_user_overrides(DeviceDoc, OwnerId, kzd_users:fetch(kz_doc:account_id(DeviceDoc), OwnerId)).
-
-set_user_overrides(_DeviceDoc, _OwnerId, {'error', _}) ->
- [fun kz_term:identity/1];
-set_user_overrides(_DeviceDoc, _OwnerId, {'ok', Owner}) ->
- case kz_json:get_json_value([<<"provision">>, <<"overrides">>], Owner) of
- 'undefined' -> [fun kz_term:identity/1];
- Overrides -> [fun(J) -> kz_json:merge(J, Overrides) end]
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc merge in any overrides from the device doc
-%% @end
-%%------------------------------------------------------------------------------
--spec set_device_overrides(kzd_devices:doc()) ->
- [fun((kz_json:object()) -> kz_json:object()),...].
-set_device_overrides(Device) ->
- case kz_json:get_json_value([<<"provision">>, <<"overrides">>], Device) of
- 'undefined' -> [fun kz_term:identity/1];
- Overrides -> [fun(J) -> kz_json:merge(J, Overrides) end]
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Send awesome provisioning request
-%% @end
-%%------------------------------------------------------------------------------
--spec send_provisioning_request(kz_json:object(), kz_term:ne_binary()) -> 'ok'.
-send_provisioning_request(Template, MACAddress) ->
- ProvisionRequest = kz_json:encode(Template),
- UrlTmpl = kapps_config:get_string(?MOD_CONFIG_CAT, <<"provisioning_url">>),
- UrlString = re:replace(UrlTmpl, "{{mac_address}}", MACAddress, ['global', {'return', 'list'}]),
- lager:debug("provisioning via ~s", [UrlString]),
- case kz_http:post(UrlString, ?JSON_HEADERS, ProvisionRequest) of
- {'ok', 200, _, Response} ->
- lager:debug("SUCCESS! BOOM! ~s", [Response]);
- {'ok', Code, _, Response} ->
- lager:debug("ERROR! OH NO! ~p. ~s", [Code, Response]);
- {'error', R} ->
- lager:debug("ERROR! OH NO! ~p", [R])
- end.
-
%%------------------------------------------------------------------------------
%% @doc
%% @end
diff --git a/core/kazoo_stdlib/include/kz_databases.hrl b/core/kazoo_stdlib/include/kz_databases.hrl
index eb9b270e6e7..efbfc82cd84 100644
--- a/core/kazoo_stdlib/include/kz_databases.hrl
+++ b/core/kazoo_stdlib/include/kz_databases.hrl
@@ -7,7 +7,6 @@
-define(KZ_ACCOUNTS_DB, <<"accounts">>).
-define(KZ_ALERTS_DB, <<"alerts">>).
-define(KZ_RATES_DB, <<"ratedeck">>).
--define(KZ_PROVISIONER_DB, <<"global_provisioner">>).
-define(KZ_FAXES_DB, <<"faxes">>).
-define(KZ_SERVICES_DB, <<"services">>).
-define(KZ_OFFNET_DB, <<"offnet">>).
@@ -43,7 +42,6 @@
,?KZ_SIP_DB
,?KZ_ACCOUNTS_DB
,?KZ_RATES_DB
- ,?KZ_PROVISIONER_DB
,?KZ_FAXES_DB
,?KZ_SERVICES_DB
,?KZ_OFFNET_DB
diff --git a/doc/announcements.md b/doc/announcements.md
index 24ab2971f9c..65a21d2fcaa 100644
--- a/doc/announcements.md
+++ b/doc/announcements.md
@@ -9,10 +9,24 @@ This file will serve as a reference point for upcoming announcements, both of th
The 5.0 release will start Kazoo's official support for OTP 21 ([21.3](http://www.erlang.org/news/127) currently being the preferred version).
1. The big change for Erlang code is the deprecation of using `erlang:get_stacktrace()`. There is a target in the root Makefile `make check_stacktrace` that will update uses of `get_stacktrace()` from `try/catch` clauses. Please ensure any private code is adjusted accordingly.
-
2. Community-supported and deprecated apps will be moved out of Kazoo and into a [kazoo-community](https://github.com/kazoo-community) organization. De-factor maintainers of the community apps have been added to remove 2600Hz from blocking PR and code management for those apps. Tooling will continue to be improved for those apps (and 3rd party apps in general). If you would like to take on a maintainer's role for any of the kazoo-community apps, let us know!
-
3. Dependencies have been re-evaluated, updated, or removed as necessary. Please check that your use of them is still available. We're thinking on how community/private apps can include unique dependencies within themselves without impacting core Kazoo's dependency list.
+4. All Crossbar API version 1 modules are removed. The supported API version is now version 2. Please upgrade your applications, UI or scripts to work with version 2.
+5. These long deprecated and unused Crossbar modules are remove:
+ * `cb_bulk `: Old unused, error prone, and version 1 API. There is no substituted API.
+ * `cb_freeswitch`: Old unused module. There is no substituted API.
+ * `cb_global_provisioner_templates`: Long deprecated and unsupported provisioner, you should use already migrated to the new 2600Hz provisioner.
+ * `cb_local_provisioner_templates`: Long deprecated and unsupported provisioner, you should use already migrated to the new 2600Hz provisioner.
+ * `cb_local_resources`: APIs for `/local_resources` and `/global_resources` are deprecated for along time. Use the new `/resources` API with or without `{ACCOUNT_ID}` for configuring global or local resources instead.
+ * `cb_onboard`: Old unused, error prone modules. There is no substituted API.
+ * `cb_shared_auth`: Old unused module with possible security issues.
+ * `cb_templates`
+ * `cb_ubiquiti_auth` and `cb_ubiquiti_util`
+6. These long deprecated and unsupported provisioner are remove:
+ * `super_awesome_provisioner`
+ * `awesome_provisioner`
+ * `simple_provisioner`
+ * Database `global_provisioner` used by these provisioners are remove.
5. Kazoo Number Manager core application has been renamed to `kazoo_numbers`. This should be almost transparent to the client users. Applications not included in KAZOO repo should do this rename if they are depending on knm app or include one of its header files. `scripts/kz_diaspora.bash` script has been updated to do this rename.
@@ -32,6 +46,8 @@ The old `save/2` took an updater function and tried to save the result. Because
4. New parameters were added to the account, user and device documents to set the asserted identity. These parameters are currently free-form but will be strictly verified by default in the future!
+5. Crossbar API version 1 has been deprecated. This is the last major version of Kazoo with support of `v1`. Please consider migrating your customize Crossbar modules from version 1 to version 2. Also upgrade your applications, UI or scripts to use version 2. This is the last version of Kazoo which is deprecated Kazoo-UI works with.
+
### 4.2
1. Erlang Version Support
diff --git a/doc/mkdocs/commercial.yml b/doc/mkdocs/commercial.yml
index c7641244294..b077d2fbccd 100644
--- a/doc/mkdocs/commercial.yml
+++ b/doc/mkdocs/commercial.yml
@@ -30,9 +30,7 @@ pages:
# - 'applications/crossbar/doc/ip_auth.md' ##
# - 'Adding Multi-factor': 'applications/crossbar/doc/multi_factor.md'
# - 'applications/crossbar/doc/security.md'
-# - 'applications/crossbar/doc/shared_auth.md' ##
# - 'applications/crossbar/doc/token_auth.md'
-# - 'applications/crossbar/doc/ubiquiti_auth.md'
# - 'applications/crossbar/doc/user_authentication.md'
- 'System Preparation':
@@ -180,9 +178,7 @@ pages:
# - 'applications/crossbar/doc/ip_auth.md' ##
- 'Adding Multi-factor': 'applications/crossbar/doc/multi_factor.md'
- 'applications/crossbar/doc/security.md'
-# - 'applications/crossbar/doc/shared_auth.md' ##
# - 'applications/crossbar/doc/token_auth.md'
-# - 'applications/crossbar/doc/ubiquiti_auth.md'
- 'applications/crossbar/doc/user_authentication.md'
- 'Advanced System Configuration':
@@ -316,15 +312,6 @@ pages:
# - 'applications/crossbar/doc/system_configs.md'
# - 'applications/crossbar/doc/tasks.md'
# - 'applications/crossbar/doc/token_restrictions.md'
-# - 'Deprecated':
-# - 'applications/crossbar/doc/bulk.md'
-# - 'applications/crossbar/doc/global_provisioner_templates.md'
-# - 'applications/crossbar/doc/local_provisioner_templates.md'
-# - 'applications/crossbar/doc/onboard.md'
-# - 'applications/crossbar/doc/onboarding.md'
-# - 'applications/crossbar/doc/signup.md'
-# - 'applications/crossbar/doc/templates.md'
-
# - 'System Status':
# - 'applications/crossbar/doc/about.md'
# - 'applications/crossbar/doc/acls.md' ##
diff --git a/doc/mkdocs/integrator.yml b/doc/mkdocs/integrator.yml
index 90beecdc421..5bb896afb7f 100644
--- a/doc/mkdocs/integrator.yml
+++ b/doc/mkdocs/integrator.yml
@@ -18,9 +18,7 @@ pages:
- 'API': 'applications/crossbar/doc/multi_factor.md'
- 'Backend': 'core/kazoo_auth/doc/multi_factor.md'
- 'applications/crossbar/doc/security.md'
- - 'applications/crossbar/doc/shared_auth.md'
- 'applications/crossbar/doc/token_auth.md'
- - 'applications/crossbar/doc/ubiquiti_auth.md'
- 'applications/crossbar/doc/user_authentication.md'
- 'Account Management':
- 'applications/crossbar/doc/accounts.md'
@@ -51,7 +49,6 @@ pages:
- 'applications/crossbar/doc/media.md'
- 'Misc':
- 'applications/crossbar/doc/comments.md'
- - 'applications/crossbar/doc/freeswitch.md'
- 'applications/crossbar/doc/lists.md'
- 'PBX Features':
- 'applications/crossbar/doc/blacklists.md'
@@ -107,14 +104,6 @@ pages:
- 'applications/crossbar/doc/system_configs.md'
- 'applications/crossbar/doc/tasks.md'
- 'applications/crossbar/doc/token_restrictions.md'
- - 'Deprecated':
- - 'applications/crossbar/doc/bulk.md'
- - 'applications/crossbar/doc/global_provisioner_templates.md'
- - 'applications/crossbar/doc/local_provisioner_templates.md'
- - 'applications/crossbar/doc/onboard.md'
- - 'applications/crossbar/doc/onboarding.md'
- - 'applications/crossbar/doc/signup.md'
- - 'applications/crossbar/doc/templates.md'
- 'Integrations':
- 'Pivot':
- 'Intro': 'applications/pivot/doc/README.md'
diff --git a/doc/mkdocs/mkdocs.yml b/doc/mkdocs/mkdocs.yml
index e5ad424c9f0..3b870c781c9 100644
--- a/doc/mkdocs/mkdocs.yml
+++ b/doc/mkdocs/mkdocs.yml
@@ -18,9 +18,7 @@ pages:
- 'applications/crossbar/doc/ip_auth.md'
- 'Adding Multi-factor': 'applications/crossbar/doc/multi_factor.md'
- 'applications/crossbar/doc/security.md'
- - 'applications/crossbar/doc/shared_auth.md'
- 'applications/crossbar/doc/token_auth.md'
- - 'applications/crossbar/doc/ubiquiti_auth.md'
- 'applications/crossbar/doc/user_authentication.md'
- 'Account Management':
- 'applications/crossbar/doc/accounts.md'
@@ -49,7 +47,6 @@ pages:
- 'applications/crossbar/doc/media.md'
- 'Misc':
- 'applications/crossbar/doc/comments.md'
- - 'applications/crossbar/doc/freeswitch.md'
- 'applications/crossbar/doc/lists.md'
- 'PBX Features':
- 'applications/crossbar/doc/blacklists.md'
@@ -109,14 +106,6 @@ pages:
- 'applications/crossbar/doc/system_status.md'
- 'applications/crossbar/doc/tasks.md'
- 'applications/crossbar/doc/token_restrictions.md'
- - 'Deprecated':
- - 'applications/crossbar/doc/bulk.md'
- - 'applications/crossbar/doc/global_provisioner_templates.md'
- - 'applications/crossbar/doc/local_provisioner_templates.md'
- - 'applications/crossbar/doc/onboard.md'
- - 'applications/crossbar/doc/onboarding.md'
- - 'applications/crossbar/doc/signup.md'
- - 'applications/crossbar/doc/templates.md'
- 'Integrations':
- 'Pivot':
- 'Intro': 'applications/pivot/doc/README.md'
diff --git a/scripts/README.md b/scripts/README.md
index 15aaaf3da94..c760f72cd11 100644
--- a/scripts/README.md
+++ b/scripts/README.md
@@ -593,6 +593,7 @@ Searches for undocumented APIs and reports percentage of doc coverage.
./scripts/state-of-docs.py
```
+```
Undocumented API endpoints:
> DELETE /v2/templates/{TEMPLATE_NAME}
> PUT /v2/templates/{TEMPLATE_NAME}
@@ -600,177 +601,10 @@ Searches for undocumented APIs and reports percentage of doc coverage.
> GET /v2/accounts/{ACCOUNT_ID}/agents
> GET /v2/accounts/{ACCOUNT_ID}/agents/stats
> GET /v2/accounts/{ACCOUNT_ID}/agents/status
- > POST /v2/accounts/{ACCOUNT_ID}/agents/status/{USER_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/agents/status/{USER_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/agents/{USER_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/agents/{USER_ID}/queue_status
- > POST /v2/accounts/{ACCOUNT_ID}/agents/{USER_ID}/queue_status
- > GET /v2/accounts/{ACCOUNT_ID}/agents/{USER_ID}/status
- > POST /v2/accounts/{ACCOUNT_ID}/agents/{USER_ID}/status
- > GET /v2/accounts/{ACCOUNT_ID}/alerts
- > PUT /v2/accounts/{ACCOUNT_ID}/alerts
- > DELETE /v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/blacklists
- > PUT /v2/accounts/{ACCOUNT_ID}/blacklists
- > GET /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
- > PATCH /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/bulk
- > POST /v2/accounts/{ACCOUNT_ID}/bulk
- > PUT /v2/accounts/{ACCOUNT_ID}/cccps
- > PUT /v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/cdrs/summary
- > PUT /v2/accounts/{ACCOUNT_ID}/clicktocall
- > PATCH /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/connect
- > POST /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/connect
- > GET /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/history
- > GET /v2/accounts/{ACCOUNT_ID}/conferences
- > PUT /v2/accounts/{ACCOUNT_ID}/conferences
- > PATCH /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants
- > GET /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}
- > PATCH /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
- > PUT /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
- > PUT /v2/accounts/{ACCOUNT_ID}/connectivity
- > DELETE /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
- > PATCH /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
- > PUT /v2/accounts/{ACCOUNT_ID}/directories
- > POST /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}
- > PATCH /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/faxboxes
- > PUT /v2/accounts/{ACCOUNT_ID}/faxboxes
- > DELETE /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
- > PATCH /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
- > PUT /v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/freeswitch
- > PUT /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
- > GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
- > GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
- > GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
- > DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
- > GET /v2/accounts/{ACCOUNT_ID}/hotdesks
- > GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
- > PUT /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
- > GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
- > POST /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
- > DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
- > GET /v2/accounts/{ACCOUNT_ID}/menus
- > PUT /v2/accounts/{ACCOUNT_ID}/menus
- > PATCH /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/metaflows
- > DELETE /v2/accounts/{ACCOUNT_ID}/metaflows
- > POST /v2/accounts/{ACCOUNT_ID}/metaflows
- > PUT /v2/accounts/{ACCOUNT_ID}/onboard
- > GET /v2/accounts/{ACCOUNT_ID}/parked_calls
- > POST /v2/accounts/{ACCOUNT_ID}/presence
- > GET /v2/accounts/{ACCOUNT_ID}/presence/report-{REPORT_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/presence/{EXTENSION}
- > PUT /v2/accounts/{ACCOUNT_ID}/queues/eavesdrop
- > PUT /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/eavesdrop
- > POST /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster
- > GET /v2/accounts/{ACCOUNT_ID}/rate_limits
- > DELETE /v2/accounts/{ACCOUNT_ID}/rate_limits
- > POST /v2/accounts/{ACCOUNT_ID}/rate_limits
- > GET /v2/accounts/{ACCOUNT_ID}/resource_selectors
- > GET /v2/accounts/{ACCOUNT_ID}/resource_selectors/name/{SELECTOR_NAME}/resource/{RESOURCE_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/resource_selectors/rules
- > POST /v2/accounts/{ACCOUNT_ID}/resource_selectors/rules
- > DELETE /v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID}
- > GET /v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID}
- > POST /v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID}
- > PUT /v2/accounts/{ACCOUNT_ID}/resource_templates
- > GET /v2/accounts/{ACCOUNT_ID}/resource_templates
- > POST /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
- > PATCH /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/service_plans/reconciliation
- > POST /v2/accounts/{ACCOUNT_ID}/service_plans/synchronization
- > GET /v2/accounts/{ACCOUNT_ID}/services/plan
- > POST /v2/accounts/{ACCOUNT_ID}/services/status
- > GET /v2/accounts/{ACCOUNT_ID}/services/status
- > PUT /v2/accounts/{ACCOUNT_ID}/signup
- > POST /v2/accounts/{ACCOUNT_ID}/signup/{THING}
- > PUT /v2/accounts/{ACCOUNT_ID}/sms
- > GET /v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID}
- > PATCH /v2/accounts/{ACCOUNT_ID}/storage
- > DELETE /v2/accounts/{ACCOUNT_ID}/storage
- > PUT /v2/accounts/{ACCOUNT_ID}/storage
- > POST /v2/accounts/{ACCOUNT_ID}/storage
- > PUT /v2/accounts/{ACCOUNT_ID}/storage/plans
- > GET /v2/accounts/{ACCOUNT_ID}/storage/plans
- > PATCH /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
- > POST /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}/output
- > PUT /v2/accounts/{ACCOUNT_ID}/temporal_rules
- > POST /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
- > GET /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
- > DELETE /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
- > PATCH /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
- > PUT /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets
- > GET /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets
- > POST /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
- > PATCH /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
- > GET /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
- > DELETE /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
- > DELETE /v2/accounts/{ACCOUNT_ID}/whitelabel
- > PUT /v2/accounts/{ACCOUNT_ID}/whitelabel
- > POST /v2/accounts/{ACCOUNT_ID}/whitelabel
- > GET /v2/accounts/{ACCOUNT_ID}/whitelabel
- > POST /v2/accounts/{ACCOUNT_ID}/whitelabel/icon
- > GET /v2/accounts/{ACCOUNT_ID}/whitelabel/icon
- > POST /v2/accounts/{ACCOUNT_ID}/whitelabel/logo
- > GET /v2/accounts/{ACCOUNT_ID}/whitelabel/logo
- > POST /v2/accounts/{ACCOUNT_ID}/whitelabel/welcome
- > GET /v2/accounts/{ACCOUNT_ID}/whitelabel/welcome
- > GET /v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}
- > GET /v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/icon
- > GET /v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/logo
- > GET /v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/welcome
> GET /v2/sup/{MODULE}/{FUNCTION}
> GET /v2/sup/{MODULE}/{FUNCTION}/{ARGS}
> DELETE /v2/auth/links
- > GET /v2/about
- > GET /v2/auth/links
- > GET /v2/auth/tokeninfo
- > GET /v2/templates
- > POST /v2/auth/links
- > PUT /v2/auth/authorize
- > PUT /v2/auth/callback
- > PUT /v2/ip_auth
- > PUT /v2/shared_auth
-
+....
349 / 526 ( 66% documented )
Documented but not matching any allowed_method:
@@ -780,22 +614,7 @@ Searches for undocumented APIs and reports percentage of doc coverage.
> PATCH /v2/accounts/{ACCOUNT_ID}/descendants/webhooks
> DELETE /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists
> GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/channels
- > GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/cdrs
- > GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/channels
- > GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/devices
- > GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/recordings
- > GET /v1/accounts
- > GET /v2/channels
- > GET /v2/notifications
- > GET /v2/phone_numbers
- > GET /v2/resource_selectors/rules
- > GET /v2/search
- > GET /v2/search/multi
- > GET /v2/tasks
- > GET /v2/webhooks
- > GET /v2/websockets
- > POST /v2/resource_selectors/rules
- > POST /v2/whitelabel/domains
+```
## state-of-edoc.escript