UNPKG

mcp-quiz-server

Version:

🧠 AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.

156 lines (155 loc) 6.24 kB
"use strict"; /** * @fileoverview Delete Quiz Command Handler - Clean Architecture Application Layer * @version 1.0.0 * @since 2025-07-30 * @module DeleteQuizCommandHandler * @description Handles quiz deletion with business rules and event publication * * @architecture * Layer: Application (Command Handler) * Pattern: Command Handler Pattern + Repository Pattern * Dependencies: Domain repositories, event bus, cache * * @relationships * DEPENDS_ON: * - QuizRepository (Infrastructure) * - EventBus (Infrastructure) * - CacheService (Infrastructure) * USED_BY: * - MCP delete-quiz tool (Infrastructure) * - HTTP delete endpoints (Infrastructure) * * @contributors Claude Code Agent * @testCoverage Command handler tests, integration tests */ Object.defineProperty(exports, "__esModule", { value: true }); exports.DeleteQuizCommandHandler = void 0; const QuizDeletedEvent_1 = require("../../domain/events/QuizDeletedEvent"); /** * Delete Quiz Command Handler * * @description Processes quiz deletion commands with proper business logic, * validation, caching, and event publication. * * @example * ```typescript * const handler = new DeleteQuizCommandHandler({ quizRepository, eventBus, cacheService }); * const result = await handler.handle(deleteCommand); * ``` * * @since 2025-07-30 * @author Claude Code Agent */ class DeleteQuizCommandHandler { constructor(dependencies) { this.quizRepository = dependencies.quizRepository; this.eventBus = dependencies.eventBus; this.cacheService = dependencies.cacheService; } /** * Handle Delete Quiz Command * * @description Executes quiz deletion with validation, business rules, * cache invalidation, and event publication. * * @param command Delete quiz command with validation * @returns Promise<DeleteQuizResult> Result with audit information */ async handle(command) { console.log(`🗑️ Clean Architecture: Processing ${command.toString()}`); try { // 1. Validate quiz exists const existingQuiz = await this.quizRepository.findById(command.quizId); if (!existingQuiz) { throw new Error(`Quiz not found: ${command.quizId.value}`); } console.log(`📋 Found quiz to delete: "${existingQuiz.title}"`); // 2. Apply business rules await this.validateDeletionRules(existingQuiz, command); // 3. Delete from repository await this.quizRepository.delete(command.quizId); const deletedAt = new Date().toISOString(); // 4. Invalidate cache await this.invalidateCache(command.quizId.value); // 5. Publish domain event const event = new QuizDeletedEvent_1.QuizDeletedEvent({ quizId: command.quizId.value, quizTitle: existingQuiz.title, deletedAt, deletedBy: command.requestedBy, reason: command.reason, metadata: command.metadata, }); await this.eventBus.publish(event); const result = { success: true, quizId: command.quizId.value, deletedAt, events: ['QuizDeletedEvent'], audit: command.getAuditInfo(), }; console.log(`✅ Quiz deleted successfully: ${command.quizId.value}`); return result; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error(`❌ Quiz deletion failed: ${errorMessage}`); // Publish failure event for monitoring (generic event) try { await this.eventBus.publish({ eventType: 'QuizDeletionFailed', eventId: 'temp-failure-id', occurredOn: new Date(), version: 1, data: { quizId: command.quizId.value, error: errorMessage, requestedBy: command.requestedBy, timestamp: new Date().toISOString(), }, }); } catch (eventError) { console.warn('Failed to publish failure event:', eventError); } throw error; } } /** * Validate business rules for quiz deletion */ async validateDeletionRules(quiz, command) { // Business Rule: Cannot delete quiz with active attempts (if we implement this) // For now, we allow all deletions with confirmation // Business Rule: Require confirmation for safety if (!command.confirmDelete) { throw new Error('Delete confirmation is required'); } // Business Rule: Audit trail required for deletions if (!command.requestedBy || command.requestedBy === 'anonymous') { console.warn('⚠️ Quiz deletion by anonymous user:', command.quizId.value); } console.log(`✅ Deletion validation passed for quiz: ${quiz.title}`); } /** * Invalidate related cache entries */ async invalidateCache(quizId) { try { // Clear specific quiz cache await this.cacheService.delete(`quiz:${quizId}`); // Clear quiz list cache (as it may contain this quiz) await this.cacheService.delete('quiz:list:all'); // Clear category-specific caches (we don't know which category, so clear pattern) // Note: This could be optimized by storing category info in the command console.log(`🗑️ Cache invalidated for quiz: ${quizId}`); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.warn(`⚠️ Cache invalidation warning for quiz ${quizId}:`, errorMessage); // Don't fail the entire operation for cache issues } } } exports.DeleteQuizCommandHandler = DeleteQuizCommandHandler;