diff --git a/db/jambones-sql.sql b/db/jambones-sql.sql
index e450a4a..e502bd1 100644
--- a/db/jambones-sql.sql
+++ b/db/jambones-sql.sql
@@ -8,6 +8,8 @@ DROP TABLE IF EXISTS account_products;
DROP TABLE IF EXISTS account_subscriptions;
+DROP TABLE IF EXISTS account_limits;
+
DROP TABLE IF EXISTS beta_invite_codes;
DROP TABLE IF EXISTS call_routes;
@@ -38,6 +40,8 @@ DROP TABLE IF EXISTS ms_teams_tenants;
DROP TABLE IF EXISTS signup_history;
+DROP TABLE IF EXISTS service_provider_limits;
+
DROP TABLE IF EXISTS smpp_addresses;
DROP TABLE IF EXISTS speech_credentials;
@@ -88,6 +92,15 @@ pending_reason VARBINARY(52),
PRIMARY KEY (account_subscription_sid)
);
+CREATE TABLE account_limits
+(
+account_limits_sid CHAR(36) NOT NULL UNIQUE ,
+account_sid CHAR(36) NOT NULL,
+category ENUM('api_rate','voice_call_session', 'device') NOT NULL,
+quantity INTEGER NOT NULL,
+PRIMARY KEY (account_limits_sid)
+);
+
CREATE TABLE beta_invite_codes
(
invite_code CHAR(6) NOT NULL UNIQUE ,
@@ -236,6 +249,15 @@ signed_up_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (email)
);
+CREATE TABLE service_provider_limits
+(
+service_provider_limits_sid CHAR(36) NOT NULL UNIQUE ,
+service_provider_sid CHAR(36) NOT NULL,
+category ENUM('api_rate','voice_call_session', 'device') NOT NULL,
+quantity INTEGER NOT NULL,
+PRIMARY KEY (service_provider_limits_sid)
+);
+
CREATE TABLE smpp_addresses
(
smpp_address_sid CHAR(36) NOT NULL UNIQUE ,
@@ -434,14 +456,17 @@ CREATE INDEX account_subscription_sid_idx ON account_subscriptions (account_subs
CREATE INDEX account_sid_idx ON account_subscriptions (account_sid);
ALTER TABLE account_subscriptions ADD FOREIGN KEY account_sid_idxfk_1 (account_sid) REFERENCES accounts (account_sid);
+CREATE INDEX account_sid_idx ON account_limits (account_sid);
+ALTER TABLE account_limits ADD FOREIGN KEY account_sid_idxfk_2 (account_sid) REFERENCES accounts (account_sid) ON DELETE CASCADE;
+
CREATE INDEX invite_code_idx ON beta_invite_codes (invite_code);
CREATE INDEX call_route_sid_idx ON call_routes (call_route_sid);
-ALTER TABLE call_routes ADD FOREIGN KEY account_sid_idxfk_2 (account_sid) REFERENCES accounts (account_sid);
+ALTER TABLE call_routes ADD FOREIGN KEY account_sid_idxfk_3 (account_sid) REFERENCES accounts (account_sid);
ALTER TABLE call_routes ADD FOREIGN KEY application_sid_idxfk (application_sid) REFERENCES applications (application_sid);
CREATE INDEX dns_record_sid_idx ON dns_records (dns_record_sid);
-ALTER TABLE dns_records ADD FOREIGN KEY account_sid_idxfk_3 (account_sid) REFERENCES accounts (account_sid);
+ALTER TABLE dns_records ADD FOREIGN KEY account_sid_idxfk_4 (account_sid) REFERENCES accounts (account_sid);
CREATE INDEX predefined_carrier_sid_idx ON predefined_carriers (predefined_carrier_sid);
CREATE INDEX predefined_sip_gateway_sid_idx ON predefined_sip_gateways (predefined_sip_gateway_sid);
@@ -461,14 +486,14 @@ ALTER TABLE account_products ADD FOREIGN KEY product_sid_idxfk (product_sid) REF
CREATE INDEX account_offer_sid_idx ON account_offers (account_offer_sid);
CREATE INDEX account_sid_idx ON account_offers (account_sid);
-ALTER TABLE account_offers ADD FOREIGN KEY account_sid_idxfk_4 (account_sid) REFERENCES accounts (account_sid);
+ALTER TABLE account_offers ADD FOREIGN KEY account_sid_idxfk_5 (account_sid) REFERENCES accounts (account_sid);
CREATE INDEX product_sid_idx ON account_offers (product_sid);
ALTER TABLE account_offers ADD FOREIGN KEY product_sid_idxfk_1 (product_sid) REFERENCES products (product_sid);
CREATE INDEX api_key_sid_idx ON api_keys (api_key_sid);
CREATE INDEX account_sid_idx ON api_keys (account_sid);
-ALTER TABLE api_keys ADD FOREIGN KEY account_sid_idxfk_5 (account_sid) REFERENCES accounts (account_sid);
+ALTER TABLE api_keys ADD FOREIGN KEY account_sid_idxfk_6 (account_sid) REFERENCES accounts (account_sid);
CREATE INDEX service_provider_sid_idx ON api_keys (service_provider_sid);
ALTER TABLE api_keys ADD FOREIGN KEY service_provider_sid_idxfk (service_provider_sid) REFERENCES service_providers (service_provider_sid);
@@ -482,41 +507,44 @@ ALTER TABLE sbc_addresses ADD FOREIGN KEY service_provider_sid_idxfk_1 (service_
CREATE INDEX ms_teams_tenant_sid_idx ON ms_teams_tenants (ms_teams_tenant_sid);
ALTER TABLE ms_teams_tenants ADD FOREIGN KEY service_provider_sid_idxfk_2 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
-ALTER TABLE ms_teams_tenants ADD FOREIGN KEY account_sid_idxfk_6 (account_sid) REFERENCES accounts (account_sid);
+ALTER TABLE ms_teams_tenants ADD FOREIGN KEY account_sid_idxfk_7 (account_sid) REFERENCES accounts (account_sid);
ALTER TABLE ms_teams_tenants ADD FOREIGN KEY application_sid_idxfk_1 (application_sid) REFERENCES applications (application_sid);
CREATE INDEX tenant_fqdn_idx ON ms_teams_tenants (tenant_fqdn);
CREATE INDEX email_idx ON signup_history (email);
+CREATE INDEX service_provider_sid_idx ON service_provider_limits (service_provider_sid);
+ALTER TABLE service_provider_limits ADD FOREIGN KEY service_provider_sid_idxfk_3 (service_provider_sid) REFERENCES service_providers (service_provider_sid) ON DELETE CASCADE;
+
CREATE INDEX smpp_address_sid_idx ON smpp_addresses (smpp_address_sid);
CREATE INDEX service_provider_sid_idx ON smpp_addresses (service_provider_sid);
-ALTER TABLE smpp_addresses ADD FOREIGN KEY service_provider_sid_idxfk_3 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
+ALTER TABLE smpp_addresses ADD FOREIGN KEY service_provider_sid_idxfk_4 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
CREATE UNIQUE INDEX speech_credentials_idx_1 ON speech_credentials (vendor,account_sid);
CREATE INDEX speech_credential_sid_idx ON speech_credentials (speech_credential_sid);
CREATE INDEX service_provider_sid_idx ON speech_credentials (service_provider_sid);
-ALTER TABLE speech_credentials ADD FOREIGN KEY service_provider_sid_idxfk_4 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
+ALTER TABLE speech_credentials ADD FOREIGN KEY service_provider_sid_idxfk_5 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
CREATE INDEX account_sid_idx ON speech_credentials (account_sid);
-ALTER TABLE speech_credentials ADD FOREIGN KEY account_sid_idxfk_7 (account_sid) REFERENCES accounts (account_sid);
+ALTER TABLE speech_credentials ADD FOREIGN KEY account_sid_idxfk_8 (account_sid) REFERENCES accounts (account_sid);
CREATE INDEX user_sid_idx ON users (user_sid);
CREATE INDEX email_idx ON users (email);
CREATE INDEX phone_idx ON users (phone);
CREATE INDEX account_sid_idx ON users (account_sid);
-ALTER TABLE users ADD FOREIGN KEY account_sid_idxfk_8 (account_sid) REFERENCES accounts (account_sid);
+ALTER TABLE users ADD FOREIGN KEY account_sid_idxfk_9 (account_sid) REFERENCES accounts (account_sid);
CREATE INDEX service_provider_sid_idx ON users (service_provider_sid);
-ALTER TABLE users ADD FOREIGN KEY service_provider_sid_idxfk_5 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
+ALTER TABLE users ADD FOREIGN KEY service_provider_sid_idxfk_6 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
CREATE INDEX email_activation_code_idx ON users (email_activation_code);
CREATE INDEX voip_carrier_sid_idx ON voip_carriers (voip_carrier_sid);
CREATE INDEX account_sid_idx ON voip_carriers (account_sid);
-ALTER TABLE voip_carriers ADD FOREIGN KEY account_sid_idxfk_9 (account_sid) REFERENCES accounts (account_sid);
+ALTER TABLE voip_carriers ADD FOREIGN KEY account_sid_idxfk_10 (account_sid) REFERENCES accounts (account_sid);
CREATE INDEX service_provider_sid_idx ON voip_carriers (service_provider_sid);
-ALTER TABLE voip_carriers ADD FOREIGN KEY service_provider_sid_idxfk_6 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
+ALTER TABLE voip_carriers ADD FOREIGN KEY service_provider_sid_idxfk_7 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
ALTER TABLE voip_carriers ADD FOREIGN KEY application_sid_idxfk_2 (application_sid) REFERENCES applications (application_sid);
@@ -529,12 +557,12 @@ CREATE INDEX number_idx ON phone_numbers (number);
CREATE INDEX voip_carrier_sid_idx ON phone_numbers (voip_carrier_sid);
ALTER TABLE phone_numbers ADD FOREIGN KEY voip_carrier_sid_idxfk_1 (voip_carrier_sid) REFERENCES voip_carriers (voip_carrier_sid);
-ALTER TABLE phone_numbers ADD FOREIGN KEY account_sid_idxfk_10 (account_sid) REFERENCES accounts (account_sid);
+ALTER TABLE phone_numbers ADD FOREIGN KEY account_sid_idxfk_11 (account_sid) REFERENCES accounts (account_sid);
ALTER TABLE phone_numbers ADD FOREIGN KEY application_sid_idxfk_3 (application_sid) REFERENCES applications (application_sid);
CREATE INDEX service_provider_sid_idx ON phone_numbers (service_provider_sid);
-ALTER TABLE phone_numbers ADD FOREIGN KEY service_provider_sid_idxfk_7 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
+ALTER TABLE phone_numbers ADD FOREIGN KEY service_provider_sid_idxfk_8 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
CREATE INDEX sip_gateway_idx_hostport ON sip_gateways (ipv4,port);
@@ -550,10 +578,10 @@ CREATE UNIQUE INDEX applications_idx_name ON applications (account_sid,name);
CREATE INDEX application_sid_idx ON applications (application_sid);
CREATE INDEX service_provider_sid_idx ON applications (service_provider_sid);
-ALTER TABLE applications ADD FOREIGN KEY service_provider_sid_idxfk_8 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
+ALTER TABLE applications ADD FOREIGN KEY service_provider_sid_idxfk_9 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
CREATE INDEX account_sid_idx ON applications (account_sid);
-ALTER TABLE applications ADD FOREIGN KEY account_sid_idxfk_11 (account_sid) REFERENCES accounts (account_sid);
+ALTER TABLE applications ADD FOREIGN KEY account_sid_idxfk_12 (account_sid) REFERENCES accounts (account_sid);
ALTER TABLE applications ADD FOREIGN KEY call_hook_sid_idxfk (call_hook_sid) REFERENCES webhooks (webhook_sid);
@@ -569,7 +597,7 @@ ALTER TABLE service_providers ADD FOREIGN KEY registration_hook_sid_idxfk (regis
CREATE INDEX account_sid_idx ON accounts (account_sid);
CREATE INDEX sip_realm_idx ON accounts (sip_realm);
CREATE INDEX service_provider_sid_idx ON accounts (service_provider_sid);
-ALTER TABLE accounts ADD FOREIGN KEY service_provider_sid_idxfk_9 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
+ALTER TABLE accounts ADD FOREIGN KEY service_provider_sid_idxfk_10 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
ALTER TABLE accounts ADD FOREIGN KEY registration_hook_sid_idxfk_1 (registration_hook_sid) REFERENCES webhooks (webhook_sid);
diff --git a/db/jambones.sqs b/db/jambones.sqs
index f931aa3..af71528 100644
--- a/db/jambones.sqs
+++ b/db/jambones.sqs
@@ -95,8 +95,8 @@
- 1791.00
- 608.00
+ 1823.00
+ 738.00
294.00
@@ -233,8 +233,8 @@
- 1334.00
- 1169.00
+ 1333.00
+ 1267.00
298.00
@@ -287,8 +287,8 @@
- 1745.00
- 19.00
+ 1769.00
+ 16.00
316.00
@@ -757,12 +757,63 @@
+
+
+
+
+ 1334.00
+ 325.00
+
+
+ 352.00
+ 100.00
+
+ 30
+
+
+
+ 1
+
+
+
+
+
+
+
+ account_sid
+ accounts
+ 1
+
+
+ 4
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- 1354.00
- 821.00
+ 1328.00
+ 958.00
368.00
@@ -909,8 +960,8 @@
- 1386.00
- 333.00
+ 1330.00
+ 514.00
276.00
@@ -966,6 +1017,57 @@
+
+
+
+
+ 1327.00
+ 205.00
+
+
+ 352.00
+ 100.00
+
+ 29
+
+
+
+ 1
+
+
+
+
+
+
+
+ service_provider_sid
+ service_providers
+ 1
+
+
+ 4
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1226,8 +1328,8 @@
- 1796.00
- 780.00
+ 1860.00
+ 897.00
232.00
@@ -1599,8 +1701,8 @@
- 1779.00
- 427.00
+ 1842.00
+ 550.00
352.00
@@ -2146,8 +2248,8 @@
- 1367.00
- 477.00
+ 1324.00
+ 637.00
322.00
@@ -2455,7 +2557,7 @@
-
+
diff --git a/db/upgrade-jambonz-db.js b/db/upgrade-jambonz-db.js
index 8101aaa..28b62de 100644
--- a/db/upgrade-jambonz-db.js
+++ b/db/upgrade-jambonz-db.js
@@ -1,4 +1,5 @@
#!/usr/bin/env node
+/* eslint-disable max-len */
const assert = require('assert');
const mysql = require('mysql2/promise');
const {readFile} = require('fs/promises');
@@ -25,8 +26,34 @@ const opts = {
const sql = {
'7006': [
'ALTER TABLE `accounts` ADD COLUMN `siprec_hook_sid` CHAR(36)',
- // eslint-disable-next-line max-len
'ALTER TABLE accounts ADD FOREIGN KEY siprec_hook_sid_idxfk (siprec_hook_sid) REFERENCES applications (application_sid)'
+ ],
+ '7007': [
+ `CREATE TABLE service_provider_limits
+ (service_provider_limits_sid CHAR(36) NOT NULL UNIQUE,
+ service_provider_sid CHAR(36) NOT NULL,
+ category ENUM('api_rate','voice_call_session', 'device') NOT NULL,
+ quantity INTEGER NOT NULL,
+ PRIMARY KEY (service_provider_limits_sid)
+ )`,
+ `CREATE TABLE account_limits
+ (
+ account_limits_sid CHAR(36) NOT NULL UNIQUE ,
+ account_sid CHAR(36) NOT NULL,
+ category ENUM('api_rate','voice_call_session', 'device') NOT NULL,
+ quantity INTEGER NOT NULL,
+ PRIMARY KEY (account_limits_sid)
+ )`,
+ 'CREATE INDEX service_provider_sid_idx ON service_provider_limits (service_provider_sid)',
+ `ALTER TABLE service_provider_limits
+ ADD FOREIGN KEY service_provider_sid_idxfk_3 (service_provider_sid)
+ REFERENCES service_providers (service_provider_sid)
+ ON DELETE CASCADE`,
+ 'CREATE INDEX account_sid_idx ON account_limits (account_sid)',
+ `ALTER TABLE account_limits
+ ADD FOREIGN KEY account_sid_idxfk_2 (account_sid)
+ REFERENCES accounts (account_sid)
+ ON DELETE CASCADE`
]
};
@@ -54,6 +81,7 @@ const doIt = async() => {
logger.info(`current schema value: ${val}`);
if (val < 7006) upgrades.push(...sql['7006']);
+ if (val < 7007) upgrades.push(...sql['7007']);
// perform all upgrades
logger.info({upgrades}, 'applying schema upgrades..');
diff --git a/lib/models/account-limits.js b/lib/models/account-limits.js
new file mode 100644
index 0000000..34bd13a
--- /dev/null
+++ b/lib/models/account-limits.js
@@ -0,0 +1,33 @@
+const Model = require('./model');
+
+class AccountLimits extends Model {
+ constructor() {
+ super();
+ }
+}
+
+AccountLimits.table = 'account_limits';
+AccountLimits.fields = [
+ {
+ name: 'account_limits_sid',
+ type: 'string',
+ primaryKey: true
+ },
+ {
+ name: 'account_sid',
+ type: 'string',
+ required: true
+ },
+ {
+ name: 'category',
+ type: 'string',
+ required: true
+ },
+ {
+ name: 'quantity',
+ type: 'number',
+ required: true
+ }
+];
+
+module.exports = AccountLimits;
diff --git a/lib/models/service-provider-limits.js b/lib/models/service-provider-limits.js
new file mode 100644
index 0000000..8db6830
--- /dev/null
+++ b/lib/models/service-provider-limits.js
@@ -0,0 +1,33 @@
+const Model = require('./model');
+
+class ServiceProviderLimits extends Model {
+ constructor() {
+ super();
+ }
+}
+
+ServiceProviderLimits.table = 'service_provider_limits';
+ServiceProviderLimits.fields = [
+ {
+ name: 'service_provider_limits_sid',
+ type: 'string',
+ primaryKey: true
+ },
+ {
+ name: 'service_provider_sid',
+ type: 'string',
+ required: true
+ },
+ {
+ name: 'category',
+ type: 'string',
+ required: true
+ },
+ {
+ name: 'quantity',
+ type: 'number',
+ required: true
+ }
+];
+
+module.exports = ServiceProviderLimits;
diff --git a/lib/routes/api/accounts.js b/lib/routes/api/accounts.js
index 62ffb37..b430281 100644
--- a/lib/routes/api/accounts.js
+++ b/lib/routes/api/accounts.js
@@ -51,6 +51,7 @@ router.use('/:sid/Alerts', hasAccountPermissions, require('./alerts'));
router.use('/:sid/Charges', hasAccountPermissions, require('./charges'));
router.use('/:sid/SipRealms', hasAccountPermissions, require('./sip-realm'));
router.use('/:sid/PredefinedCarriers', hasAccountPermissions, require('./add-from-predefined-carrier'));
+router.use('/:sid/Limits', hasAccountPermissions, require('./limits'));
router.get('/:sid/Applications', async(req, res) => {
const logger = req.app.locals.logger;
try {
diff --git a/lib/routes/api/limits.js b/lib/routes/api/limits.js
new file mode 100644
index 0000000..7f07e9e
--- /dev/null
+++ b/lib/routes/api/limits.js
@@ -0,0 +1,128 @@
+const router = require('express').Router();
+const sysError = require('../error');
+const AccountLimits = require('../../models/account-limits');
+const ServiceProviderLimits = require('../../models/service-provider-limits');
+const {parseAccountSid, parseServiceProviderSid} = require('./utils');
+const {promisePool} = require('../../db');
+const sqlDeleteSPLimits = `
+DELETE FROM service_provider_limits
+WHERE service_provider_sid = ?
+`;
+const sqlDeleteSPLimitsByCategory = `
+DELETE FROM service_provider_limits
+WHERE service_provider_sid = ?
+AND category = ?
+`;
+const sqlDeleteAccountLimits = `
+DELETE FROM account_limits
+WHERE account_sid = ?
+`;
+const sqlDeleteAccountLimitsByCategory = `
+DELETE FROM account_limits
+WHERE account_sid = ?
+AND category = ?
+`;
+router.post('/', async(req, res) => {
+ const logger = req.app.locals.logger;
+ const {
+ category,
+ quantity
+ } = req.body;
+ const account_sid = parseAccountSid(req);
+ let service_provider_sid;
+ if (!account_sid) {
+ if (!req.user.hasServiceProviderAuth) {
+ logger.error('POST /SpeechCredentials invalid credentials');
+ return res.send(403);
+ }
+ service_provider_sid = parseServiceProviderSid(req);
+ }
+ try {
+ let uuid;
+ if (account_sid) {
+ const existing = (await AccountLimits.retrieveAll(account_sid) || [])
+ .find((el) => el.category === category);
+ if (existing) {
+ uuid = existing.account_limits_sid;
+ await AccountLimits.update(uuid, {category, quantity});
+ }
+ else {
+ uuid = await AccountLimits.make({
+ account_sid,
+ category,
+ quantity
+ });
+ }
+ }
+ else {
+ const existing = (await ServiceProviderLimits.retrieveAll(service_provider_sid) || [])
+ .find((el) => el.category === category);
+ if (existing) {
+ uuid = existing.service_provider_limits_sid;
+ await ServiceProviderLimits.update(uuid, {category, quantity});
+ }
+ else {
+ uuid = await ServiceProviderLimits.make({
+ service_provider_sid,
+ category,
+ quantity
+ });
+ }
+ }
+ res.status(201).json({sid: uuid});
+ } catch (err) {
+ sysError(logger, res, err);
+ }
+});
+
+/**
+ * retrieve all limits for an account or service provider
+ */
+router.get('/', async(req, res) => {
+ let service_provider_sid;
+ const account_sid = parseAccountSid(req);
+ if (!account_sid) service_provider_sid = parseServiceProviderSid(req);
+ const logger = req.app.locals.logger;
+ try {
+ const limits = account_sid ?
+ await AccountLimits.retrieveAll(account_sid) :
+ await ServiceProviderLimits.retrieveAll(service_provider_sid);
+
+ if (req.query?.category) {
+ return res.status(200).json(limits.filter((el) => el.category === req.query.category));
+ }
+ res.status(200).json(limits);
+ } catch (err) {
+ sysError(logger, res, err);
+ }
+});
+
+router.delete('/', async(req, res) => {
+ const logger = req.app.locals.logger;
+ const account_sid = parseAccountSid(req);
+ const {category} = req.query;
+ const service_provider_sid = parseServiceProviderSid(req);
+ try {
+ if (account_sid) {
+ if (category) {
+ await promisePool.execute(sqlDeleteAccountLimitsByCategory, [account_sid, category]);
+ }
+ else {
+ await promisePool.execute(sqlDeleteAccountLimits, [account_sid]);
+ }
+ }
+ else {
+ if (category) {
+ await promisePool.execute(sqlDeleteSPLimitsByCategory, [service_provider_sid, category]);
+ }
+ else {
+ await promisePool.execute(sqlDeleteSPLimits, [service_provider_sid]);
+ }
+ }
+ res.status(204).end();
+ } catch (err) {
+ sysError(logger, res, err);
+ }
+});
+
+module.exports = router;
diff --git a/lib/routes/api/service-providers.js b/lib/routes/api/service-providers.js
index 240743d..dc4df52 100644
--- a/lib/routes/api/service-providers.js
+++ b/lib/routes/api/service-providers.js
@@ -44,6 +44,7 @@ decorate(router, ServiceProvider, ['delete'], preconditions);
router.use('/:sid/RecentCalls', hasServiceProviderPermissions, require('./recent-calls'));
router.use('/:sid/Alerts', hasServiceProviderPermissions, require('./alerts'));
router.use('/:sid/SpeechCredentials', hasServiceProviderPermissions, require('./speech-credentials'));
+router.use('/:sid/Limits', hasServiceProviderPermissions, require('./limits'));
router.use('/:sid/PredefinedCarriers', hasServiceProviderPermissions, require('./add-from-predefined-carrier'));
router.get('/:sid/Accounts', async(req, res) => {
const logger = req.app.locals.logger;
@@ -129,7 +130,6 @@ router.get('/:sid/ApiKeys', async(req, res) => {
}
});
-
/* add */
router.post('/', async(req, res) => {
const logger = req.app.locals.logger;
diff --git a/lib/swagger/swagger.yaml b/lib/swagger/swagger.yaml
index 990c2b3..bad0ebe 100644
--- a/lib/swagger/swagger.yaml
+++ b/lib/swagger/swagger.yaml
@@ -1806,7 +1806,7 @@ paths:
summary: test a speech credential
operationId: testSpeechCredential
parameters:
- - name: AccountSid
+ - name: ServiceProviderSid
in: path
required: true
schema:
@@ -1855,6 +1855,122 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/GeneralError'
+ /ServiceProviders/{ServiceProviderSid}/Limits:
+ post:
+ summary: create a limit for a service provider
+ operationId: addLimitForServiceProvider
+ parameters:
+ - name: ServiceProviderSid
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Limits'
+ responses:
+ 201:
+ description: limit successfully created or updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessfulAdd'
+ 404:
+ description: service provider not found
+ 500:
+ description: system error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GeneralError'
+ get:
+ summary: retrieve call capacity and other limits from the service provider
+ operationId: getServiceProviderLimits
+ parameters:
+ - name: ServiceProviderSid
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: service provider limits
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Limits'
+ 404:
+ description: service provider not found
+ 500:
+ description: system error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GeneralError'
+ /Accounts/{AccountSid}/Limits:
+ post:
+ summary: create a limit for an account
+ operationId: addLimitForAccount
+ parameters:
+ - name: AccountSid
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Limits'
+ responses:
+ 201:
+ description: limit successfully created or updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SuccessfulAdd'
+ 404:
+ description: account not found
+ 500:
+ description: system error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GeneralError'
+ get:
+ summary: retrieve call capacity and other limits from the account
+ operationId: getAccountLimits
+ parameters:
+ - name: AccountSid
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: account limits
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Limits'
+ 404:
+ description: account not found
+ 500:
+ description: system error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GeneralError'
/MicrosoftTeamsTenants:
post:
summary: provision a customer tenant for MS Teams
@@ -4409,6 +4525,15 @@ components:
- requires_static_ip
- e164_leading_plus
- requires_register
+ Limits:
+ type: object
+ properties:
+ category:
+ type: string
+ enum:
+ - voice_call_session
+ - api_limit
+ - devices
security:
- bearerAuth: []
\ No newline at end of file
diff --git a/test/accounts.js b/test/accounts.js
index cf46279..ae66d4d 100644
--- a/test/accounts.js
+++ b/test/accounts.js
@@ -188,6 +188,60 @@ test('account tests', async(t) => {
});
t.ok(result.statusCode === 204, 'successfully assigned phone number to account');
+ /* query all limits for an account */
+ result = await request.get(`/Accounts/${sid}/Limits`, {
+ auth: authAdmin,
+ json: true,
+ });
+ t.ok(result.length === 0, 'successfully queried account limits when there is none configured');
+
+ /* add a new limit for a account */
+ result = await request.post(`/Accounts/${sid}/Limits`, {
+ auth: authAdmin,
+ json: true,
+ resolveWithFullResponse: true,
+ body: {
+ category: 'voice_call_session',
+ quantity: 200
+ }
+ });
+ t.ok(result.statusCode === 201, 'successfully added a call session limit to an account');
+
+ /* update an existing limit for a account */
+ result = await request.post(`/Accounts/${sid}/Limits`, {
+ auth: authAdmin,
+ json: true,
+ resolveWithFullResponse: true,
+ body: {
+ category: 'voice_call_session',
+ quantity: 205
+ }
+ });
+ t.ok(result.statusCode === 201, 'successfully updated a call session limit to an account');
+
+ /* query all limits for an account */
+ result = await request.get(`/Accounts/${sid}/Limits`, {
+ auth: authAdmin,
+ json: true,
+ });
+ //console.log(result);
+ t.ok(result.length === 1 && result[0].quantity === 205, 'successfully queried account limits');
+
+ /* query all limits for an account by category*/
+ result = await request.get(`/Accounts/${sid}/Limits?category=voice_call_session`, {
+ auth: authAdmin,
+ json: true,
+ });
+ //console.log(result);
+ t.ok(result.length === 1 && result[0].quantity === 205, 'successfully queried account limits by category');
+
+ /* delete call session limits for a service provider */
+ result = await request.delete(`/Accounts/${sid}/Limits?category=voice_call_session`, {
+ auth: authAdmin,
+ resolveWithFullResponse: true
+ });
+ t.ok(result.statusCode === 204, 'successfully deleted a call session limit for an account');
+
/* delete account */
result = await request.delete(`/Accounts/${sid}`, {
auth: authAdmin,
diff --git a/test/service-providers.js b/test/service-providers.js
index bf874f0..29bc632 100644
--- a/test/service-providers.js
+++ b/test/service-providers.js
@@ -140,9 +140,34 @@ test('service provider tests', async(t) => {
resolveWithFullResponse: true,
});
t.ok(result.statusCode === 201, 'successfully added predefined carrier to service provider');
-
await deleteObjectBySid(request, '/VoipCarriers', result.body.sid);
+ /* add a limit for a service provider */
+ result = await request.post(`/ServiceProviders/${sid}/Limits`, {
+ auth: authAdmin,
+ json: true,
+ resolveWithFullResponse: true,
+ body: {
+ category: 'voice_call_session',
+ quantity: 1000
+ }
+ });
+ t.ok(result.statusCode === 201, 'successfully added a call session limit to service provider');
+
+ /* query all limits for a service provider */
+ result = await request.get(`/ServiceProviders/${sid}/Limits`, {
+ auth: authAdmin,
+ json: true,
+ });
+ t.ok(result.length === 1 , 'successfully queried all limits');
+
+ /* delete call session limits for a service provider */
+ result = await request.delete(`/ServiceProviders/${sid}/Limits?category=voice_call_session`, {
+ auth: authAdmin,
+ resolveWithFullResponse: true
+ });
+ t.ok(result.statusCode === 204, 'successfully deleted a call session limit for a service provider');
+
/* delete service providers */
result = await request.delete(`/ServiceProviders/${sid}`, {
auth: authAdmin,