Introduces a new diagnostic command that walks a registry of check
modules against a store user's Webex Calling configuration and
surfaces per-issue adaptive-card remediation for the fixable ones.
Checks (services/voiceDiag/checks/): dnd, callForwarding, callWaiting,
callIntercept, voicemail, hoteling, executiveAssistant,
outgoingPermission, phoneOnline. Remediations offered for DND,
forwarding, waiting, and intercept.
Uses the /v1/people/{id}/features/* admin surface (spark-admin:people_read
+ spark-admin:people_write scopes we already hold) — the earlier
telephony/config/people/*/callSettings/* path scheme returns 404 from
the Webex gateway and is not a live surface. Runner distinguishes
routing-404s ("URL moved") from "not applicable" 404s ("no calling
license") via the response body.
Arg parser accepts detail/detailed/--detail/--detailed and normalises
macOS smart-dashes so --detailed doesn't die when auto-correct
turns it into an em-dash.
Wires a VOICEDIAG_ACTIONS dispatcher in index.js mirroring the IGMP
branch, and registers /voicediag in commands/registry.js. 170 tests
pass (52 new: 39 check + 12 renderer + 5 arg-normalization).
Docs updated in .env.example, services/phoneService.js:467, and a new
services/voiceDiag/README.md that includes a "how to add a check"
recipe plus a note on the earlier wrong URL scheme.
Co-authored-by: Cursor <cursoragent@cursor.com>
46 lines
1.4 KiB
JavaScript
46 lines
1.4 KiB
JavaScript
// src/services/voiceDiag/checks/hoteling.js
|
|
//
|
|
// Info-only check for the Hoteling feature on the store user's line.
|
|
// Hoteling lets a "guest" line temporarily associate with a shared
|
|
// desk phone — if it's turned on for a store user that shouldn't have
|
|
// it, calls can end up at whatever guest device most recently checked
|
|
// in, which usually presents as "the phone at the store isn't the
|
|
// one that rings when we call". No remediation is offered because
|
|
// the intended state is site-dependent; the operator can flip it via
|
|
// Control Hub if the current state is wrong.
|
|
//
|
|
// Endpoint: GET /v1/people/{personId}/features/hoteling
|
|
// Scope: spark-admin:people_read
|
|
// Response shape: { enabled: boolean }
|
|
|
|
const ENDPOINT = (personId) =>
|
|
`people/${personId}/features/hoteling`;
|
|
|
|
export const hotelingCheck = {
|
|
id: 'hoteling',
|
|
label: 'Hoteling',
|
|
requires: ['personId'],
|
|
scope: 'spark-admin:people_read',
|
|
|
|
async run(ctx) {
|
|
const data = await ctx.webex.request('GET', ENDPOINT(ctx.personId));
|
|
const enabled = !!data?.enabled;
|
|
|
|
if (!enabled) {
|
|
return {
|
|
status: 'ok',
|
|
message: 'Hoteling is disabled (normal for a store line).',
|
|
details: { enabled },
|
|
remediation: null,
|
|
};
|
|
}
|
|
|
|
return {
|
|
status: 'warn',
|
|
message:
|
|
'Hoteling is ENABLED — this line may be roaming to another desk phone. Verify in Control Hub.',
|
|
details: { enabled },
|
|
remediation: null,
|
|
};
|
|
},
|
|
};
|