polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
323 lines (316 loc) • 13.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateOutputFormat = validateOutputFormat;
exports.parsePositiveInteger = parsePositiveInteger;
exports.parseNonNegativeInteger = parseNonNegativeInteger;
exports.registerQaCommands = registerQaCommands;
const qa_questionnaire_handler_1 = require("../handlers/qa-questionnaire.handler");
const manager_1 = require("../config/manager");
const auth_adapter_1 = require("../config/auth-adapter");
const errors_1 = require("../utils/errors");
function validateOutputFormat(value) {
if (!['table', 'json'].includes(value)) {
throw new Error('Output format must be either "table" or "json"');
}
return value;
}
function parsePositiveInteger(value) {
const parsed = parseInt(value, 10);
if (!Number.isInteger(parsed) || parsed < 1) {
throw new Error('Value must be a positive integer');
}
return parsed;
}
function parseNonNegativeInteger(value) {
const parsed = parseInt(value, 10);
if (!Number.isInteger(parsed) || parsed < 0) {
throw new Error('Value must be a non-negative integer');
}
return parsed;
}
function registerQaCommands(program) {
const qaCmd = program.command('qa');
qaCmd.description('Manage live streaming QA question cards');
const sendCmd = qaCmd
.command('send')
.description('Send a QA question card to the channel')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--question-id <id>', 'question ID')
.option('--duration <seconds>', 'answer duration in seconds (1-99)', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const handler = new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig);
await handler.sendQa({
channelId: options.channelId,
questionId: options.questionId,
duration: options.duration,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
sendCmd.addHelpText('after', `
Examples:
# Send a QA question card
$ polyv-live-cli qa send -c "3151318" --question-id "gv0uf9s5v7"
# Send with time limit (30 seconds)
$ polyv-live-cli qa send -c "3151318" --question-id "gv0uf9s5v7" --duration 30
# JSON output
$ polyv-live-cli qa send -c "3151318" --question-id "gv0uf9s5v7" -o json
Output Formats:
table - Formatted table output (default)
json - JSON format for programmatic use
`);
const listCmd = qaCmd
.command('list')
.description('List QA question cards for the channel')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const handler = new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig);
await handler.listQa({
channelId: options.channelId,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
listCmd.addHelpText('after', `
Examples:
# List all QA question cards
$ polyv-live-cli qa list -c "3151318"
# JSON output
$ polyv-live-cli qa list -c "3151318" -o json
Output Formats:
table - Formatted table output (default)
json - JSON format for programmatic use
`);
const stopCmd = qaCmd
.command('stop')
.description('Stop a QA question card and get answer statistics')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--question-id <id>', 'question ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const handler = new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig);
await handler.stopQa({
channelId: options.channelId,
questionId: options.questionId,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
stopCmd.addHelpText('after', `
Examples:
# Stop a QA question card
$ polyv-live-cli qa stop -c "3151318" --question-id "gv0uf9s5v7"
# JSON output
$ polyv-live-cli qa stop -c "3151318" --question-id "gv0uf9s5v7" -o json
Output Formats:
table - Formatted table output (default)
json - JSON format for programmatic use
`);
qaCmd
.command('send-times')
.description('List QA question card send times')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).listQuestionSendTime({
channelId: options.channelId,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
qaCmd
.command('answers')
.description('List QA answer records')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--session-id <id>', 'filter by live session ID')
.option('--start-date <date>', 'start date filter (yyyy-MM-dd)')
.option('--end-date <date>', 'end date filter (yyyy-MM-dd)')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).getAnswerList({
channelId: options.channelId,
sessionId: options.sessionId,
startDate: options.startDate,
endDate: options.endDate,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
qaCmd
.command('question-list')
.description('List student question records')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--begin <timestamp>', 'begin timestamp', parsePositiveInteger)
.option('--end <timestamp>', 'end timestamp', parsePositiveInteger)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).getQuestionList({
channelId: options.channelId,
begin: options.begin,
end: options.end,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
qaCmd
.command('add-edit')
.description('Create or update a QA question card')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--question-id <id>', 'question ID; omit to create a new question card')
.requiredOption('--type <type>', 'question type (R|C|S|V)')
.requiredOption('--answer <answer>', 'correct answer')
.requiredOption('--name <name>', 'question title')
.requiredOption('--item-type <number>', 'item type', parseNonNegativeInteger)
.option('--option <value...>', 'question option values, repeat by providing multiple values')
.option('--tip <value...>', 'answer explanation values, repeat by providing multiple values')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).addEditQuestion({
channelId: options.channelId,
questionId: options.questionId,
type: options.type,
answer: options.answer,
name: options.name,
itemType: options.itemType,
options: options.option,
tips: options.tip,
force: options.force,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
qaCmd
.command('delete-question')
.description('Delete a QA question card')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--question-id <id>', 'question ID')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).deleteQuestion({
channelId: options.channelId,
questionId: options.questionId,
force: options.force,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
qaCmd
.command('send-result')
.description('Publish QA question result statistics')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--question-id <id>', 'question ID')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).sendQuestionResult({
channelId: options.channelId,
questionId: options.questionId,
force: options.force,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
}
async function loadAuthAndServiceConfig(parentOptions) {
const authResult = auth_adapter_1.authAdapter.tryGetAuthConfig(parentOptions);
if (!authResult) {
throw new Error(auth_adapter_1.authAdapter.getStatusMessage(parentOptions));
}
let configResult;
try {
configResult = await manager_1.configManager.load({
cliOptions: parentOptions,
});
}
catch (error) {
if (error instanceof Error && error.message.includes('Auth configuration is incomplete')) {
configResult = {
config: {
baseUrl: 'https://api.polyv.net',
timeout: 30000,
debug: false
}
};
}
else {
throw error;
}
}
const serviceConfig = {
baseUrl: configResult.config.baseUrl,
timeout: configResult.config.timeout,
debug: configResult.config.debug,
};
return {
authConfig: authResult.config,
serviceConfig,
};
}
//# sourceMappingURL=qa.commands.js.map