UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

577 lines 26.3 kB
"use strict"; 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