// commands/resetVmPin.js // // /resetvmpin — reset a user's voicemail mailbox PIN with confirmation card. // // Targets: email, 2–4 digit store number, or 5-digit extension. import { logger } from '../utils/logger.js'; import { pendingVmPinResets } from '../utils/pendingVmPinResets.js'; import { extractRequester, describeRequester } from '../utils/requester.js'; import { parseVmPinTarget, resolveVmPinTarget, } from '../services/voicePin/resolveVmPinTarget.js'; import { resetVoicemailPin } from '../services/voicePin/resetVoicemailPin.js'; function matchSourceLabel(source) { switch (source) { case 'email': return 'Email lookup'; case 'store': return 'Store user'; case 'extension': return 'Extension lookup'; default: return source || '—'; } } function buildConfirmationCard(cardId, resolved) { const facts = [ { title: 'User', value: resolved.displayName }, { title: 'Email', value: resolved.email }, { title: 'Person ID', value: resolved.personId }, { title: 'Match source', value: matchSourceLabel(resolved.matchSource) }, ]; if (resolved.storeNum) { facts.push({ title: 'Store', value: resolved.storeNum }); } if (resolved.locationName) { facts.push({ title: 'Location', value: resolved.locationName }); } if (resolved.mainNumber) { facts.push({ title: 'Main number', value: resolved.mainNumber }); } if (resolved.extension) { facts.push({ title: 'Extension', value: resolved.extension }); } facts.push({ title: 'Voicemail enabled', value: resolved.voicemailEnabled == null ? 'Unknown' : (resolved.voicemailEnabled ? 'Yes' : 'No'), }); return { type: 'AdaptiveCard', version: '1.3', body: [ { type: 'TextBlock', text: '🔐 RESET VOICEMAIL PIN', weight: 'Bolder', size: 'Large', color: 'Attention', }, { type: 'TextBlock', text: 'Confirming will generate a new **6-digit voicemail PIN** and apply it immediately. ' + 'The new PIN will be posted in this space after confirmation.', wrap: true, spacing: 'Small', }, { type: 'FactSet', spacing: 'Medium', facts, }, ], actions: [ { type: 'Action.Submit', title: '✅ Confirm Reset', data: { action: 'confirm_reset_vmpin', cardId }, }, { type: 'Action.Submit', title: '❌ Cancel', data: { action: 'cancel_reset_vmpin', cardId }, }, ], }; } export async function applyResetVmPinConfirmation(bot, data, _roomId, requester) { logger( 'resetvmpin:audit', `CONFIRMED voicemail PIN reset for ${data.email} (person=${data.personId}) by ${describeRequester(requester)}`, ); try { const newPin = await resetVoicemailPin(data.personId); await bot.say( 'markdown', `✅ Voicemail PIN reset for **${data.displayName}** (\`${data.email}\`).\n\n` + `**New voicemail PIN:** \`${newPin}\`\n\n` + '_Share this PIN only in trusted spaces._', ); logger( 'resetvmpin:audit', `COMPLETED voicemail PIN reset for ${data.email} (person=${data.personId}) by ${describeRequester(requester)}`, ); } catch (err) { const apiMsg = err?.response?.data?.message || err.message; logger( 'resetvmpin:audit', `FAILED voicemail PIN reset for ${data.email}: ${apiMsg}`, 'error', ); await bot.say( 'markdown', `❌ Voicemail PIN reset failed for **${data.displayName}**: ${apiMsg}`, ); } } export async function cancelResetVmPinCard(bot, data, _roomId, requester) { await bot.say( 'markdown', `❌ Voicemail PIN reset cancelled for **${data.displayName}** (\`${data.email}\`). No changes were made.`, ); logger( 'resetvmpin:audit', `CANCELLED voicemail PIN reset for ${data.email} by ${describeRequester(requester)}`, ); } export async function handleResetVmPin(bot, trigger) { const args = trigger.args || []; const query = trigger.query || {}; const target = (args[0] || query.target || query.email || query.store || query.extension || '').trim(); if (!target) { await bot.say( 'markdown', '**Usage:** `/resetvmpin `\n\n' + '• Email: `user@ae.com`\n' + '• Store: `782` (2–4 digits)\n' + '• Extension: `12345` (5 digits)', ); return; } const parsed = parseVmPinTarget(target); if (!parsed) { await bot.say( 'markdown', `❌ Invalid target \`${target}\`. Use email, 2–4 digit store number, or 5-digit extension.`, ); return; } const requester = extractRequester(trigger); logger( 'resetvmpin:audit', `REQUESTED voicemail PIN reset card for ${target} by ${describeRequester(requester)}`, ); try { const resolved = await resolveVmPinTarget(parsed); if (!trigger.person) { await bot.say( 'markdown', `Resolved **${resolved.displayName}** (\`${resolved.email}\`). ` + 'Confirmation cards are only available in Webex chat.', ); return; } const cardId = `vmpin-${Date.now()}`; pendingVmPinResets.set(cardId, { ...resolved, roomId: trigger.roomId || trigger.message?.roomId, requester, }); const adaptiveCard = buildConfirmationCard(cardId, resolved); await bot.say({ markdown: `Review voicemail PIN reset for **${resolved.displayName}** (\`${resolved.email}\`):`, attachments: [{ contentType: 'application/vnd.microsoft.card.adaptive', content: adaptiveCard, }], }); } catch (err) { logger('resetvmpin', `Resolve failed for ${target}: ${err.message}`, 'warn'); await bot.say('markdown', `❌ ${err.message}`); } }