Compare commits

..

2 Commits

Author SHA1 Message Date
Quan HL
9d9cad7ccc add testcase 2023-11-24 18:09:48 +07:00
Quan HL
f33343ef7b get full registration details for all users with new querry params details = true 2023-11-24 17:59:36 +07:00
8 changed files with 64 additions and 2442 deletions

2
app.js
View File

@@ -53,7 +53,7 @@ const {
getTtsSize,
purgeTtsCache,
synthAudio
} = require('@jambonz/speech-utils')({}, logger);
} = require('@jambonz/speech-utils')({redis_client: client}, logger);
const {
lookupAppBySid,
lookupAccountBySid,

View File

@@ -148,6 +148,7 @@ router.post('/:sid/VoipCarriers', async(req, res) => {
router.get('/:sid/RegisteredSipUsers', async(req, res) => {
const {logger, registrar} = req.app.locals;
const details = req.query.details;
try {
const account_sid = parseAccountSid(req);
await validateRequest(req, account_sid);
@@ -155,45 +156,12 @@ router.get('/:sid/RegisteredSipUsers', async(req, res) => {
if (!result || result.length === 0) {
throw new DbErrorBadRequest(`account not found for sid ${account_sid}`);
}
if (!result[0].sip_realm) {
throw new DbErrorBadRequest('account does not have sip_realm configuration');
}
const users = await registrar.getRegisteredUsersForRealm(result[0].sip_realm);
res.status(200).json(users.map((u) => `${u}@${result[0].sip_realm}`));
} catch (err) {
sysError(logger, res, err);
}
});
router.post('/:sid/RegisteredSipUsers', async(req, res) => {
const {logger, registrar} = req.app.locals;
const users = req.body;
try {
const account_sid = parseAccountSid(req);
await validateRequest(req, account_sid);
const result = await Account.retrieve(account_sid);
if (!result || result.length === 0) {
throw new DbErrorBadRequest(`account not found for sid ${account_sid}`);
}
if (!result[0].sip_realm) {
throw new DbErrorBadRequest('account does not have sip_realm configuration');
}
if (!users || !Array.isArray(users) || users.length === 0) {
return res.status(200).json(await registrar.getRegisteredUsersDetailsForRealm(result[0].sip_realm));
}
const ret = [];
for (const u of users) {
const user = await registrar.query(`${u}@${result[0].sip_realm}`) || {
name: u,
contact: null,
expiryTime: 0,
protocol: null
};
ret.push({
name: u,
...user,
registered_status: user.expiryTime > 0 ? 'active' : 'inactive',
});
let ret = [];
if (details) {
ret = await registrar.getRegisteredUsersDetailsForRealm(result[0].sip_realm);
} else {
const users = await registrar.getRegisteredUsersForRealm(result[0].sip_realm);
ret = users.map((u) => `${u}@${result[0].sip_realm}`);
}
res.status(200).json(ret);
} catch (err) {
@@ -264,8 +232,7 @@ function validateUpdateCall(opts) {
'mute_status',
'sip_request',
'record',
'tag',
'dtmf'
'tag'
]
.reduce((acc, prop) => (opts[prop] ? ++acc : acc), 0);
@@ -307,9 +274,6 @@ function validateUpdateCall(opts) {
if (opts.record && !opts.record.action) {
throw new DbErrorBadRequest('record requires action property');
}
if (opts.dtmf && !opts.dtmf.digit) {
throw new DbErrorBadRequest('invalid dtmf');
}
if ('startCallRecording' === opts.record?.action && !opts.record.siprecServerURL) {
throw new DbErrorBadRequest('record requires siprecServerURL property when starting recording');
}

View File

@@ -132,8 +132,7 @@ const encryptCredential = (obj) => {
custom_tts_url,
auth_token = '',
cobalt_server_uri,
model_id,
options
model_id
} = obj;
switch (vendor) {
@@ -211,7 +210,7 @@ const encryptCredential = (obj) => {
case 'elevenlabs':
assert(api_key, 'invalid elevenLabs speech credential: api_key is required');
assert(model_id, 'invalid elevenLabs speech credential: model_id is required');
const elevenlabsData = JSON.stringify({api_key, model_id, options});
const elevenlabsData = JSON.stringify({api_key, model_id});
return encrypt(elevenlabsData);
case 'assemblyai':
@@ -412,8 +411,7 @@ router.put('/:sid', async(req, res) => {
custom_stt_url,
custom_tts_url,
cobalt_server_uri,
model_id,
options
model_id
} = req.body;
const newCred = {
@@ -435,8 +433,7 @@ router.put('/:sid', async(req, res) => {
custom_stt_url,
custom_tts_url,
cobalt_server_uri,
model_id,
options
model_id
};
logger.info({o, newCred}, 'updating speech credential with this new credential');
obj.credential = encryptCredential(newCred);
@@ -556,7 +553,7 @@ router.get('/:sid/test', async(req, res) => {
} = credential;
if (cred.use_for_tts) {
try {
await testMicrosoftTts(logger, synthAudio, {
await testMicrosoftTts(logger, {
api_key,
region,
use_custom_tts,

View File

@@ -4192,27 +4192,6 @@ paths:
type: array
items:
type: string
post:
tags:
- Accounts
summary: retrieve online sip users for an account by list of sip username
operationId: listRegisteredSipUsers
requestBody:
content:
application/json:
schema:
type: array
items:
type: string
responses:
200:
description: retrieve online sip users for an account
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/RegisteredClient'
/Accounts/{AccountSid}/RegisteredSipUsers/{Client}:
parameters:
- name: Client

View File

@@ -150,19 +150,38 @@ const testAwsStt = async(logger, credentials) => {
}
};
const testMicrosoftTts = async(logger, synthAudio, credentials) => {
const testMicrosoftTts = async(logger, credentials) => {
const {
api_key,
region,
// eslint-disable-next-line no-unused-vars
use_custom_tts,
// eslint-disable-next-line no-unused-vars
custom_tts_endpoint,
// eslint-disable-next-line no-unused-vars
use_custom_stt,
// eslint-disable-next-line no-unused-vars
custom_stt_endpoint
} = credentials;
logger.info({
api_key,
region,
use_custom_tts,
custom_tts_endpoint,
use_custom_stt,
custom_stt_endpoint
}, 'testing microsoft tts');
if (!api_key) throw new Error('testMicrosoftTts: credentials are missing api_key');
if (!region) throw new Error('testMicrosoftTts: credentials are missing region');
try {
await synthAudio({increment: () => {}, histogram: () => {}},
{
vendor: 'microsoft',
credentials,
language: 'en-US',
voice: 'en-US-JennyMultilingualNeural',
text: 'Hi there and welcome to jambones!'
}
);
const getJSON = bent('json', {
'Ocp-Apim-Subscription-Key': api_key
});
const response = await getJSON(`https://${region}.tts.speech.microsoft.com/cognitiveservices/voices/list`);
return response;
} catch (err) {
logger.info({err}, 'testMicrosoftTts returned error');
logger.info({err}, `testMicrosoftTts - failed to list voices for region ${region}`);
throw err;
}
};
@@ -376,7 +395,6 @@ function decryptCredential(obj, credential, logger, isObscureKey = true) {
const o = JSON.parse(decrypt(credential));
obj.api_key = isObscureKey ? obscureKey(o.api_key) : o.api_key;
obj.model_id = o.model_id;
obj.options = o.options;
} else if (obj.vendor.startsWith('custom:')) {
const o = JSON.parse(decrypt(credential));
obj.auth_token = isObscureKey ? obscureKey(o.auth_token) : o.auth_token;

2357
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -27,9 +27,9 @@
"@google-cloud/storage": "^6.12.0",
"@jambonz/db-helpers": "^0.9.1",
"@jambonz/lamejs": "^1.2.2",
"@jambonz/mw-registrar": "^0.2.7",
"@jambonz/mw-registrar": "^0.2.5",
"@jambonz/realtimedb-helpers": "^0.8.7",
"@jambonz/speech-utils": "^0.0.31",
"@jambonz/speech-utils": "^0.0.26",
"@jambonz/time-series": "^0.2.8",
"@jambonz/verb-specifications": "^0.0.45",
"@soniox/soniox-node": "^1.1.1",

View File

@@ -85,22 +85,11 @@ test('client test', async(t) => {
t.ok(result.length === 1 && result[0] === 'dhorton@drachtio.org',
'successfully queried all registered clients');
result = await request.post(`/Accounts/${account_sid}/RegisteredSipUsers`, {
resolveWithFullResponse: true,
auth: authAdmin,
json: true,
body: ['dhorton']
});
t.ok(result.body.length === 1 && result.body[0].name === 'dhorton',
'successfully queried all registered clients');
result = await request.post(`/Accounts/${account_sid}/RegisteredSipUsers`, {
resolveWithFullResponse: true,
result = await request.get(`/Accounts/${account_sid}/RegisteredSipUsers?details=true`, {
auth: authAdmin,
json: true,
body: []
});
t.ok(result.body.length === 1 && result.body[0].name === 'dhorton',
t.ok(result.length === 1 && result[0].name === 'dhorton',
'successfully queried all registered clients');
/* query all entity */