This commit is contained in:
Markus Frindt
2024-06-17 09:49:25 +02:00
committed by GitHub
25 changed files with 6525 additions and 161 deletions

View File

@@ -17,8 +17,33 @@ insert into smpp_addresses (smpp_address_sid, ipv4, port, use_tls, is_primary)
values('049078a0', '3.209.58.102', 3550, 1, 1);
-- create one service provider and account
insert into api_keys (api_key_sid, token)
values ('3f35518f-5a0d-4c2e-90a5-2407bb3b36f0', '38700987-c7a4-4685-a5bb-af378f9734de');
insert into api_keys (api_key_sid, token, account_sid)
('3f35518f-5a0d-4c2e-90a5-2407bb3b36fa', '38700987-c7a4-4685-a5bb-af378f9734da', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('9a9f220e-1c64-4aa4-a94f-4221b8486f11', '32c687eb-f57e-476a-bbec-cd20ec1d840d', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('417110d1-ab8c-48f9-9f3a-be69eff2c6f8', '04868c2c-f187-4555-b847-19fe64507566', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('a89fd59b-f98b-4682-9d43-d78b6b5a2adb', 'd95188e7-fbda-4e92-86a9-dd7e90e6ba99', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('7e3f0f53-fff7-48f7-bd7f-07087e94b83b', '67484932-3207-4199-b172-5b25cab73912', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('cddaf2c0-e2a2-46ce-89b9-8e172b1a7f34', 'f8c44bf2-010d-4150-b198-98a10101eb1a', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('6a312d2e-cdbc-47f5-83ea-f2e704be43d8', '30067c66-c55b-4e1f-a4a3-7b5674bfa7fb', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('53a3aef1-ef93-4c5c-b89e-b45360ebd087', 'ce1cde34-0f83-4179-8e1f-11452376e12b', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('14aa8867-aa08-480b-b1d1-7dea30e63ffa', 'eef78786-0e4b-4ed5-aa6a-2d5ef836cb87', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('5be9494c-132a-48d2-b928-576ab0fbc144', 'a8ac120e-1178-40a4-990e-c173d8bf97ba', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('a8df3d6a-1f51-4efd-8a95-4925e9d00fa7', '841c2cff-5d6b-4776-9fc8-b87190bc0c9f', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('16c62198-5f1e-4aff-bda7-5a0121ce8cb0', '04be0f91-3772-47ae-a467-9c29da3a8a79', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('ca96f1cf-0158-4b20-bfcc-60b5a3b96461', '105dedda-fa3c-4146-b51e-5ca253bb6b88', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('1db27613-e5c3-49b3-970e-edfd15f97ab0', 'ee4b03b4-bdec-4b37-8d36-3cdd70e4a93b', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('d2482a65-2895-4131-9818-34331d9a512e', 'e6f1e1ef-9d66-4cab-b047-5dcdddcc5b4a', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('88851e5e-3241-4cdc-bede-8cf0740e8d4c', 'ee6f22bd-59e9-453a-8bb2-909ec1e7204c', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('787e7aec-163f-4b48-8bca-bd96c435a06e', 'f131067b-587e-456a-b432-ae389b6ded2c', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('d883ef06-582d-40cb-92da-63b1831dd170', 'c25699d5-7bc6-4892-b589-f744ae47b3dc', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('bed6d98b-2912-46d1-8830-fd1c0659b3b7', '1aef8599-6043-455c-b009-21b2266db7e4', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('6f4d5047-d1f0-4df0-b5c3-032dae1e784b', '08a3eac4-c399-43ce-855f-f268e58bee30', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('1d689103-f04b-4cc1-85d2-99e48e4d6b2c', 'd858643f-3cd7-4efb-992f-d293b791c623', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('9b67593f-29bc-4651-8412-2ad94c982115', '7c2e0eb8-7ebb-45bc-b5d0-2eb78eddd67a', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('7b377326-9c1b-44ae-b3af-0702689c9f8f', '5a887940-39c1-4ad4-92b4-1099e548a5bf', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('7f306b65-de74-4e17-8d1d-602908fc823a', '61f0bd74-71cd-4a12-85eb-9a2ce423749d', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('c3277d25-5c06-4ee1-bfda-102fb69785e4', 'ece4b921-440c-452d-9747-5ae7cc8268e5', '9351f46a-678c-43f5-b8a6-d4eb58d131af'),
('62f3a6d7-b930-46e9-9687-eea65e80eb1e', '83378993-1dac-4880-9a42-a49da150c533', '9351f46a-678c-43f5-b8a6-d4eb58d131af');
-- create one service provider and one account
insert into service_providers (service_provider_sid, name, root_domain)

5
lib/config.js Normal file
View File

@@ -0,0 +1,5 @@
const isPaginationEnabled = process.env.PAGINATION === 'true';
module.exports = {
isPaginationEnabled,
};

View File

@@ -55,6 +55,13 @@ WHERE account_sid = ?
AND effective_end_date IS NULL
AND pending = 0`;
const retrieveAllSqlCount = `SELECT COUNT(*) AS total_items
FROM accounts acc
LEFT JOIN webhooks AS rh
ON acc.registration_hook_sid = rh.webhook_sid
LEFT JOIN webhooks AS qh
ON acc.queue_event_hook_sid = qh.webhook_sid`;
const extractBucketCredential = (obj) => {
const {bucket_credential} = obj;
if (bucket_credential) {
@@ -107,10 +114,48 @@ class Account extends Model {
sql = `${sql} WHERE acc.service_provider_sid = ?`;
args.push(service_provider_sid);
}
return this.wrapPromise(sql, args);
}
static async retrieveAllPaginated(service_provider_sid, account_sid, limit, page) {
const offset = (page - 1) * limit;
const args = [];
let sql = retrieveSql;
let sqlCount = retrieveAllSqlCount;
if (account_sid) {
sql = `${sql} WHERE acc.account_sid = ?`;
sqlCount = `${sqlCount} WHERE acc.account_sid = ?`;
args.push(account_sid);
} else if (service_provider_sid) {
sql = `${sql} WHERE acc.service_provider_sid = ?`;
sqlCount = `${sqlCount} WHERE acc.service_provider_sid = ?`;
args.push(service_provider_sid);
}
const [row] = await promisePool.query(sqlCount, args);
const [{ total_items = 0 }] = row;
const total_pages = Math.ceil(total_items / limit) || 1;
sql = `${sql} LIMIT ? OFFSET ?`;
args.push(limit, offset);
const data = await this.wrapPromise(sql, args);
return {
total_items,
total_pages,
page,
data,
};
}
static wrapPromise(sql, args) {
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
conn.query({sql, nestTables: true}, args, (err, results, fields) => {
conn.query({ sql, nestTables: true }, args, (err, results, fields) => {
conn.release();
if (err) return reject(err);
const r = transmogrifyResults(results);
@@ -130,17 +175,7 @@ class Account extends Model {
sql = `${retrieveSql} WHERE acc.account_sid = ? AND acc.service_provider_sid = ?`;
args.push(service_provider_sid);
}
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
conn.query({sql, nestTables: true}, args, (err, results, fields) => {
conn.release();
if (err) return reject(err);
const r = transmogrifyResults(results);
resolve(r);
});
});
});
return this.wrapPromise(sql, args);
}
static async updateStripeCustomerId(sid, customerId) {
@@ -248,6 +283,16 @@ class Account extends Model {
}));
return account_subscription_sid;
}
static async isPropertyAvailable(property, args) {
const sql = `SELECT *
FROM accounts acc
WHERE acc.service_provider_sid = ?
AND acc.${property} = ?`;
const result = await this.wrapPromise(sql, args);
return result.length === 0;
}
}
Account.table = 'accounts';

View File

@@ -1,6 +1,9 @@
const Model = require('./model');
const {getMysqlConnection} = require('../db');
const sqlCountSP = 'SELECT COUNT(*) AS total_items from api_keys WHERE service_provider_sid = ?';
const sqlCountAcc = 'SELECT COUNT(*) AS total_items from api_keys WHERE account_sid = ?';
class ApiKey extends Model {
constructor() {
super();
@@ -15,6 +18,31 @@ class ApiKey extends Model {
'SELECT * from api_keys WHERE account_sid IS NULL';
const args = account_sid ? [account_sid] : [];
return this.wrapPromise(sql, args);
}
/**
* list all api keys for an account paginated
*/
static async retrieveAllPaginated(account_sid, limit, page) {
const offset = (page - 1) * limit;
const [{ total_items = 0 }] = await this.wrapPromise(sqlCountAcc, [account_sid]);
const total_pages = Math.ceil(total_items / limit) || 1;
const sql = 'SELECT * from api_keys WHERE account_sid = ? LIMIT ? OFFSET ?';
const args = [account_sid, limit, offset];
const data = await this.wrapPromise(sql, args);
return {
total_items,
total_pages,
page,
data
};
}
static wrapPromise(sql, args) {
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
@@ -30,20 +58,31 @@ class ApiKey extends Model {
/**
* list all api keys for a service provider
*/
static retrieveAllForSP(service_provider_sid) {
static async retrieveAllForSP(service_provider_sid) {
const sql = 'SELECT * from api_keys WHERE service_provider_sid = ?';
const args = [service_provider_sid];
return this.wrapPromise(sql, args);
}
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
conn.query(sql, args, (err, results) => {
conn.release();
if (err) return reject(err);
resolve(results);
});
});
});
/**
* list all api keys for a service provider paginated
*/
static async retrieveAllForSPPaginated(service_provider_sid, limit = 25, page = 1) {
const offset = (page - 1) * limit;
const [{total_items = 0}] = await this.wrapPromise(sqlCountSP, [service_provider_sid]);
const total_pages = Math.ceil(total_items / limit) || 1;
const sql = 'SELECT * from api_keys WHERE service_provider_sid = ? LIMIT ? OFFSET ?';
const args = [service_provider_sid, limit, offset];
const data = await this.wrapPromise(sql, args);
return {
total_items,
total_pages,
page,
data
};
}
/**
@@ -53,16 +92,7 @@ class ApiKey extends Model {
const sql = 'UPDATE api_keys SET last_used = NOW() WHERE account_sid = ?';
const args = [account_sid];
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
conn.query(sql, args, (err, results) => {
conn.release();
if (err) return reject(err);
resolve(results);
});
});
});
return this.wrapPromise(sql, args);
}
}

View File

@@ -1,5 +1,6 @@
const Model = require('./model');
const {getMysqlConnection} = require('../db');
const { promisePool } = require('../db');
const retrieveSql = `SELECT * from applications app
LEFT JOIN webhooks AS ch
@@ -9,6 +10,15 @@ ON app.call_status_hook_sid = sh.webhook_sid
LEFT JOIN webhooks AS mh
ON app.messaging_hook_sid = mh.webhook_sid`;
const retrieveAllSqlCount = `SELECT COUNT(*) as total_items
FROM applications app
LEFT JOIN webhooks AS ch
ON app.call_hook_sid = ch.webhook_sid
LEFT JOIN webhooks AS sh
ON app.call_status_hook_sid = sh.webhook_sid
LEFT JOIN webhooks AS mh
ON app.messaging_hook_sid = mh.webhook_sid`;
function transmogrifyResults(results) {
return results.map((row) => {
const obj = row.app;
@@ -50,6 +60,44 @@ class Application extends Model {
sql = `${sql} WHERE account_sid in (SELECT account_sid from accounts WHERE service_provider_sid = ?)`;
args.push(service_provider_sid);
}
return this.wrapPromise(sql, args);
}
static async retrieveAllPaginated(service_provider_sid, account_sid, limit, page) {
const offset = (page - 1) * limit;
const args = [];
let sql = retrieveSql;
let sqlCount = retrieveAllSqlCount;
if (account_sid) {
sql = `${sql} WHERE app.account_sid = ?`;
sqlCount = `${sqlCount} WHERE app.account_sid = ?`;
args.push(account_sid);
} else if (service_provider_sid) {
sql = `${sql} WHERE account_sid in (SELECT account_sid from accounts WHERE service_provider_sid = ?)`;
sqlCount = `${sqlCount} WHERE account_sid in (SELECT account_sid from accounts WHERE service_provider_sid = ?)`;
args.push(service_provider_sid);
}
const [row] = await promisePool.query(sqlCount, args);
const [{total_items = 0}] = row;
const total_pages = Math.ceil(total_items / limit) || 1;
sql = `${sql} LIMIT ? OFFSET ?`;
args.push(limit, offset);
const data = await this.wrapPromise(sql, args);
return {
total_items,
total_pages,
page,
data,
};
}
static wrapPromise(sql, args) {
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
@@ -77,17 +125,7 @@ class Application extends Model {
sql = `${sql} AND account_sid in (SELECT account_sid from accounts WHERE service_provider_sid = ?)`;
args.push(service_provider_sid);
}
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
conn.query({sql, nestTables: true}, args, (err, results, fields) => {
conn.release();
if (err) return reject(err);
const r = transmogrifyResults(results);
resolve(r);
});
});
});
return this.wrapPromise(sql, args);
}
}

View File

@@ -7,7 +7,7 @@ class LcrCarrierSetEntry extends Model {
}
static async retrieveAllByLcrRouteSid(sid) {
const sql = `SELECT * FROM ${this.table} WHERE lcr_route_sid = ? ORDER BY priority`;
const sql = `(SELECT * FROM ${this.table} WHERE lcr_route_sid = ?) ORDER BY priority`;
const [rows] = await promisePool.query(sql, sid);
return rows;
}

View File

@@ -8,7 +8,7 @@ class LcrRoutes extends Model {
}
static async retrieveAllByLcrSid(sid) {
const sql = `SELECT * FROM ${this.table} WHERE lcr_sid = ? ORDER BY priority`;
const sql = `(SELECT * FROM ${this.table} WHERE lcr_sid = ?) ORDER BY priority`;
const [rows] = await promisePool.query(sql, sid);
return rows;
}
@@ -24,6 +24,25 @@ class LcrRoutes extends Model {
const [rows] = await promisePool.query(sql, sid);
return rows.length ? rows[0].count : 0;
}
static async retrieveAllByLcrSidPaginated(sid, limit, page) {
const offset = (page - 1) * limit;
const sql = `(SELECT * FROM ${this.table} WHERE lcr_sid = ? LIMIT ? OFFSET ? ) ORDER BY priority`;
const [rows] = await promisePool.query(sql, [sid, limit, offset]);
const countSql = `SELECT COUNT(*) AS total_items FROM ${this.table} WHERE lcr_sid = ?`;
const [row] = await promisePool.query(countSql, [sid]);
const [{ total_items = 0 }] = row;
const total_pages = Math.ceil(total_items / limit) || 1;
return {
total_items,
total_pages,
page,
data: rows,
};
}
}
LcrRoutes.table = 'lcr_routes';

View File

@@ -6,18 +6,86 @@ class Lcr extends Model {
super();
}
static async countAll() {
const countSql = `SELECT COUNT(*) AS total_items FROM ${this.table}`;
const [row] = await promisePool.query(countSql);
const [{ total_items = 0 }] = row;
return total_items;
}
static async retrieveAllPaginated(limit, page) {
const offset = (page - 1) * limit;
const data = await super.retrieveAllPaginated([limit, offset]);
const total_items = await this.countAll();
const total_pages = Math.ceil(total_items / limit) || 1;
return {
total_items,
total_pages,
page,
data,
};
}
static async retrieveAllByAccountSid(account_sid) {
const sql = `SELECT * FROM ${this.table} WHERE account_sid = ?`;
const [rows] = await promisePool.query(sql, account_sid);
return rows;
}
static async countAcc(sid) {
const countSql = `SELECT COUNT(*) AS total_items FROM ${this.table} WHERE account_sid = ?`;
const [row] = await promisePool.query(countSql, [sid]);
const [{ total_items = 0 }] = row;
return total_items;
}
static async retrieveAllByAccountSidPaginated(sid, limit, page) {
const offset = (page - 1) * limit;
const sql = `SELECT * FROM ${this.table} WHERE account_sid = ? LIMIT ? OFFSET ?`;
const [rows] = await promisePool.query(sql, [sid, limit, offset]);
const total_items = await this.countAcc(sid);
const total_pages = Math.ceil(total_items / limit) || 1;
return {
total_items,
total_pages,
page,
data: rows,
};
}
static async retrieveAllByServiceProviderSid(sid) {
const sql = `SELECT * FROM ${this.table} WHERE service_provider_sid = ?`;
const [rows] = await promisePool.query(sql, sid);
return rows;
}
static async countSP(sid) {
const countSql = `SELECT COUNT(*) AS total_items FROM ${this.table} WHERE service_provider_sid = ?`;
const [row] = await promisePool.query(countSql, [sid]);
const [{ total_items = 0 }] = row;
return total_items;
}
static async retrieveAllByServiceProviderSidPaginated(sid, limit, page) {
const offset = (page - 1) * limit;
const sql = `SELECT * FROM ${this.table} WHERE account_sid = ? LIMIT ? OFFSET ?`;
const [rows] = await promisePool.query(sql, [sid, limit, offset]);
const total_items = await this.countSP(sid);
const total_pages = Math.ceil(total_items / limit) || 1;
return {
total_items,
total_pages,
page,
data: rows,
};
}
static async releaseDefaultEntry(sid) {
const sql = `UPDATE ${this.table} SET default_carrier_set_entry_sid = null WHERE lcr_sid = ?`;
const [rows] = await promisePool.query(sql, sid);

View File

@@ -79,6 +79,22 @@ class Model extends Emitter {
});
}
/**
* retrieve all objects paginated
*/
static retrieveAllPaginated(args) {
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
conn.query(`SELECT * from ${this.table} LIMIT ? OFFSET ?`, args, (err, results, fields) => {
conn.release();
if (err) return reject(err);
resolve(results);
});
});
});
}
/**
* retrieve a specific object
*/

View File

@@ -10,6 +10,21 @@ WHERE account_sid IN
FROM accounts
WHERE service_provider_sid = ?
) ORDER BY number`;
const retrieveSqlCount = `SELECT COUNT(*) AS total_items
FROM phone_numbers pn`;
const retrieveSqlCountForAcc = `SELECT COUNT(*) AS total_items
FROM phone_numbers pn
WHERE pn.account_sid = ?`;
const retrieveSqlCountForSP = `SELECT COUNT(*) as total_items
FROM phone_numbers
WHERE account_sid IN
(
SELECT account_sid
FROM accounts
WHERE service_provider_sid = ?
) ORDER BY number`;
class PhoneNumber extends Model {
constructor() {
@@ -21,11 +36,70 @@ class PhoneNumber extends Model {
const [rows] = await promisePool.query(sqlRetrieveAll, account_sid);
return rows;
}
static async retrieveAllPaginated(account_sid, limit, page) {
const offset = (page - 1) * limit;
let data;
const countArgs = [];
let countSql;
if (!account_sid) {
data = await super.retrieveAllPaginated([limit, offset]);
countSql = retrieveSqlCount;
} else {
countSql = retrieveSqlCountForAcc;
countArgs.push(account_sid);
const sql = `${sqlRetrieveAll} LIMIT ? OFFSET ?`;
const [rows] = await promisePool.query(sql, [account_sid, limit, offset]);
data = rows;
}
const [row] = await promisePool.query(countSql, countArgs);
const [{ total_items = 0 }] = row;
const total_pages = Math.ceil(total_items / limit) || 1;
return {
total_items,
total_pages,
page,
data,
};
}
static async retrieveAllForSP(service_provider_sid) {
const [rows] = await promisePool.query(sqlSP, service_provider_sid);
return rows;
}
static async retrieveAllForSPPaginated(service_provider_sid, limit, page) {
const offset = (page - 1) * limit;
let data;
const countArgs = [];
let countSql;
if (!service_provider_sid) {
data = await super.retrieveAllPaginated([limit, offset]);
countSql = retrieveSqlCount;
} else {
countArgs.push(service_provider_sid);
countSql = retrieveSqlCountForSP;
const sql = `${sqlSP} LIMIT ? OFFSET ?`;
const [rows] = await promisePool.query(sql, [service_provider_sid, limit, offset]);
data = rows;
}
const [row] = await promisePool.query(countSql, countArgs);
const [{ total_items = 0 }] = row;
const total_pages = Math.ceil(total_items / limit) || 1;
return {
total_items,
total_pages,
page,
data,
};
}
/**
* retrieve a phone number
*/

View File

@@ -1,5 +1,5 @@
const Model = require('./model');
const {getMysqlConnection} = require('../db');
const {getMysqlConnection, promisePool} = require('../db');
const retrieveSql = `SELECT * from service_providers sp
LEFT JOIN webhooks AS rh
@@ -29,25 +29,10 @@ class ServiceProvider extends Model {
*/
static retrieveAll() {
const sql = retrieveSql;
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
conn.query({sql, nestTables: true}, [], (err, results, fields) => {
conn.release();
if (err) return reject(err);
const r = transmogrifyResults(results);
resolve(r);
});
});
});
return this.wrapPromise(sql);
}
/**
* retrieve a service provider
*/
static retrieve(sid) {
const args = [sid];
const sql = `${retrieveSql} WHERE sp.service_provider_sid = ?`;
static async wrapPromise(sql, args = []) {
return new Promise((resolve, reject) => {
getMysqlConnection((err, conn) => {
if (err) return reject(err);
@@ -60,6 +45,34 @@ class ServiceProvider extends Model {
});
});
}
static async retrieveAllPaginated(limit, page) {
const offset = (page - 1) * limit;
const sql = `${retrieveSql} LIMIT ? OFFSET ?`;
const data = await this.wrapPromise(sql, [limit, offset]);
const countSql = 'SELECT COUNT(*) as total_items from service_providers sp';
const [row] = await promisePool.query(countSql, []);
const [{ total_items = 0 }] = row;
const total_pages = Math.ceil(total_items / limit) || 1;
return {
total_items,
total_pages,
page,
data,
};
}
/**
* retrieve a service provider
*/
static retrieve(sid) {
const args = [sid];
const sql = `${retrieveSql} WHERE sp.service_provider_sid = ?`;
return this.wrapPromise(sql, args);
}
}
ServiceProvider.table = 'service_providers';

View File

@@ -29,6 +29,10 @@ LEFT JOIN service_providers as sp ON u.service_provider_sid = sp.service_provide
LEFT JOIN accounts acc ON u.account_sid = acc.account_sid
WHERE u.service_provider_sid = ?
`;
const sqlCountSP = 'SELECT COUNT(*) AS total_items from users WHERE service_provider_sid = ?';
const sqlCountAcc = 'SELECT COUNT(*) AS total_items from users WHERE account_sid = ?';
const sqlCount = 'SELECT COUNT(*) AS total_items from users';
class User extends Model {
constructor() {
@@ -40,15 +44,69 @@ class User extends Model {
return rows;
}
static async retrieveAllPaginated(limit, page) {
const offset = (page - 1) * limit;
const [row] = await promisePool.query(sqlCount);
const [{total_items = 0}] = row;
const total_pages = Math.ceil(total_items / limit) || 1;
const sql = `${sqlAll} LIMIT ? OFFSET ?`;
const args = [limit, offset];
const [data] = await promisePool.query(sql, args);
return {
total_items,
total_pages,
page,
data
};
}
static async retrieveAllForAccount(account_sid) {
const [rows] = await promisePool.query(sqlAccount, [account_sid]);
return rows;
}
static async retrieveAllForAccountPaginated(account_sid, limit, page) {
const offset = (page - 1) * limit;
const [row] = await promisePool.query(sqlCountAcc, [account_sid]);
const [{total_items = 0}] = row;
const total_pages = Math.ceil(total_items / limit) || 1;
const sql = `${sqlAccount} LIMIT ? OFFSET ?`;
const args = [account_sid, limit, offset];
const [data] = await promisePool.query(sql, args);
return {
total_items,
total_pages,
page,
data
};
}
static async retrieveAllForServiceProvider(service_provider_sid) {
const [rows] = await promisePool.query(sqlSP, [service_provider_sid]);
return rows;
}
static async retrieveAllForServiceProviderPaginated(service_provider_sid, limit, page) {
const offset = (page - 1) * limit;
const [{total_items}] = await promisePool.query(sqlCountSP, [service_provider_sid]);
const total_pages = Math.ceil(total_items / limit) || 1;
const sql = `${sqlSP} LIMIT ? OFFSET ?`;
const args = [service_provider_sid, limit, offset];
const [data] = await promisePool.query(sql, args);
return {
total_items,
total_pages,
page,
data
};
}
}
User.table = 'users';

View File

@@ -1,8 +1,11 @@
const Model = require('./model');
const {promisePool} = require('../db');
const retrieveSql = 'SELECT * from voip_carriers vc WHERE vc.account_sid = ?';
const { promisePool } = require('../db');
const retrieveSqlForAcc = 'SELECT * from voip_carriers vc WHERE vc.account_sid = ?';
const retrieveSqlForSP = 'SELECT * from voip_carriers vc WHERE vc.service_provider_sid = ?';
const retrieveSqlCount = 'SELECT COUNT(*) AS total_items from voip_carriers vc';
const retrieveSqlCountForAcc = 'SELECT COUNT(*) AS total_items from voip_carriers vc WHERE vc.account_sid = ?';
const retrieveSqlCountForSP = 'SELECT COUNT(*) AS total_items from voip_carriers vc WHERE vc.service_provider_sid = ?';
class VoipCarrier extends Model {
constructor() {
@@ -10,12 +13,55 @@ class VoipCarrier extends Model {
}
static async retrieveAll(account_sid) {
if (!account_sid) return super.retrieveAll();
const [rows] = await promisePool.query(retrieveSql, account_sid);
const [rows] = await promisePool.query(retrieveSqlForAcc, account_sid);
if (rows) {
rows.map((r) => r.register_status = JSON.parse(r.register_status || '{}'));
}
return rows;
}
static async countAll(filter) {
const {account_sid, service_provider_sid} = filter || {};
let countSql = retrieveSqlCount;
const countArgs = [];
if (account_sid) {
countArgs.push(account_sid);
countSql = retrieveSqlCountForAcc;
} else if (service_provider_sid) {
countArgs.push(service_provider_sid);
countSql = retrieveSqlCountForSP;
}
const [row] = await promisePool.query(countSql, countArgs);
const [{ total_items }] = row;
return total_items;
}
static async retrieveAllPaginated(account_sid, limit, page) {
const offset = (page - 1) * limit;
let data;
if (!account_sid) {
data = await super.retrieveAllPaginated([limit, offset]);
} else {
const [rows] = await promisePool.query(`${retrieveSqlForAcc} LIMIT ? OFFSET ?`, [account_sid, limit, offset]);
if (rows) {
rows.map((r) => r.register_status = JSON.parse(r.register_status || '{}'));
data = rows;
}
}
const total_items = await this.countAll({account_sid});
const total_pages = Math.ceil(total_items / limit) || 1;
return {
total_items,
total_pages,
page,
data,
};
}
static async retrieveAllForSP(service_provider_sid) {
const [rows] = await promisePool.query(retrieveSqlForSP, service_provider_sid);
if (rows) {
@@ -23,6 +69,34 @@ class VoipCarrier extends Model {
}
return rows;
}
static async retrieveAllForSPPaginated(service_provider_sid, limit, page) {
const offset = (page - 1) * limit;
let data;
if (!service_provider_sid) {
data = await super.retrieveAllPaginated([limit, offset]);
} else {
const sql = `${retrieveSqlForSP} LIMIT ? OFFSET ?`;
const [rows] = await promisePool.query(sql, [service_provider_sid, limit, offset]);
if (rows) {
rows.map((r) => r.register_status = JSON.parse(r.register_status || '{}'));
data = rows;
}
}
const total_items = await this.countAll({service_provider_sid});
const total_pages = Math.ceil(total_items / limit) || 1;
return {
total_items,
total_pages,
page,
data,
};
}
}
VoipCarrier.table = 'voip_carriers';

View File

@@ -25,6 +25,8 @@ const short = require('short-uuid');
const VoipCarrier = require('../../models/voip-carrier');
const { encrypt } = require('../../utils/encrypt-decrypt');
const { testS3Storage, testGoogleStorage, testAzureStorage } = require('../../utils/storage-utils');
const {validateQuery} = require('../../utils/validate-query');
const { isPaginationEnabled } = require('../../config');
const translator = short();
let idx = 0;
@@ -92,23 +94,41 @@ router.get('/:sid/Applications', async(req, res) => {
try {
const account_sid = parseAccountSid(req);
await validateRequest(req, account_sid);
const results = await Application.retrieveAll(null, account_sid);
let results;
if (isPaginationEnabled) {
validateQuery(req.query);
results = await Application.retrieveAllPaginated(null, account_sid, req.query.limit, req.query.page);
} else {
results = await Application.retrieveAll(null, account_sid);
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);
}
});
router.get('/:sid/VoipCarriers', async(req, res) => {
const logger = req.app.locals.logger;
try {
const account_sid = parseAccountSid(req);
await validateRequest(req, account_sid);
const results = await VoipCarrier.retrieveAll(account_sid);
let results;
if (isPaginationEnabled) {
validateQuery(req.query);
results = await VoipCarrier.retrieveAllPaginated(account_sid, req.query.limit, req.query.page);
} else {
results = await VoipCarrier.retrieveAll(account_sid);
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);
}
});
router.put('/:sid/VoipCarriers/:voip_carrier_sid', async(req, res) => {
const logger = req.app.locals.logger;
@@ -540,7 +560,14 @@ router.get('/', async(req, res) => {
try {
const service_provider_sid = req.user.hasServiceProviderAuth ? req.user.service_provider_sid : null;
const account_sid = req.user.hasAccountAuth ? req.user.account_sid : null;
const results = await Account.retrieveAll(service_provider_sid, account_sid);
let results;
const {limit, page} = req.query || {};
if (isPaginationEnabled && limit && page) {
validateQuery(req.query);
results = await Account.retrieveAllPaginated(service_provider_sid, account_sid, req.query.limit, req.query.page);
} else {
results = await Account.retrieveAll(service_provider_sid, account_sid);
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);
@@ -877,8 +904,13 @@ router.get('/:sid/ApiKeys', async(req, res) => {
try {
const sid = parseAccountSid(req);
await validateRequest(req, sid);
const results = await ApiKey.retrieveAll(sid);
let results;
if (isPaginationEnabled) {
validateQuery(req.query);
results = await ApiKey.retrieveAllPaginated(sid, req.query.limit, req.query.page);
} else {
results = await ApiKey.retrieveAll(sid);
}
res.status(200).json(results);
updateLastUsed(logger, sid, req).catch((err) => {});
} catch (err) {
@@ -943,8 +975,20 @@ router.get('/:sid/Calls', async(req, res) => {
to,
callStatus
});
let results = coerceNumbers(snakeCase(calls));
if (isPaginationEnabled) {
validateQuery(req.query);
results = {
total_items: results.length,
total_pages: results.length / req.query.limit || 1,
page: req.query.page,
data: results,
};
}
logger.debug(`retrieved ${calls.length} calls for account sid ${accountSid}`);
res.status(200).json(coerceNumbers(snakeCase(calls)));
res.status(200).json(results);
updateLastUsed(logger, accountSid, req).catch((err) => {});
} catch (err) {
sysError(logger, res, err);

View File

@@ -8,6 +8,8 @@ const decorate = require('./decorate');
const sysError = require('../error');
const { validate } = require('@jambonz/verb-specifications');
const { parseApplicationSid } = require('./utils');
const { isPaginationEnabled } = require('../../config');
const { validateQuery } = require('../../utils/validate-query');
const preconditions = {
'add': validateAdd,
'update': validateUpdate
@@ -156,7 +158,20 @@ router.get('/', async(req, res) => {
try {
const service_provider_sid = req.user.hasServiceProviderAuth ? req.user.service_provider_sid : null;
const account_sid = req.user.hasAccountAuth ? req.user.account_sid : null;
const results = await Application.retrieveAll(service_provider_sid, account_sid);
let results;
if (isPaginationEnabled) {
validateQuery(req.query);
results = await Application.retrieveAllPaginated(
service_provider_sid,
account_sid,
req.query.limit,
req.query.page
);
} else {
results = await Application.retrieveAll(service_provider_sid, account_sid);
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);

View File

@@ -5,6 +5,8 @@ const LcrCarrierSetEntry = require('../../models/lcr-carrier-set-entry');
const decorate = require('./decorate');
const {DbErrorBadRequest} = require('../../utils/errors');
const sysError = require('../error');
const { isPaginationEnabled } = require('../../config');
const { validateQuery } = require('../../utils/validate-query');
const validateAdd = async(req) => {
// check if lcr sid is available
@@ -68,10 +70,18 @@ router.get('/', async(req, res) => {
const lcr_sid = req.query.lcr_sid;
try {
await checkUserScope(req, lcr_sid);
const results = await LcrRoute.retrieveAllByLcrSid(lcr_sid);
for (const r of results) {
let results;
if (isPaginationEnabled) {
validateQuery(req.query);
results = await LcrRoute.retrieveAllByLcrSidPaginated(lcr_sid, req.query.limit, req.query.page);
} else {
results = await LcrRoute.retrieveAllByLcrSid(lcr_sid);
}
for (const r of results?.data || results) {
r.lcr_carrier_set_entries = await LcrCarrierSetEntry.retrieveAllByLcrRouteSid(r.lcr_route_sid);
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);

View File

@@ -6,6 +6,8 @@ const decorate = require('./decorate');
const {DbErrorBadRequest} = require('../../utils/errors');
const sysError = require('../error');
const ServiceProvider = require('../../models/service-provider');
const { isPaginationEnabled } = require('../../config');
const { validateQuery } = require('../../utils/validate-query');
const validateAssociatedTarget = async(req, sid) => {
const {lookupAccountBySid} = req.app.locals;
@@ -190,14 +192,59 @@ router.put('/:sid/Routes', async(req, res) => {
router.get('/', async(req, res) => {
const logger = req.app.locals.logger;
try {
const results = req.user.hasAdminAuth ?
await Lcr.retrieveAll() : req.user.hasAccountAuth ?
await Lcr.retrieveAllByAccountSid(req.user.hasAccountAuth ? req.user.account_sid : null) :
await Lcr.retrieveAllByServiceProviderSid(req.user.service_provider_sid);
let results;
for (const lcr of results) {
lcr.number_routes = await LcrRoutes.countAllByLcrSid(lcr.lcr_sid);
if (req.user.hasAdminAuth) {
if (isPaginationEnabled) {
validateQuery(req.query);
results = await Lcr.retrieveAllPaginated(req.query.limit, req.query.page);
} else {
results = await Lcr.retrieveAll();
}
} else if (req.user.hasAccountAuth) {
if (isPaginationEnabled) {
validateQuery(req.query);
results = await Lcr.retrieveAllByAccountSidPaginated(
req.user.account_sid,
req.query.limit,
req.query.page
);
} else {
results = await Lcr.retrieveAllByAccountSid(req.user.account_sid);
}
} else if (req.user.hasServiceProviderAuth) {
if (isPaginationEnabled) {
validateQuery(req.query);
results = await Lcr.retrieveAllByServiceProviderSidPaginated(
req.user.service_provider_sid,
req.query.limit,
req.query.page
);
if (results.data.length) {
for (const lcr of results?.data || results) {
lcr.number_routes = await LcrRoutes.countAllByLcrSid(lcr.lcr_sid);
}
}
} else {
results = await Lcr.retrieveAllByServiceProviderSid(req.user.service_provider_sid);
}
}
if (Array.isArray(results)) {
for (const lcr of results) {
lcr.number_routes = await LcrRoutes.countAllByLcrSid(lcr.lcr_sid);
}
} else {
for (const lcr of results.data) {
lcr.number_routes = await LcrRoutes.countAllByLcrSid(lcr.lcr_sid);
}
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);

View File

@@ -13,7 +13,8 @@ const preconditions = {
};
const sysError = require('../error');
const { parsePhoneNumberSid } = require('./utils');
const { isPaginationEnabled } = require('../../config');
const { validateQuery } = require('../../utils/validate-query');
/* check for required fields when adding */
async function validateAdd(req) {
@@ -94,9 +95,31 @@ decorate(router, PhoneNumber, ['add', 'update', 'delete'], preconditions);
router.get('/', async(req, res) => {
const logger = req.app.locals.logger;
try {
const results = req.user.hasServiceProviderAuth ?
await PhoneNumber.retrieveAllForSP(req.user.service_provider_sid) :
await PhoneNumber.retrieveAll(req.user.hasAccountAuth ? req.user.account_sid : null);
let results;
if (req.user.hasServiceProviderAuth) {
if (isPaginationEnabled) {
validateQuery(req.query);
results = await PhoneNumber.retrieveAllForSPPaginated(
req.user.service_provider_sid,
req.query.limit,
req.query.page
);
} else {
results = await PhoneNumber.retrieveAllForSP(req.user.service_provider_sid);
}
} else {
if (isPaginationEnabled) {
validateQuery(req.query);
results = await PhoneNumber.retrieveAllPaginated(
req.user.account_sid,
req.query.limit,
req.query.page
);
} else {
results = await PhoneNumber.retrieveAll(req.user.account_sid);
}
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);

View File

@@ -15,6 +15,8 @@ const {
} = require('./utils');
const sysError = require('../error');
const decorate = require('./decorate');
const { validateQuery } = require('../../utils/validate-query');
const { isPaginationEnabled } = require('../../config');
const preconditions = {
'delete': noActiveAccountsOrUsers
};
@@ -103,13 +105,24 @@ 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;
const {limit, page} = req.query;
try {
await validateRetrieve(req);
const service_provider_sid = parseServiceProviderSid(req);
let results = await Account.retrieveAll(service_provider_sid);
if (req.user.hasScope('account')) {
results = results.filter((r) => r.account_sid === req.user.account_sid);
const account_sid = req.user.hasScope('account') ? req.user.account_sid : null;
let results;
if (isPaginationEnabled && limit && page) {
validateQuery(req.query);
results = await Account.retrieveAllPaginated(
service_provider_sid,
account_sid,
req.query.limit,
req.query.page
);
} else {
results = await Account.retrieveAll(service_provider_sid);
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);
@@ -121,41 +134,98 @@ router.get('/:sid/Applications', async(req, res) => {
try {
await validateRetrieve(req);
const service_provider_sid = parseServiceProviderSid(req);
let results = await Application.retrieveAll(service_provider_sid);
if (req.user.hasScope('account')) {
results = results.filter((r) => r.account_sid === req.user.account_sid);
const account_sid = req.user.hasScope('account') ? req.user.account_sid : null;
let results;
if (isPaginationEnabled) {
validateQuery(req.query);
results = await Application.retrieveAllPaginated(
service_provider_sid,
account_sid,
req.query.limit,
req.query.page
);
} else {
results = await Application.retrieveAll(service_provider_sid, account_sid);
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);
}
});
router.get('/:sid/Accounts/Availability', async(req, res) => {
const logger = req.app.locals.logger;
const { sid } = req.params;
const { property, value } = req.query;
try {
const results = await Account.isPropertyAvailable(property, [sid, value]);
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);
}
});
router.get('/:sid/PhoneNumbers', async(req, res) => {
const logger = req.app.locals.logger;
try {
await validateRetrieve(req);
let results;
const service_provider_sid = parseServiceProviderSid(req);
let results = await PhoneNumber.retrieveAllForSP(service_provider_sid);
if (req.user.hasScope('account')) {
results = results.filter((r) => r.account_sid === req.user.account_sid);
if (isPaginationEnabled) {
validateQuery(req.query);
results = await PhoneNumber.retrieveAllForSPPaginated(service_provider_sid, req.query.limit, req.query.page);
if (req.user.hasScope('account')) {
results.data = results.data.filter((r) => r.account_sid === req.user.account_sid);
}
} else {
results = await PhoneNumber.retrieveAllForSP(service_provider_sid);
if (req.user.hasScope('account')) {
results = results.filter((r) => r.account_sid === req.user.account_sid);
}
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);
}
});
router.get('/:sid/VoipCarriers', async(req, res) => {
const logger = req.app.locals.logger;
try {
await validateRetrieve(req);
const service_provider_sid = parseServiceProviderSid(req);
const carriers = await VoipCarrier.retrieveAllForSP(service_provider_sid);
const account_sid = req.user.hasScope('account') ? req.user.account_sid : null;
let carriers;
if (isPaginationEnabled) {
validateQuery(req.query);
if (account_sid) {
carriers = await VoipCarrier.retrieveAllPaginated(
account_sid,
req.query.limit,
req.query.page
);
} else {
carriers = await VoipCarrier.retrieveAllForSPPaginated(
service_provider_sid,
req.query.limit,
req.query.page
);
}
if (req.user.hasScope('account')) {
return res.status(200).json(carriers.filter((c) => c.account_sid === req.user.account_sid || !c.account_sid));
} else {
if (account_sid) {
carriers = await VoipCarrier.retrieveAll(account_sid);
} else {
carriers = await VoipCarrier.retrieveAllForSP(service_provider_sid);
}
}
res.status(200).json(carriers);
return res.status(200).json(carriers);
} catch (err) {
sysError(logger, res, err);
}
@@ -185,15 +255,31 @@ router.put('/:sid/VoipCarriers/:voip_carrier_sid', async(req, res) => {
sysError(logger, res, err);
}
});
router.get('/:sid/ApiKeys', async(req, res) => {
const logger = req.app.locals.logger;
const {sid} = req.params;
const { sid } = req.params;
try {
await validateRetrieve(req);
let results = await ApiKey.retrieveAllForSP(sid);
if (req.user.hasScope('account')) {
results = results.filter((r) => r.account_sid === req.user.account_sid);
const account_sid = req.user.hasScope('account') ? req.user.account_sid : null;
let results;
if (isPaginationEnabled) {
validateQuery(req.query);
if (account_sid) {
results = await ApiKey.retrieveAllPaginated(account_sid, req.query.limit, req.query.page);
} else {
results = await ApiKey.retrieveAllForSPPaginated(sid, req.query.limit, req.query.page);
}
} else {
if (account_sid) {
results = await ApiKey.retrieveAll(account_sid);
} else {
results = await ApiKey.retrieveAllForSP(sid);
}
}
res.status(200).json(results);
await ApiKey.updateLastUsed(sid);
} catch (err) {
@@ -226,14 +312,27 @@ router.post('/', async(req, res) => {
/* list */
router.get('/', async(req, res) => {
const logger = req.app.locals.logger;
const { limit, page } = req.query;
try {
const results = await ServiceProvider.retrieveAll();
logger.debug({results, user: req.user}, 'ServiceProvider.retrieveAll');
if (req.user.hasScope('service_provider') || req.user.hasScope('account')) {
logger.debug(`Filtering results for ${req.user.service_provider_sid}`);
return res.status(200).json(results.filter((e) => req.user.service_provider_sid === e.service_provider_sid));
let results;
if (isPaginationEnabled && limit && page) {
validateQuery(req.query);
results = await ServiceProvider.retrieveAllPaginated(req.query.limit, req.query.page);
if (req.user.hasScope('service_provider') || req.user.hasScope('account')) {
logger.debug(`Filtering results for ${req.user.service_provider_sid}`);
results.data = results.data.filter((e) => req.user.service_provider_sid === e.service_provider_sid);
}
} else {
results = await ServiceProvider.retrieveAll();
if (req.user.hasScope('service_provider') || req.user.hasScope('account')) {
logger.debug(`Filtering results for ${req.user.service_provider_sid}`);
results = results.filter((e) => req.user.service_provider_sid === e.service_provider_sid);
}
}
logger.debug({ results, user: req.user }, 'ServiceProvider.retrieveAll');
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);

View File

@@ -3,10 +3,13 @@ const User = require('../../models/user');
const {DbErrorBadRequest, BadRequestError, DbErrorForbidden} = require('../../utils/errors');
const {generateHashedPassword, verifyPassword} = require('../../utils/password-utils');
const {promisePool} = require('../../db');
const {validatePasswordSettings, parseUserSid} = require('./utils');
const {validatePasswordSettings, parseUserSid, hasUserScope} = require('./utils');
const {decrypt} = require('../../utils/encrypt-decrypt');
const {cacheClient} = require('../../helpers');
const sysError = require('../error');
const { isPaginationEnabled } = require('../../config');
const { validateQuery } = require('../../utils/validate-query');
const retrieveMyDetails = `SELECT *
FROM users user
JOIN accounts AS account ON account.account_sid = user.account_sid
@@ -141,63 +144,88 @@ const ensureUserRetrievalIsAllowed = (req, user) => {
}
};
const buildUser = (user) => {
const {
user_sid,
name,
email,
force_change,
is_active,
account_sid,
service_provider_sid,
account_name,
service_provider_name,
cognigy_user_id,
} = user || {};
let scope;
if (account_sid && service_provider_sid) {
scope = 'account';
} else if (service_provider_sid) {
scope = 'service_provider';
} else {
scope = 'admin';
}
const obj = {
user_sid,
name,
email,
scope,
force_change,
is_active,
...(account_sid && { account_sid }),
...(account_name && { account_name }),
...(service_provider_sid && { service_provider_sid }),
...(service_provider_name && { service_provider_name }),
...(cognigy_user_id && { cognigy_user_id }),
};
return obj;
};
router.get('/', async(req, res) => {
const logger = req.app.locals.logger;
let usersList;
let results;
try {
let results;
if (req.user.hasAdminAuth) {
results = await User.retrieveAll();
}
else if (req.user.hasAccountAuth) {
results = await User.retrieveAllForAccount(req.user.account_sid, true);
}
else if (req.user.hasServiceProviderAuth) {
results = await User.retrieveAllForServiceProvider(req.user.service_provider_sid, true);
if (hasUserScope('admin', req)) {
if (isPaginationEnabled) {
validateQuery(req.query);
results = await User.retrieveAllPaginated(req.query.limit, req.query.page);
} else {
results = await User.retrieveAll();
}
} else if (hasUserScope('account', req)) {
if (isPaginationEnabled) {
validateQuery(req.query);
results = await User.retrieveAllForAccountPaginated(req.user.account_sid, req.query.limit, req.query.page);
} else {
results = await User.retrieveAllForAccount(req.user.account_sid, true);
}
} else if (hasUserScope('sp', req)) {
if (isPaginationEnabled) {
validateQuery(req.query);
results = await User.retrieveAllForServiceProviderPaginated(
req.user.service_provider_sid,
req.query.limit,
req.query.page
);
} else {
results = await User.retrieveAllForServiceProvider(req.user.service_provider_sid, true);
}
}
if (results.length === 0) throw new Error('failure retrieving users list');
usersList = results.map((user) => {
const {
user_sid,
name,
email,
force_change,
is_active,
account_sid,
service_provider_sid,
account_name,
service_provider_name
} = user;
let scope;
if (account_sid && service_provider_sid) {
scope = 'account';
} else if (service_provider_sid) {
scope = 'service_provider';
} else {
scope = 'admin';
}
if (isPaginationEnabled) {
results.data = results.data.map((user) => buildUser(user));
} else {
results = results.map((user) => buildUser(user));
}
const obj = {
user_sid,
name,
email,
scope,
force_change,
is_active,
...(account_sid && {account_sid}),
...(account_name && {account_name}),
...(service_provider_sid && {service_provider_sid}),
...(service_provider_name && {service_provider_name})
};
return obj;
});
} catch (err) {
sysError(logger, res, err);
}
res.status(200).json(usersList);
res.status(200).json(results);
});
router.get('/me', async(req, res) => {

View File

@@ -313,6 +313,22 @@ const hasServiceProviderPermissions = (req, res, next) => {
}
};
const hasUserScope = (scope, req) => {
const {user} = req || {};
const {hasServiceProviderAuth, hasAccountAuth, hasAdminAuth} = user || {};
switch (scope) {
case 'admin':
return hasAdminAuth;
case 'sp':
return hasServiceProviderAuth;
case 'account':
return hasAccountAuth;
default:
return false;
}
};
const checkLimits = async(req, res, next) => {
const logger = req.app.locals.logger;
if (process.env.APPLY_JAMBONZ_DB_LIMITS && req.user.hasScope('account')) {
@@ -460,5 +476,6 @@ module.exports = {
checkLimits,
enableSubspace,
disableSubspace,
validatePasswordSettings
validatePasswordSettings,
hasUserScope,
};

View File

@@ -5,6 +5,8 @@ const {promisePool} = require('../../db');
const decorate = require('./decorate');
const sysError = require('../error');
const { parseVoipCarrierSid } = require('./utils');
const { isPaginationEnabled } = require('../../config');
const { validateQuery } = require('../../utils/validate-query');
const validate = async(req) => {
const {lookupAppBySid, lookupAccountBySid} = req.app.locals;
@@ -74,9 +76,33 @@ decorate(router, VoipCarrier, ['add', 'update', 'delete'], preconditions);
router.get('/', async(req, res) => {
const logger = req.app.locals.logger;
try {
const results = req.user.hasAdminAuth ?
await VoipCarrier.retrieveAll(req.user.hasAccountAuth ? req.user.account_sid : null) :
await VoipCarrier.retrieveAllForSP(req.user.service_provider_sid);
let results;
if (req.user.hasAdminAuth) {
const account_sid = req.user.hasAccountAuth ? req.user.account_sid : null;
if (isPaginationEnabled) {
validateQuery(req.query);
results = await VoipCarrier.retrieveAllPaginated(
account_sid,
req.query.limit,
req.query.page
);
} else {
results = await VoipCarrier.retrieveAll(account_sid);
}
} else {
if (isPaginationEnabled) {
validateQuery(req.query);
results = await VoipCarrier.retrieveAllForSPPaginated(
req.user.service_provider_sid,
req.query.limit,
req.query.page
);
} else {
results = await VoipCarrier.retrieveAllForSP(req.user.service_provider_sid);
}
}
if (req.user.hasScope('account')) {
return res.status(200).json(results.filter((c) => c.account_sid === req.user.account_sid || !c.account_sid));

View File

@@ -2,7 +2,13 @@ const express = require('express');
const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
const path = require('path');
const swaggerDocument = YAML.load(path.resolve(__dirname, '../swagger/swagger.yaml'));
const { isPaginationEnabled } = require('../config');
let swaggerFilepath = '../swagger/swagger.yaml';
if (isPaginationEnabled) {
swaggerFilepath = '../swagger/swagger-pagination.yaml';
}
const swaggerDocument = YAML.load(path.resolve(__dirname, swaggerFilepath));
const api = require('./api');
const stripe = require('./stripe');
const {checkLimits} = require('./api/utils');

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
const { DbErrorBadRequest } = require('../utils/errors');
const validateQuery = (query) => {
const { page = 1, limit = 25 } = query || {};
query.page = Number(page);
query.limit = Number(limit);
if (query.page < 1) {
throw new DbErrorBadRequest('invalid "page" query parameter');
}
switch (query.limit) {
case 25:
case 50:
case 100:
break;
default:
throw new DbErrorBadRequest('invalid "limit" query parameter');
}
return true;
};
module.exports = {
validateQuery
};