mirror of
https://github.com/jambonz/jambonz-api-server.git
synced 2026-07-24 13:02:16 +00:00
d4f2be3dc1
* add check for users to delete function * fix typo * fix active admin check --------- Co-authored-by: eglehelms <e.helms@cognigy.com>
281 lines
9.7 KiB
JavaScript
281 lines
9.7 KiB
JavaScript
const router = require('express').Router();
|
|
const {promisePool} = require('../../db');
|
|
const {DbErrorUnprocessableRequest, DbErrorForbidden} = require('../../utils/errors');
|
|
const Webhook = require('../../models/webhook');
|
|
const ServiceProvider = require('../../models/service-provider');
|
|
const Account = require('../../models/account');
|
|
const VoipCarrier = require('../../models/voip-carrier');
|
|
const Application = require('../../models/application');
|
|
const PhoneNumber = require('../../models/phone-number');
|
|
const ApiKey = require('../../models/api-key');
|
|
const {hasServiceProviderPermissions, parseServiceProviderSid} = require('./utils');
|
|
const sysError = require('../error');
|
|
const decorate = require('./decorate');
|
|
const preconditions = {
|
|
'delete': noActiveAccountsOrUsers
|
|
};
|
|
const sqlDeleteSipGateways = `DELETE from sip_gateways
|
|
WHERE voip_carrier_sid IN (
|
|
SELECT voip_carrier_sid
|
|
FROM voip_carriers
|
|
WHERE service_provider_sid = ?
|
|
)`;
|
|
const sqlDeleteSmppGateways = `DELETE from smpp_gateways
|
|
WHERE voip_carrier_sid IN (
|
|
SELECT voip_carrier_sid
|
|
FROM voip_carriers
|
|
WHERE service_provider_sid = ?
|
|
)`;
|
|
|
|
/* only admin users can add a service provider */
|
|
function validateAdd(req) {
|
|
if (!req.user.hasAdminAuth) {
|
|
throw new DbErrorForbidden('only admin users can add a service provider');
|
|
}
|
|
}
|
|
|
|
async function validateRetrieve(req) {
|
|
const service_provider_sid = parseServiceProviderSid(req);
|
|
if (req.user.hasScope('admin')) return ;
|
|
if (req.user.hasScope('service_provider')) {
|
|
if (service_provider_sid === req.user.service_provider_sid) return ;
|
|
}
|
|
if (req.user.hasScope('account')) {
|
|
/* allow account users to retrieve service provider data from parent SP */
|
|
const sid = req.user.account_sid;
|
|
const [r] = await promisePool.execute('SELECT service_provider_sid from accounts WHERE account_sid = ?', [sid]);
|
|
if (r.length === 1 && r[0].service_provider_sid === req.user.service_provider_sid) return;
|
|
}
|
|
throw new DbErrorForbidden('insufficient permissions to update service provider');
|
|
}
|
|
|
|
function validateUpdate(req) {
|
|
if (req.user.hasScope('admin')) return ;
|
|
if (req.user.hasScope('service_provider')) {
|
|
const service_provider_sid = parseServiceProviderSid(req);
|
|
if (service_provider_sid === req.user.service_provider_sid) return ;
|
|
}
|
|
throw new DbErrorForbidden('insufficient permissions to update service provider');
|
|
}
|
|
|
|
/* can not delete a service provider if it has any active accounts */
|
|
async function noActiveAccountsOrUsers(req, sid) {
|
|
if (!req.user.hasAdminAuth) {
|
|
throw new DbErrorForbidden('only admin users can delete a service provider');
|
|
}
|
|
const activeAccounts = await ServiceProvider.getForeignKeyReferences('accounts.service_provider_sid', sid);
|
|
const activeUsers = await ServiceProvider.getForeignKeyReferences('users.service_provider_sid', sid);
|
|
if (activeAccounts > 0 && activeUsers > 0) throw new DbErrorUnprocessableRequest(
|
|
'cannot delete service provider with active accounts or users'
|
|
);
|
|
|
|
if (activeAccounts > 0) throw new DbErrorUnprocessableRequest('cannot delete service provider with active accounts');
|
|
if (activeUsers > 0) throw new DbErrorUnprocessableRequest(
|
|
'cannot delete service provider with active service provider level users'
|
|
);
|
|
|
|
/* ok we can delete -- no active accounts. remove carriers and speech credentials */
|
|
await promisePool.execute('DELETE from speech_credentials WHERE service_provider_sid = ?', [sid]);
|
|
await promisePool.query(sqlDeleteSipGateways, [sid]);
|
|
await promisePool.query(sqlDeleteSmppGateways, [sid]);
|
|
await promisePool.query('DELETE from voip_carriers WHERE service_provider_sid = ?', [sid]);
|
|
}
|
|
|
|
decorate(router, ServiceProvider, ['delete'], preconditions);
|
|
|
|
router.use('/:sid/RecentCalls', hasServiceProviderPermissions, require('./recent-calls'));
|
|
router.use('/:sid/Alerts', hasServiceProviderPermissions, require('./alerts'));
|
|
router.use('/:sid/SpeechCredentials', 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;
|
|
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);
|
|
}
|
|
res.status(200).json(results);
|
|
} catch (err) {
|
|
sysError(logger, res, err);
|
|
}
|
|
});
|
|
router.get('/:sid/Applications', async(req, res) => {
|
|
const logger = req.app.locals.logger;
|
|
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);
|
|
}
|
|
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);
|
|
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);
|
|
}
|
|
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);
|
|
|
|
if (req.user.hasScope('account')) {
|
|
return res.status(200).json(carriers.filter((c) => c.account_sid === req.user.account_sid || !c.account_sid));
|
|
}
|
|
|
|
res.status(200).json(carriers);
|
|
} catch (err) {
|
|
sysError(logger, res, err);
|
|
}
|
|
});
|
|
router.post('/:sid/VoipCarriers', async(req, res) => {
|
|
const logger = req.app.locals.logger;
|
|
try {
|
|
validateUpdate(req);
|
|
const service_provider_sid = parseServiceProviderSid(req);
|
|
const uuid = await VoipCarrier.make({...req.body, service_provider_sid});
|
|
res.status(201).json({sid: uuid});
|
|
} catch (err) {
|
|
sysError(logger, res, err);
|
|
}
|
|
});
|
|
router.put('/:sid/VoipCarriers/:voip_carrier_sid', async(req, res) => {
|
|
const logger = req.app.locals.logger;
|
|
try {
|
|
validateUpdate(req);
|
|
const rowsAffected = await VoipCarrier.update(req.params.voip_carrier_sid, req.body);
|
|
if (rowsAffected === 0) {
|
|
return res.sendStatus(404);
|
|
}
|
|
res.status(204).end();
|
|
} catch (err) {
|
|
sysError(logger, res, err);
|
|
}
|
|
});
|
|
router.get('/:sid/ApiKeys', async(req, res) => {
|
|
const logger = req.app.locals.logger;
|
|
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);
|
|
}
|
|
res.status(200).json(results);
|
|
await ApiKey.updateLastUsed(sid);
|
|
} catch (err) {
|
|
sysError(logger, res, err);
|
|
}
|
|
});
|
|
|
|
/* add */
|
|
router.post('/', async(req, res) => {
|
|
const logger = req.app.locals.logger;
|
|
try {
|
|
validateAdd(req);
|
|
|
|
// create webhooks if provided
|
|
const obj = Object.assign({}, req.body);
|
|
for (const prop of ['registration_hook']) {
|
|
if (obj[prop]) {
|
|
obj[`${prop}_sid`] = await Webhook.make(obj[prop]);
|
|
delete obj[prop];
|
|
}
|
|
}
|
|
|
|
//logger.debug(`Attempting to add account ${JSON.stringify(obj)}`);
|
|
const uuid = await ServiceProvider.make(obj);
|
|
res.status(201).json({sid: uuid});
|
|
} catch (err) {
|
|
sysError(logger, res, err);
|
|
}
|
|
});
|
|
|
|
/* list */
|
|
router.get('/', async(req, res) => {
|
|
const logger = req.app.locals.logger;
|
|
|
|
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));
|
|
}
|
|
|
|
res.status(200).json(results);
|
|
} catch (err) {
|
|
sysError(logger, res, err);
|
|
}
|
|
});
|
|
|
|
/* retrieve */
|
|
router.get('/:sid', async(req, res) => {
|
|
const logger = req.app.locals.logger;
|
|
try {
|
|
const results = await ServiceProvider.retrieve(req.params.sid);
|
|
if (results.length === 0) return res.status(404).end();
|
|
return res.status(200).json(results[0]);
|
|
}
|
|
catch (err) {
|
|
sysError(logger, res, err);
|
|
}
|
|
});
|
|
|
|
/* update */
|
|
router.put('/:sid', async(req, res) => {
|
|
const sid = req.params.sid;
|
|
const logger = req.app.locals.logger;
|
|
try {
|
|
validateUpdate(req);
|
|
|
|
// create webhooks if provided
|
|
const obj = Object.assign({}, req.body);
|
|
for (const prop of ['registration_hook']) {
|
|
if (prop in obj && Object.keys(obj[prop]).length) {
|
|
if ('webhook_sid' in obj[prop]) {
|
|
const sid = obj[prop]['webhook_sid'];
|
|
delete obj[prop]['webhook_sid'];
|
|
await Webhook.update(sid, obj[prop]);
|
|
}
|
|
else {
|
|
const sid = await Webhook.make(obj[prop]);
|
|
obj[`${prop}_sid`] = sid;
|
|
}
|
|
}
|
|
else {
|
|
obj[`${prop}_sid`] = null;
|
|
}
|
|
delete obj[prop];
|
|
}
|
|
|
|
const rowsAffected = await ServiceProvider.update(sid, obj);
|
|
if (rowsAffected === 0) {
|
|
return res.status(404).end();
|
|
}
|
|
res.status(204).end();
|
|
} catch (err) {
|
|
sysError(logger, res, err);
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|