committtttt
This commit is contained in:
475
backend/internal/handlers/knowledge.go
Normal file
475
backend/internal/handlers/knowledge.go
Normal file
@@ -0,0 +1,475 @@
|
||||
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,
|
||||
},
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user