collabSupport/services/voicePin/resetVoicemailPin.js
jmcqueen 2ec2b7a486 Add /resetvmpin and /resetvppin with confirmation cards for Webex PIN resets.
Chat-only commands reset voicemail mailbox and voice portal passcodes via telephony_config_write, with extension lookup and unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 16:34:09 -04:00

54 lines
1.9 KiB
JavaScript

// services/voicePin/resetVoicemailPin.js
// PUT /v1/telephony/config/people/{personId}/voicemail/passcode
//
// Admin API to set a custom voicemail PIN (spark-admin:telephony_config_write).
// Do NOT use people/{id}/features/voicemail/passcode — that path does not exist.
// For org-default reset only: POST people/{id}/features/voicemail/actions/resetPin/invoke
import { logger } from '../../utils/logger.js';
import { generatePin } from './generatePin.js';
const LOG_SCOPE = 'resetvmpin:service';
const VM_PIN_LENGTH = 6;
const MAX_PUT_ATTEMPTS = 5;
function vmPasscodeEndpoint(personId) {
return `telephony/config/people/${personId}/voicemail/passcode`;
}
/**
* Reset a user's voicemail mailbox PIN.
*
* @param {string} personId
* @param {object} [opts]
* @param {object} [opts.webexClient] injectable client for tests
* @returns {Promise<string>} new PIN (never log this value)
*/
export async function resetVoicemailPin(personId, opts = {}) {
if (!personId) {
throw new Error('personId is required');
}
const client = opts.webexClient || (await import('../../integrations/webex/WebexClient.js')).default;
const endpoint = vmPasscodeEndpoint(personId);
let lastError = null;
for (let attempt = 0; attempt < MAX_PUT_ATTEMPTS; attempt += 1) {
const passcode = generatePin({ minLength: VM_PIN_LENGTH, maxLength: VM_PIN_LENGTH });
try {
await client.request('PUT', endpoint, { passcode });
logger(LOG_SCOPE, `Voicemail PIN reset succeeded for person ${personId}`, 'info');
return passcode;
} catch (err) {
lastError = err;
const status = err?.response?.status;
if (status === 400 && attempt < MAX_PUT_ATTEMPTS - 1) {
logger(LOG_SCOPE, `Voicemail PIN rejected for ${personId} (attempt ${attempt + 1}), retrying`, 'warn');
continue;
}
throw err;
}
}
throw lastError || new Error('Voicemail PIN reset failed');
}