polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
577 lines • 26.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.QaQuestionnaireHandler = void 0;
const base_handler_1 = require("./base.handler");
const qa_questionnaire_service_1 = require("../services/qa-questionnaire-service");
const errors_1 = require("../utils/errors");
const api_command_1 = require("../utils/api-command");
class QaQuestionnaireHandler extends base_handler_1.BaseHandler {
constructor(authConfig, serviceConfig) {
super();
this.service = new qa_questionnaire_service_1.QaQuestionnaireServiceSdk(authConfig, serviceConfig);
}
async sendQa(options) {
return this.executeWithErrorHandling(async () => {
this.validateSendOptions(options);
const result = await this.service.sendQa({
channelId: parseInt(options.channelId, 10),
questionId: options.questionId,
duration: options.duration,
});
this.displaySendResult(result, options);
}, 'qa.send');
}
async listQa(options) {
return this.executeWithErrorHandling(async () => {
this.validateListOptions(options);
const result = await this.service.listQa({
channelId: options.channelId,
});
this.displayListResult(result, options);
}, 'qa.list');
}
async stopQa(options) {
return this.executeWithErrorHandling(async () => {
this.validateStopOptions(options);
const result = await this.service.stopQa({
channelId: parseInt(options.channelId, 10),
questionId: options.questionId,
});
this.displayStopResult(result, options);
}, 'qa.stop');
}
async listQuestionSendTime(options) {
return this.executeWithErrorHandling(async () => {
this.validateRequiredOptions(options, ['channelId']);
const result = await this.service.listQuestionSendTime({
channelId: options.channelId,
});
this.displayGenericResult(result, options.output);
}, 'qa.send-times');
}
async getAnswerList(options) {
return this.executeWithErrorHandling(async () => {
this.validateRequiredOptions(options, ['channelId']);
this.validateDateRangeOptions(options);
const params = {
channelId: options.channelId,
};
if (options.sessionId !== undefined)
params.sessionId = options.sessionId;
if (options.startDate !== undefined)
params.startDate = options.startDate;
if (options.endDate !== undefined)
params.endDate = options.endDate;
const result = await this.service.getAnswerList(params);
this.displayGenericResult(result, options.output);
}, 'qa.answers');
}
async getQuestionList(options) {
return this.executeWithErrorHandling(async () => {
this.validateRequiredOptions(options, ['channelId']);
this.validateOptionalPositiveInteger('begin', options.begin);
this.validateOptionalPositiveInteger('end', options.end);
const params = {
channelId: options.channelId,
};
if (options.begin !== undefined)
params.begin = options.begin;
if (options.end !== undefined)
params.end = options.end;
const result = await this.service.getQuestionList(params);
this.displayGenericResult(result, options.output);
}, 'qa.question-list');
}
async addEditQuestion(options) {
return this.executeWithErrorHandling(async () => {
this.validateRequiredOptions(options, ['channelId', 'type', 'answer', 'name', 'itemType']);
this.validateOptionalNonBlankString('questionId', options.questionId);
if (!Number.isInteger(options.itemType) || options.itemType < 0) {
throw new errors_1.PolyVValidationError('itemType must be a non-negative integer', 'itemType', options.itemType, 'validation_failed');
}
const actionLabel = options.questionId
? `Create or update QA question ${options.questionId}?`
: `Create QA question "${options.name}"?`;
await (0, api_command_1.confirmWrite)(options.force, actionLabel);
const params = {
channelId: options.channelId,
type: options.type,
answer: options.answer,
name: options.name,
itemType: options.itemType,
};
if (options.questionId !== undefined)
params.questionId = options.questionId;
if (options.options !== undefined)
params.options = options.options;
if (options.tips !== undefined)
params.tips = options.tips;
const result = await this.service.addEditQuestion(params);
this.displayGenericResult(result, options.output, 'QA question saved successfully');
}, 'qa.add-edit');
}
async deleteQuestion(options) {
return this.executeWithErrorHandling(async () => {
this.validateRequiredOptions(options, ['channelId', 'questionId']);
await (0, api_command_1.confirmWrite)(options.force, `Delete QA question ${options.questionId}?`);
const result = await this.service.deleteQuestion({
channelId: options.channelId,
questionId: options.questionId,
});
this.displayGenericResult(result ?? { success: true }, options.output, 'QA question deleted successfully');
}, 'qa.delete-question');
}
async sendQuestionResult(options) {
return this.executeWithErrorHandling(async () => {
this.validateRequiredOptions(options, ['channelId', 'questionId']);
await (0, api_command_1.confirmWrite)(options.force, `Publish QA result for question ${options.questionId}?`);
const result = await this.service.sendQuestionResult({
channelId: options.channelId,
questionId: options.questionId,
});
this.displayGenericResult(result ?? { success: true }, options.output, 'QA result published successfully');
}, 'qa.send-result');
}
async createQuestionnaire(options) {
return this.executeWithErrorHandling(async () => {
this.validateCreateOptions(options);
const parsedQuestions = options._parsedQuestions || options.questions;
const result = await this.service.createQuestionnaire({
channelId: options.channelId,
title: options.title,
questions: parsedQuestions,
customQuestionnaireId: options.customQuestionnaireId,
autoPublishTime: options.autoPublishTime,
autoEndTime: options.autoEndTime,
privacyEnabled: options.privacyEnabled,
privacyContent: options.privacyContent,
});
this.displayCreateResult(result, options, parsedQuestions.length);
}, 'questionnaire.create');
}
async listQuestionnaires(options) {
return this.executeWithErrorHandling(async () => {
this.validateListQuestionnairesOptions(options);
const result = await this.service.listQuestionnaires({
channelId: options.channelId,
page: options.page,
pageSize: options.size,
sessionId: options.sessionId,
startDate: options.startDate,
endDate: options.endDate,
});
this.displayListQuestionnairesResult(result, options);
}, 'questionnaire.result-list');
}
async listQuestionnaire(options) {
return this.executeWithErrorHandling(async () => {
this.validateRequiredOptions(options, ['channelId']);
this.validateOptionalPositiveInteger('page', options.page);
this.validateOptionalPositiveInteger('size', options.size);
const params = {
channelId: options.channelId,
};
if (options.startTime !== undefined)
params.startTime = options.startTime;
if (options.endTime !== undefined)
params.endTime = options.endTime;
if (options.page !== undefined)
params.page = options.page;
if (options.size !== undefined)
params.pageSize = options.size;
const result = await this.service.listQuestionnaire(params);
this.displayGenericResult(result, options.output);
}, 'questionnaire.list');
}
async getQuestionnaireDetail(options) {
return this.executeWithErrorHandling(async () => {
this.validateDetailOptions(options);
const result = await this.service.getQuestionnaireDetail({
channelId: options.channelId,
questionnaireId: options.questionnaireId,
});
this.displayDetailResult(result, options);
}, 'questionnaire.detail');
}
async getQuestionnaireResult(options) {
return this.executeWithErrorHandling(async () => {
this.validateRequiredOptions(options, ['channelId']);
this.validateDateRangeOptions(options);
const params = {
channelId: options.channelId,
};
if (options.questionnaireId !== undefined)
params.questionnaireId = options.questionnaireId;
if (options.sessionId !== undefined)
params.sessionId = options.sessionId;
if (options.startDate !== undefined)
params.startDate = options.startDate;
if (options.endDate !== undefined)
params.endDate = options.endDate;
const result = await this.service.getQuestionnaireResult(params);
this.displayGenericResult(result, options.output);
}, 'questionnaire.results');
}
async batchCreateQuestionnaire(options) {
return this.executeWithErrorHandling(async () => {
this.validateRequiredOptions(options, ['questionnaires']);
const questionnaires = this.parseQuestionnaires(options.questionnaires);
await (0, api_command_1.confirmWrite)(options.force, `Batch create ${questionnaires.length} questionnaire(s)?`);
const result = await this.service.batchCreateQuestionnaire({
questionnaires,
});
this.displayGenericResult(result, options.output, 'Questionnaires created successfully');
}, 'questionnaire.batch-create');
}
validateRequiredOptions(options, fields) {
const missing = fields.filter((field) => {
const value = options[field];
return value === undefined || value === null || (typeof value === 'string' && value.trim() === '');
});
if (missing.length > 0) {
throw new errors_1.PolyVValidationError(`Missing required options: ${missing.join(', ')}`, 'options', options, 'validation_failed');
}
if (options.output && !['table', 'json'].includes(options.output)) {
throw new errors_1.PolyVValidationError('output must be either "table" or "json"', 'output', options.output, 'validation_failed');
}
}
validateDateRangeOptions(options) {
const dateFormatRegex = /^\d{4}-\d{2}-\d{2}$/;
if (options.startDate && !dateFormatRegex.test(options.startDate)) {
throw new errors_1.PolyVValidationError('Invalid startDate format. Use yyyy-MM-dd', 'startDate', options.startDate, 'validation_failed');
}
if (options.endDate && !dateFormatRegex.test(options.endDate)) {
throw new errors_1.PolyVValidationError('Invalid endDate format. Use yyyy-MM-dd', 'endDate', options.endDate, 'validation_failed');
}
}
validateOptionalPositiveInteger(field, value) {
if (value === undefined)
return;
if (!Number.isInteger(value) || value < 1) {
throw new errors_1.PolyVValidationError(`${field} must be a positive integer`, field, value, 'validation_failed');
}
}
validateOptionalNonBlankString(field, value) {
if (value === undefined)
return;
if (value.trim() === '') {
throw new errors_1.PolyVValidationError(`${field} is required`, field, value, 'validation_failed');
}
}
parseQuestionnaires(value) {
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
if (!Array.isArray(parsed) || parsed.length === 0) {
throw new errors_1.PolyVValidationError('questionnaires must be a non-empty JSON array', 'questionnaires', value, 'validation_failed');
}
return parsed;
}
validateSendOptions(options) {
const errors = [];
if (!options.channelId || options.channelId.trim() === '') {
errors.push('channelId is required');
}
if (!options.questionId || options.questionId.trim() === '') {
errors.push('questionId is required');
}
if (options.duration !== undefined) {
if (typeof options.duration !== 'number' || options.duration < 1 || options.duration > 99) {
errors.push('duration must be between 1 and 99');
}
}
if (options.output && !['table', 'json'].includes(options.output)) {
errors.push('output must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`QA send options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateListOptions(options) {
const errors = [];
if (!options.channelId || options.channelId.trim() === '') {
errors.push('channelId is required');
}
if (options.output && !['table', 'json'].includes(options.output)) {
errors.push('output must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`QA list options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateStopOptions(options) {
const errors = [];
if (!options.channelId || options.channelId.trim() === '') {
errors.push('channelId is required');
}
if (!options.questionId || options.questionId.trim() === '') {
errors.push('questionId is required');
}
if (options.output && !['table', 'json'].includes(options.output)) {
errors.push('output must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`QA stop options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateCreateOptions(options) {
const errors = [];
if (!options.channelId || options.channelId.trim() === '') {
errors.push('channelId is required');
}
if (!options.title || options.title.trim() === '') {
errors.push('title is required');
}
let parsedQuestions = null;
if (typeof options.questions === 'string') {
if (options.questions.trim() === '') {
parsedQuestions = null;
}
else {
try {
parsedQuestions = JSON.parse(options.questions);
}
catch {
throw new errors_1.PolyVValidationError('Invalid JSON format for questions', 'questions', options.questions, 'invalid_json');
}
}
}
else if (Array.isArray(options.questions)) {
parsedQuestions = options.questions;
}
if (parsedQuestions === null) {
errors.push('questions is required');
}
else if (Array.isArray(parsedQuestions) && parsedQuestions.length > 0) {
parsedQuestions.forEach((q, idx) => {
if (!q.name || q.name.trim() === '') {
errors.push(`questions[${idx}].name is required`);
}
if (!q.type) {
errors.push(`questions[${idx}].type is required`);
}
if ((q.type === 'R' || q.type === 'C') && (!q.options || q.options.length === 0)) {
errors.push(`questions[${idx}].options is required for choice questions`);
}
});
}
if (options.output && !['table', 'json'].includes(options.output)) {
errors.push('output must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Questionnaire create options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
options._parsedQuestions = parsedQuestions || [];
}
validateListQuestionnairesOptions(options) {
const errors = [];
if (!options.channelId || options.channelId.trim() === '') {
errors.push('channelId is required');
}
if (options.page !== undefined) {
if (typeof options.page !== 'number' || !Number.isInteger(options.page) || options.page < 1) {
errors.push('page must be a positive integer');
}
}
if (options.size !== undefined) {
if (typeof options.size !== 'number' || !Number.isInteger(options.size) || options.size < 1) {
errors.push('size must be a positive integer');
}
}
const dateFormatRegex = /^\d{4}-\d{2}-\d{2}$/;
if (options.startDate && !dateFormatRegex.test(options.startDate)) {
errors.push('Invalid startDate format. Use yyyy-MM-dd');
}
if (options.endDate && !dateFormatRegex.test(options.endDate)) {
errors.push('Invalid endDate format. Use yyyy-MM-dd');
}
if (options.output && !['table', 'json'].includes(options.output)) {
errors.push('output must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Questionnaire list options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateDetailOptions(options) {
const errors = [];
if (!options.channelId || options.channelId.trim() === '') {
errors.push('channelId is required');
}
if (!options.questionnaireId || options.questionnaireId.trim() === '') {
errors.push('questionnaireId is required');
}
if (options.output && !['table', 'json'].includes(options.output)) {
errors.push('output must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Questionnaire detail options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
displaySendResult(result, options) {
if (options.output === 'json') {
this.displayData({
channelId: options.channelId,
questionId: options.questionId,
duration: options.duration,
result
}, 'json');
}
else {
console.log(`QA sent successfully`);
console.log(`Channel ID: ${options.channelId}`);
console.log(`Question ID: ${options.questionId}`);
if (options.duration) {
console.log(`Duration: ${options.duration} seconds`);
}
}
}
displayListResult(result, options) {
const questions = result?.data?.questions || result?.data?.contents || result?.questions || result?.list || [];
if (questions.length === 0) {
this.displayInfo(`No QA found`);
return;
}
if (options.output === 'json') {
this.displayData({
channelId: options.channelId,
count: questions.length,
data: questions
}, 'json');
}
else {
const tableData = questions.map((item) => ({
'Question ID': this.truncate(item.questionId, 10),
'Name': this.truncate(item.name, 30),
'Type': item.type || '-',
'Status': item.status || '-',
'Times': item.times || 0,
}));
console.log(`Found ${questions.length} QA questions`);
this.displayAsTable(tableData);
}
}
displayStopResult(result, options) {
const data = result?.data || result;
if (options.output === 'json') {
this.displayData({
channelId: options.channelId,
questionId: options.questionId,
result: data
}, 'json');
}
else {
console.log(`QA stopped successfully`);
console.log(`Channel ID: ${options.channelId}`);
console.log(`Question ID: ${options.questionId}`);
if (data) {
console.log('\n--- Answer Statistics ---');
if (data.answer) {
console.log(`Correct Answer: ${data.answer}`);
}
if (data.total !== undefined) {
console.log(`Total Respondents: ${data.total}`);
}
if (data.rightUserCount !== undefined) {
console.log(`Correct: ${data.rightUserCount}`);
}
if (data.faultUserCount !== undefined) {
console.log(`Incorrect: ${data.faultUserCount}`);
}
if (data.singleResult && Array.isArray(data.singleResult)) {
console.log('\nOption Distribution:');
data.singleResult.forEach((count, idx) => {
console.log(` Option ${idx + 1}: ${count}`);
});
}
}
}
}
displayCreateResult(result, options, questionsCount) {
const questionnaireId = result?.data?.questionnaireId || result?.questionnaireId || 'N/A';
if (options.output === 'json') {
this.displayData({
channelId: options.channelId,
questionnaireId,
title: options.title,
questionsCount,
result
}, 'json');
}
else {
console.log(`Questionnaire created successfully`);
console.log(`Channel ID: ${options.channelId}`);
console.log(`Questionnaire ID: ${questionnaireId}`);
console.log(`Title: ${options.title}`);
console.log(`Questions: ${questionsCount}`);
}
}
displayListQuestionnairesResult(result, options) {
const contents = result?.data?.contents || result?.contents || [];
const count = result?.data?.totalItems || contents.length;
if (contents.length === 0) {
this.displayInfo(`No questionnaire results found for channel ${options.channelId}`);
return;
}
if (options.output === 'json') {
this.displayData({
channelId: options.channelId,
count,
data: contents
}, 'json');
}
else {
const tableData = contents.map((item) => ({
'Questionnaire ID': this.truncate(item.questionnaireId, 10),
'Title': this.truncate(item.title || item.questionnaireTitle, 30),
'Last Modified': item.lastModified ? new Date(item.lastModified).toLocaleString() : '-',
'Users': item.users?.length || 0,
}));
console.log(`Found ${count} questionnaire result records`);
this.displayAsTable(tableData);
}
}
displayDetailResult(result, options) {
const data = result?.data || result;
if (!data) {
this.displayInfo(`No questionnaire detail found for ID ${options.questionnaireId}`);
return;
}
if (options.output === 'json') {
this.displayData({
channelId: options.channelId,
questionnaireId: options.questionnaireId,
data
}, 'json');
}
else {
console.log(`Questionnaire Detail`);
console.log(`Channel ID: ${options.channelId}`);
console.log(`Questionnaire ID: ${data.questionnaireId || options.questionnaireId}`);
console.log(`Name: ${data.name || '-'}`);
console.log(`Status: ${data.status || '-'}`);
const questions = data.questions || [];
if (questions.length > 0) {
console.log(`\n--- Questions (${questions.length}) ---`);
const tableData = questions.map((q) => ({
'Question ID': this.truncate(q.questionId, 10),
'Name': this.truncate(q.name, 30),
'Type': q.type || '-',
'Required': q.required === 'Y' ? 'Yes' : 'No',
'Score Enabled': q.scoreEnabled === 'Y' ? 'Yes' : 'No',
}));
this.displayAsTable(tableData);
}
}
}
displayGenericResult(result, format, successMessage) {
if (successMessage && format !== 'json') {
this.displaySuccess(successMessage);
}
this.displayData(result ?? { success: true }, format || 'table');
}
truncate(str, maxLength) {
if (!str)
return '-';
return str.length > maxLength ? str.substring(0, maxLength) + '...' : str;
}
}
exports.QaQuestionnaireHandler = QaQuestionnaireHandler;
//# sourceMappingURL=qa-questionnaire.handler.js.map