package handlers import ( "net/http" "strconv" "github.com/gin-gonic/gin" "customer-support-system/internal/knowledge" "customer-support-system/internal/models" "customer-support-system/pkg/logger" ) // KnowledgeHandler handles knowledge base-related HTTP requests type KnowledgeHandler struct { knowledgeService *knowledge.KnowledgeService } // NewKnowledgeHandler creates a new knowledge handler func NewKnowledgeHandler() *KnowledgeHandler { return &KnowledgeHandler{ knowledgeService: knowledge.NewKnowledgeService(), } } // CreateKnowledgeEntry handles creating a new knowledge base entry func (h *KnowledgeHandler) CreateKnowledgeEntry(c *gin.Context) { // Get user ID from context userID, exists := c.Get("userID") if !exists { logger.Error("Failed to get user ID from context") c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "Unauthorized", }) return } var req models.CreateKnowledgeBaseRequest if err := c.ShouldBindJSON(&req); err != nil { logger.WithError(err).Error("Failed to parse create knowledge entry request") c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "Invalid request body", }) return } // Create knowledge entry entry, err := h.knowledgeService.CreateKnowledgeEntry(userID.(uint), &req) if err != nil { logger.WithError(err).Error("Failed to create knowledge entry") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to create knowledge entry", }) return } c.JSON(http.StatusCreated, gin.H{ "success": true, "message": "Knowledge entry created successfully", "data": gin.H{ "entry": entry, }, }) } // GetKnowledgeEntry handles getting a knowledge base entry by ID func (h *KnowledgeHandler) GetKnowledgeEntry(c *gin.Context) { // Get knowledge entry ID from URL params entryID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { logger.WithError(err).Error("Failed to parse knowledge entry ID") c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "Invalid knowledge entry ID", }) return } // Get knowledge entry entry, err := h.knowledgeService.GetKnowledgeEntry(uint(entryID)) if err != nil { logger.WithError(err).Error("Failed to get knowledge entry") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to get knowledge entry", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": gin.H{ "entry": entry, }, }) } // ListKnowledgeEntries handles listing knowledge base entries func (h *KnowledgeHandler) ListKnowledgeEntries(c *gin.Context) { // Parse query parameters page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10")) category := c.DefaultQuery("category", "") activeStr := c.DefaultQuery("active", "true") if page < 1 { page = 1 } if pageSize < 1 || pageSize > 100 { pageSize = 10 } // Parse active parameter var active *bool if activeStr != "" { activeVal := activeStr == "true" active = &activeVal } // List knowledge entries response, err := h.knowledgeService.ListKnowledgeEntries(page, pageSize, category, active) if err != nil { logger.WithError(err).Error("Failed to list knowledge entries") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to list knowledge entries", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": gin.H{ "entries": response.Entries, "total": response.Total, "page": response.Page, "pageSize": response.PageSize, }, }) } // UpdateKnowledgeEntry handles updating a knowledge base entry func (h *KnowledgeHandler) UpdateKnowledgeEntry(c *gin.Context) { // Get user ID from context userID, exists := c.Get("userID") if !exists { logger.Error("Failed to get user ID from context") c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "Unauthorized", }) return } // Get knowledge entry ID from URL params entryID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { logger.WithError(err).Error("Failed to parse knowledge entry ID") c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "Invalid knowledge entry ID", }) return } var req models.UpdateKnowledgeBaseRequest if err := c.ShouldBindJSON(&req); err != nil { logger.WithError(err).Error("Failed to parse update knowledge entry request") c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "Invalid request body", }) return } // Update knowledge entry entry, err := h.knowledgeService.UpdateKnowledgeEntry(uint(entryID), userID.(uint), &req) if err != nil { logger.WithError(err).Error("Failed to update knowledge entry") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to update knowledge entry", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Knowledge entry updated successfully", "data": gin.H{ "entry": entry, }, }) } // DeleteKnowledgeEntry handles deleting a knowledge base entry func (h *KnowledgeHandler) DeleteKnowledgeEntry(c *gin.Context) { // Get user ID from context userID, exists := c.Get("userID") if !exists { logger.Error("Failed to get user ID from context") c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "Unauthorized", }) return } // Get knowledge entry ID from URL params entryID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { logger.WithError(err).Error("Failed to parse knowledge entry ID") c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "Invalid knowledge entry ID", }) return } // Delete knowledge entry err = h.knowledgeService.DeleteKnowledgeEntry(uint(entryID), userID.(uint)) if err != nil { logger.WithError(err).Error("Failed to delete knowledge entry") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to delete knowledge entry", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Knowledge entry deleted successfully", }) } // SearchKnowledge handles searching knowledge base entries func (h *KnowledgeHandler) SearchKnowledge(c *gin.Context) { // Parse query parameters query := c.DefaultQuery("query", "") page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10")) category := c.DefaultQuery("category", "") if page < 1 { page = 1 } if pageSize < 1 || pageSize > 100 { pageSize = 10 } // Search knowledge entries response, err := h.knowledgeService.SearchKnowledge(query, page, pageSize, category) if err != nil { logger.WithError(err).Error("Failed to search knowledge entries") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to search knowledge entries", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": gin.H{ "results": response.Results, "total": response.Total, "query": response.Query, "page": response.Page, "pageSize": response.PageSize, }, }) } // GetCategories handles getting all unique categories in the knowledge base func (h *KnowledgeHandler) GetCategories(c *gin.Context) { // Get categories categories, err := h.knowledgeService.GetCategories() if err != nil { logger.WithError(err).Error("Failed to get knowledge categories") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to get knowledge categories", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": gin.H{ "categories": categories, }, }) } // GetTags handles getting all unique tags in the knowledge base func (h *KnowledgeHandler) GetTags(c *gin.Context) { // Get tags tags, err := h.knowledgeService.GetTags() if err != nil { logger.WithError(err).Error("Failed to get knowledge tags") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to get knowledge tags", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": gin.H{ "tags": tags, }, }) } // RateKnowledgeEntry handles rating a knowledge base entry as helpful or not func (h *KnowledgeHandler) RateKnowledgeEntry(c *gin.Context) { // Get user ID from context userID, exists := c.Get("userID") if !exists { logger.Error("Failed to get user ID from context") c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "Unauthorized", }) return } // Get knowledge entry ID from URL params entryID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { logger.WithError(err).Error("Failed to parse knowledge entry ID") c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "Invalid knowledge entry ID", }) return } var req models.CreateKnowledgeBaseFeedbackRequest if err := c.ShouldBindJSON(&req); err != nil { logger.WithError(err).Error("Failed to parse rate knowledge entry request") c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "Invalid request body", }) return } // Rate knowledge entry err = h.knowledgeService.RateKnowledgeEntry(uint(entryID), userID.(uint), req.Helpful, req.Comment) if err != nil { logger.WithError(err).Error("Failed to rate knowledge entry") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to rate knowledge entry", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Knowledge entry rated successfully", }) } // GetPopularKnowledge handles getting popular knowledge base entries func (h *KnowledgeHandler) GetPopularKnowledge(c *gin.Context) { // Parse query parameters limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10")) if limit < 1 || limit > 100 { limit = 10 } // Get popular knowledge entries entries, err := h.knowledgeService.GetPopularKnowledge(limit) if err != nil { logger.WithError(err).Error("Failed to get popular knowledge entries") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to get popular knowledge entries", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": gin.H{ "entries": entries, }, }) } // GetRecentKnowledge handles getting recent knowledge base entries func (h *KnowledgeHandler) GetRecentKnowledge(c *gin.Context) { // Parse query parameters limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10")) if limit < 1 || limit > 100 { limit = 10 } // Get recent knowledge entries entries, err := h.knowledgeService.GetRecentKnowledge(limit) if err != nil { logger.WithError(err).Error("Failed to get recent knowledge entries") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to get recent knowledge entries", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": gin.H{ "entries": entries, }, }) } // FindBestMatch handles finding the best matching knowledge base entry for a query func (h *KnowledgeHandler) FindBestMatch(c *gin.Context) { // Parse query parameters query := c.DefaultQuery("query", "") if query == "" { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "message": "Query parameter is required", }) return } // Find best match entry, err := h.knowledgeService.FindBestMatch(query) if err != nil { logger.WithError(err).Error("Failed to find best match") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to find best match", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": gin.H{ "entry": entry, }, }) } // GetKnowledgeStats handles getting statistics for the knowledge base func (h *KnowledgeHandler) GetKnowledgeStats(c *gin.Context) { // Get knowledge stats stats, err := h.knowledgeService.GetKnowledgeStats() if err != nil { logger.WithError(err).Error("Failed to get knowledge stats") c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "Failed to get knowledge stats", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": gin.H{ "stats": stats, }, }) }