Files
jambonz-api-server/lib/routes/api/lcrs.js
Hoan Luu Huu 0f244cf6d5 fix create update lcr generate too much request (#259)
* fix create update lcr generate too much request

* wip
2023-11-14 08:07:04 -05:00

226 lines
8.0 KiB
JavaScript

const router = require('express').Router();
const Lcr = require('../../models/lcr');
const LcrCarrierSetEntry = require('../../models/lcr-carrier-set-entry');
const LcrRoutes = require('../../models/lcr-route');
const decorate = require('./decorate');
const {DbErrorBadRequest} = require('../../utils/errors');
const sysError = require('../error');
const ServiceProvider = require('../../models/service-provider');
const validateAssociatedTarget = async(req, sid) => {
const {lookupAccountBySid} = req.app.locals;
if (req.body.account_sid) {
// Add only for account
req.body.service_provider_sid = null;
const account = await lookupAccountBySid(req.body.account_sid);
if (!account) throw new DbErrorBadRequest('unknown account_sid');
const lcr = await Lcr.retrieveAllByAccountSid(req.body.account_sid);
if (lcr.length > 0 && (!sid || sid !== lcr[0].lcr_sid)) {
throw new DbErrorBadRequest(`Account: ${account.name} already has an active call routing table.`);
}
} else if (req.body.service_provider_sid) {
const serviceProviders = await ServiceProvider.retrieve(req.body.service_provider_sid);
if (serviceProviders.length === 0) throw new DbErrorBadRequest('unknown service_provider_sid');
const serviceProvider = serviceProviders[0];
const lcr = await Lcr.retrieveAllByServiceProviderSid(req.body.service_provider_sid);
if (lcr.length > 0 && (!sid || sid !== lcr[0].lcr_sid)) {
throw new DbErrorBadRequest(`Service Provider: ${serviceProvider.name} already
has an active call routing table.`);
}
}
};
const validateAdd = async(req) => {
if (req.user.hasAccountAuth) {
// Account just create LCR for himself
req.body.account_sid = req.user.account_sid;
} else if (req.user.hasServiceProviderAuth) {
// SP just can create LCR for himself
req.body.service_provider_sid = req.user.service_provider_sid;
req.body.account_sid = null;
}
await validateAssociatedTarget(req);
// check if lcr_carrier_set_entry is available
if (req.body.lcr_carrier_set_entry) {
const e = await LcrCarrierSetEntry.retrieve(req.body.lcr_carrier_set_entry);
if (e.length === 0) throw new DbErrorBadRequest('unknown lcr_carrier_set_entry');
}
};
const validateUserPermissionForExistingEntity = async(req, sid) => {
const r = await Lcr.retrieve(sid);
if (r.length === 0) {
throw new DbErrorBadRequest('unknown lcr_sid');
}
const lcr = r[0];
if (req.user.hasAccountAuth) {
if (lcr.account_sid != req.user.account_sid) {
throw new DbErrorBadRequest('unknown lcr_sid');
}
} else if (req.user.hasServiceProviderAuth) {
if (lcr.service_provider_sid != req.user.service_provider_sid) {
throw new DbErrorBadRequest('unknown lcr_sid');
}
}
};
const validateUpdate = async(req, sid) => {
await validateUserPermissionForExistingEntity(req, sid);
await validateAssociatedTarget(req, sid);
};
const validateDelete = async(req, sid) => {
if (req.user.hasAccountAuth) {
/* can only delete Lcr for the user's account */
const r = await Lcr.retrieve(sid);
const lcr = r.length > 0 ? r[0] : null;
if (!lcr || (req.user.account_sid && lcr.account_sid != req.user.account_sid)) {
throw new DbErrorBadRequest('unknown lcr_sid');
}
}
await Lcr.releaseDefaultEntry(sid);
// fetch lcr route
const lcr_routes = await LcrRoutes.retrieveAllByLcrSid(sid);
// delete all lcr carrier set entries
for (const e of lcr_routes) {
await LcrCarrierSetEntry.deleteByLcrRouteSid(e.lcr_route_sid);
}
// delete all lcr routes
await LcrRoutes.deleteByLcrSid(sid);
};
const preconditions = {
add: validateAdd,
update: validateUpdate,
delete: validateDelete
};
decorate(router, Lcr, ['add', 'update', 'delete'], preconditions);
const validateLcrBatchAdd = async(lcr_sid, body, lookupCarrierBySid) => {
for (const lcr_route of body) {
lcr_route.lcr_sid = lcr_sid;
if (!lcr_route.lcr_carrier_set_entries || lcr_route.lcr_carrier_set_entries.length === 0) {
throw new DbErrorBadRequest('Lcr Route batch process require lcr_carrier_set_entries');
}
for (const entry of lcr_route.lcr_carrier_set_entries) {
// check voip_carrier_sid is exist
if (!entry.voip_carrier_sid) {
throw new DbErrorBadRequest('One of lcr_carrier_set_entries is missing voip_carrier_sid');
}
const carrier = await lookupCarrierBySid(entry.voip_carrier_sid);
if (!carrier) {
throw new DbErrorBadRequest('unknown voip_carrier_sid');
}
}
}
};
const addNewLcrRoute = async(lcr_route) => {
const lcr_sid = lcr_route.lcr_sid;
const lcr_carrier_set_entries = lcr_route.lcr_carrier_set_entries;
delete lcr_route.lcr_carrier_set_entries;
const lcr_route_sid = await LcrRoutes.make(lcr_route);
for (const entry of lcr_carrier_set_entries) {
entry.lcr_route_sid = lcr_route_sid;
const lcr_carrier_set_entry_sid = await LcrCarrierSetEntry.make(entry);
if (lcr_route.priority === 9999) {
// this is default lcr set entry
const [lcr] = await Lcr.retrieve(lcr_sid);
if (lcr) {
lcr.default_carrier_set_entry_sid = lcr_carrier_set_entry_sid;
delete lcr.lcr_sid;
await Lcr.update(lcr_sid, lcr);
}
}
}
};
router.post('/:sid/Routes', async(req, res) => {
const results = await Lcr.retrieve(req.params.sid);
if (results.length === 0) return res.sendStatus(404);
const {logger, lookupCarrierBySid} = req.app.locals;
try {
const body = req.body;
await validateLcrBatchAdd(req.params.sid, body, lookupCarrierBySid);
for (const lcr_route of body) {
await addNewLcrRoute(lcr_route, lookupCarrierBySid);
}
res.sendStatus(204);
} catch (err) {
sysError(logger, res, err);
}
});
router.put('/:sid/Routes', async(req, res) => {
const results = await Lcr.retrieve(req.params.sid);
if (results.length === 0) return res.sendStatus(404);
const {logger, lookupCarrierBySid} = req.app.locals;
try {
const body = req.body;
await validateLcrBatchAdd(req.params.sid, body, lookupCarrierBySid);
for (const lcr_route of body) {
if (lcr_route.lcr_route_sid) {
const lcr_route_sid = lcr_route.lcr_route_sid;
delete lcr_route.lcr_route_sid;
const lcr_carrier_set_entries = lcr_route.lcr_carrier_set_entries;
delete lcr_route.lcr_carrier_set_entries;
await LcrRoutes.update(lcr_route_sid, lcr_route);
for (const entry of lcr_carrier_set_entries) {
const lcr_carrier_set_entry_sid = entry.lcr_carrier_set_entry_sid;
delete entry.lcr_carrier_set_entry_sid;
await LcrCarrierSetEntry.update(lcr_carrier_set_entry_sid, entry);
}
} else {
// Route is not available yet, let create it now
await addNewLcrRoute(lcr_route, lookupCarrierBySid);
}
}
res.sendStatus(204);
} catch (err) {
sysError(logger, res, err);
}
});
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);
for (const lcr of results) {
lcr.number_routes = await LcrRoutes.countAllByLcrSid(lcr.lcr_sid);
}
res.status(200).json(results);
} catch (err) {
sysError(logger, res, err);
}
});
router.get('/:sid', async(req, res) => {
const logger = req.app.locals.logger;
try {
const results = await Lcr.retrieve(req.params.sid);
if (results.length === 0) return res.sendStatus(404);
const lcr = results[0];
if (req.user.hasAccountAuth && lcr.account_sid !== req.user.account_sid) {
return res.sendStatus(404);
} else if (req.user.hasServiceProviderAuth && lcr.service_provider_sid !== req.user.service_provider_sid) {
return res.sendStatus(404);
}
lcr.number_routes = await LcrRoutes.countAllByLcrSid(lcr.lcr_sid);
return res.status(200).json(lcr);
} catch (err) {
sysError(logger, res, err);
}
});
module.exports = router;