committtttt
This commit is contained in:
553
backend/internal/knowledge/knowledge.go
Normal file
553
backend/internal/knowledge/knowledge.go
Normal file
@@ -0,0 +1,553 @@
|
||||
package knowledge
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"customer-support-system/internal/database"
|
||||
"customer-support-system/internal/models"
|
||||
"customer-support-system/pkg/logger"
|
||||
)
|
||||
|
||||
// KnowledgeService handles knowledge base operations
|
||||
type KnowledgeService struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewKnowledgeService creates a new knowledge service
|
||||
func NewKnowledgeService() *KnowledgeService {
|
||||
return &KnowledgeService{
|
||||
db: database.GetDB(),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateKnowledgeEntry creates a new knowledge base entry
|
||||
func (s *KnowledgeService) CreateKnowledgeEntry(userID uint, req *models.CreateKnowledgeBaseRequest) (*models.KnowledgeBase, error) {
|
||||
knowledge := models.KnowledgeBase{
|
||||
Question: req.Question,
|
||||
Answer: req.Answer,
|
||||
Category: req.Category,
|
||||
Tags: req.Tags,
|
||||
Priority: req.Priority,
|
||||
ViewCount: 0,
|
||||
Helpful: 0,
|
||||
NotHelpful: 0,
|
||||
Active: true,
|
||||
CreatedBy: userID,
|
||||
UpdatedBy: userID,
|
||||
}
|
||||
|
||||
if err := s.db.Create(&knowledge).Error; err != nil {
|
||||
logger.WithError(err).WithField("user_id", userID).Error("Failed to create knowledge entry")
|
||||
return nil, fmt.Errorf("failed to create knowledge entry: %w", err)
|
||||
}
|
||||
|
||||
logger.WithField("knowledge_id", knowledge.ID).Info("Knowledge entry created successfully")
|
||||
|
||||
return &knowledge, nil
|
||||
}
|
||||
|
||||
// GetKnowledgeEntry retrieves a knowledge base entry by ID
|
||||
func (s *KnowledgeService) GetKnowledgeEntry(knowledgeID uint) (*models.KnowledgeBase, error) {
|
||||
var knowledge models.KnowledgeBase
|
||||
if err := s.db.First(&knowledge, knowledgeID).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("knowledge entry not found")
|
||||
}
|
||||
logger.WithError(err).WithField("knowledge_id", knowledgeID).Error("Failed to get knowledge entry")
|
||||
return nil, fmt.Errorf("failed to get knowledge entry: %w", err)
|
||||
}
|
||||
|
||||
// Increment view count
|
||||
s.db.Model(&knowledge).Update("view_count", knowledge.ViewCount+1)
|
||||
|
||||
return &knowledge, nil
|
||||
}
|
||||
|
||||
// ListKnowledgeEntries retrieves a list of knowledge base entries
|
||||
func (s *KnowledgeService) ListKnowledgeEntries(page, pageSize int, category string, active *bool) (*models.KnowledgeBaseListResponse, error) {
|
||||
var knowledge []models.KnowledgeBase
|
||||
var total int64
|
||||
|
||||
query := s.db.Model(&models.KnowledgeBase{})
|
||||
|
||||
if category != "" {
|
||||
query = query.Where("category = ?", category)
|
||||
}
|
||||
|
||||
if active != nil {
|
||||
query = query.Where("active = ?", *active)
|
||||
}
|
||||
|
||||
// Get total count
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to count knowledge entries")
|
||||
return nil, fmt.Errorf("failed to count knowledge entries: %w", err)
|
||||
}
|
||||
|
||||
// Get paginated results
|
||||
offset := (page - 1) * pageSize
|
||||
if err := query.Order("priority DESC, view_count DESC, created_at DESC").Offset(offset).Limit(pageSize).Find(&knowledge).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to list knowledge entries")
|
||||
return nil, fmt.Errorf("failed to list knowledge entries: %w", err)
|
||||
}
|
||||
|
||||
return &models.KnowledgeBaseListResponse{
|
||||
Entries: knowledge,
|
||||
Total: total,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateKnowledgeEntry updates a knowledge base entry
|
||||
func (s *KnowledgeService) UpdateKnowledgeEntry(knowledgeID uint, userID uint, req *models.UpdateKnowledgeBaseRequest) (*models.KnowledgeBase, error) {
|
||||
var knowledge models.KnowledgeBase
|
||||
if err := s.db.First(&knowledge, knowledgeID).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("knowledge entry not found")
|
||||
}
|
||||
logger.WithError(err).WithField("knowledge_id", knowledgeID).Error("Failed to get knowledge entry")
|
||||
return nil, fmt.Errorf("failed to get knowledge entry: %w", err)
|
||||
}
|
||||
|
||||
// Check if user is the creator or an admin
|
||||
if knowledge.CreatedBy != userID {
|
||||
// Check if user is admin
|
||||
var user models.User
|
||||
if err := s.db.First(&user, userID).Error; err != nil {
|
||||
logger.WithError(err).WithField("user_id", userID).Error("Failed to get user")
|
||||
return nil, fmt.Errorf("failed to get user: %w", err)
|
||||
}
|
||||
if user.Role != "admin" {
|
||||
return nil, fmt.Errorf("unauthorized to update this knowledge entry")
|
||||
}
|
||||
}
|
||||
|
||||
// Update fields
|
||||
if req.Question != "" {
|
||||
knowledge.Question = req.Question
|
||||
}
|
||||
if req.Answer != "" {
|
||||
knowledge.Answer = req.Answer
|
||||
}
|
||||
if req.Category != "" {
|
||||
knowledge.Category = req.Category
|
||||
}
|
||||
if req.Tags != "" {
|
||||
knowledge.Tags = req.Tags
|
||||
}
|
||||
if req.Priority != 0 {
|
||||
knowledge.Priority = req.Priority
|
||||
}
|
||||
if req.Active != nil {
|
||||
knowledge.Active = *req.Active
|
||||
}
|
||||
knowledge.UpdatedBy = userID
|
||||
|
||||
if err := s.db.Save(&knowledge).Error; err != nil {
|
||||
logger.WithError(err).WithField("knowledge_id", knowledgeID).Error("Failed to update knowledge entry")
|
||||
return nil, fmt.Errorf("failed to update knowledge entry: %w", err)
|
||||
}
|
||||
|
||||
logger.WithField("knowledge_id", knowledgeID).Info("Knowledge entry updated successfully")
|
||||
|
||||
return &knowledge, nil
|
||||
}
|
||||
|
||||
// DeleteKnowledgeEntry deletes a knowledge base entry
|
||||
func (s *KnowledgeService) DeleteKnowledgeEntry(knowledgeID uint, userID uint) error {
|
||||
var knowledge models.KnowledgeBase
|
||||
if err := s.db.First(&knowledge, knowledgeID).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return fmt.Errorf("knowledge entry not found")
|
||||
}
|
||||
logger.WithError(err).WithField("knowledge_id", knowledgeID).Error("Failed to get knowledge entry")
|
||||
return fmt.Errorf("failed to get knowledge entry: %w", err)
|
||||
}
|
||||
|
||||
// Check if user is the creator or an admin
|
||||
if knowledge.CreatedBy != userID {
|
||||
// Check if user is admin
|
||||
var user models.User
|
||||
if err := s.db.First(&user, userID).Error; err != nil {
|
||||
logger.WithError(err).WithField("user_id", userID).Error("Failed to get user")
|
||||
return fmt.Errorf("failed to get user: %w", err)
|
||||
}
|
||||
if user.Role != "admin" {
|
||||
return fmt.Errorf("unauthorized to delete this knowledge entry")
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.db.Delete(&knowledge).Error; err != nil {
|
||||
logger.WithError(err).WithField("knowledge_id", knowledgeID).Error("Failed to delete knowledge entry")
|
||||
return fmt.Errorf("failed to delete knowledge entry: %w", err)
|
||||
}
|
||||
|
||||
logger.WithField("knowledge_id", knowledgeID).Info("Knowledge entry deleted successfully")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SearchKnowledge searches for knowledge base entries
|
||||
func (s *KnowledgeService) SearchKnowledge(query string, page, pageSize int, category string) (*models.KnowledgeBaseSearchResponse, error) {
|
||||
var knowledge []models.KnowledgeBase
|
||||
var total int64
|
||||
|
||||
// Build search query
|
||||
searchQuery := s.db.Model(&models.KnowledgeBase{})
|
||||
|
||||
if query != "" {
|
||||
// Search in question, answer, and tags
|
||||
searchQuery = searchQuery.Where(
|
||||
"active = ? AND (question ILIKE ? OR answer ILIKE ? OR tags ILIKE ?)",
|
||||
true,
|
||||
"%"+query+"%",
|
||||
"%"+query+"%",
|
||||
"%"+query+"%",
|
||||
)
|
||||
} else {
|
||||
searchQuery = searchQuery.Where("active = ?", true)
|
||||
}
|
||||
|
||||
if category != "" {
|
||||
searchQuery = searchQuery.Where("category = ?", category)
|
||||
}
|
||||
|
||||
// Get total count
|
||||
if err := searchQuery.Count(&total).Error; err != nil {
|
||||
logger.WithError(err).WithField("query", query).Error("Failed to count knowledge entries")
|
||||
return nil, fmt.Errorf("failed to count knowledge entries: %w", err)
|
||||
}
|
||||
|
||||
// Get paginated results
|
||||
offset := (page - 1) * pageSize
|
||||
if err := searchQuery.Order("priority DESC, view_count DESC, created_at DESC").Offset(offset).Limit(pageSize).Find(&knowledge).Error; err != nil {
|
||||
logger.WithError(err).WithField("query", query).Error("Failed to search knowledge entries")
|
||||
return nil, fmt.Errorf("failed to search knowledge entries: %w", err)
|
||||
}
|
||||
|
||||
// Convert to search results with relevance scores
|
||||
results := make([]models.KnowledgeBaseSearchResult, len(knowledge))
|
||||
for i, entry := range knowledge {
|
||||
results[i] = models.KnowledgeBaseSearchResult{
|
||||
KnowledgeBase: entry,
|
||||
RelevanceScore: s.calculateRelevanceScore(query, entry),
|
||||
MatchedFields: s.getMatchedFields(query, entry),
|
||||
}
|
||||
}
|
||||
|
||||
return &models.KnowledgeBaseSearchResponse{
|
||||
Results: results,
|
||||
Total: total,
|
||||
Query: query,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetCategories retrieves all unique categories in the knowledge base
|
||||
func (s *KnowledgeService) GetCategories() ([]string, error) {
|
||||
var categories []string
|
||||
if err := s.db.Model(&models.KnowledgeBase{}).Where("active = ?", true).Distinct().Pluck("category", &categories).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to get knowledge categories")
|
||||
return nil, fmt.Errorf("failed to get knowledge categories: %w", err)
|
||||
}
|
||||
return categories, nil
|
||||
}
|
||||
|
||||
// GetTags retrieves all unique tags in the knowledge base
|
||||
func (s *KnowledgeService) GetTags() ([]string, error) {
|
||||
var tags []string
|
||||
if err := s.db.Model(&models.KnowledgeBase{}).Where("active = ?", true).Find(&[]models.KnowledgeBase{}).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to get knowledge entries for tags")
|
||||
return nil, fmt.Errorf("failed to get knowledge entries for tags: %w", err)
|
||||
}
|
||||
|
||||
// Extract and deduplicate tags
|
||||
tagMap := make(map[string]bool)
|
||||
for _, entry := range []models.KnowledgeBase{} {
|
||||
if entry.Tags != "" {
|
||||
entryTags := strings.Split(entry.Tags, ",")
|
||||
for _, tag := range entryTags {
|
||||
tag = strings.TrimSpace(tag)
|
||||
if tag != "" {
|
||||
tagMap[tag] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert map to slice
|
||||
tags = make([]string, 0, len(tagMap))
|
||||
for tag := range tagMap {
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
// RateKnowledgeEntry rates a knowledge base entry as helpful or not
|
||||
func (s *KnowledgeService) RateKnowledgeEntry(knowledgeID uint, userID uint, helpful bool, comment string) error {
|
||||
var knowledge models.KnowledgeBase
|
||||
if err := s.db.First(&knowledge, knowledgeID).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return fmt.Errorf("knowledge entry not found")
|
||||
}
|
||||
logger.WithError(err).WithField("knowledge_id", knowledgeID).Error("Failed to get knowledge entry")
|
||||
return fmt.Errorf("failed to get knowledge entry: %w", err)
|
||||
}
|
||||
|
||||
// Create feedback record
|
||||
feedback := models.KnowledgeBaseFeedback{
|
||||
KnowledgeBaseID: knowledgeID,
|
||||
UserID: userID,
|
||||
Helpful: helpful,
|
||||
Comment: comment,
|
||||
}
|
||||
|
||||
if err := s.db.Create(&feedback).Error; err != nil {
|
||||
logger.WithError(err).WithField("knowledge_id", knowledgeID).Error("Failed to create knowledge feedback")
|
||||
return fmt.Errorf("failed to create knowledge feedback: %w", err)
|
||||
}
|
||||
|
||||
// Update helpful/not helpful counts
|
||||
if helpful {
|
||||
knowledge.Helpful++
|
||||
} else {
|
||||
knowledge.NotHelpful++
|
||||
}
|
||||
|
||||
if err := s.db.Save(&knowledge).Error; err != nil {
|
||||
logger.WithError(err).WithField("knowledge_id", knowledgeID).Error("Failed to rate knowledge entry")
|
||||
return fmt.Errorf("failed to rate knowledge entry: %w", err)
|
||||
}
|
||||
|
||||
logger.WithFields(map[string]interface{}{
|
||||
"knowledge_id": knowledgeID,
|
||||
"user_id": userID,
|
||||
"helpful": helpful,
|
||||
}).Info("Knowledge entry rated successfully")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPopularKnowledge retrieves popular knowledge base entries
|
||||
func (s *KnowledgeService) GetPopularKnowledge(limit int) ([]models.KnowledgeBase, error) {
|
||||
var knowledge []models.KnowledgeBase
|
||||
if err := s.db.Where("active = ?", true).
|
||||
Order("view_count DESC, helpful DESC").
|
||||
Limit(limit).
|
||||
Find(&knowledge).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to get popular knowledge entries")
|
||||
return nil, fmt.Errorf("failed to get popular knowledge entries: %w", err)
|
||||
}
|
||||
return knowledge, nil
|
||||
}
|
||||
|
||||
// GetRecentKnowledge retrieves recent knowledge base entries
|
||||
func (s *KnowledgeService) GetRecentKnowledge(limit int) ([]models.KnowledgeBase, error) {
|
||||
var knowledge []models.KnowledgeBase
|
||||
if err := s.db.Where("active = ?", true).
|
||||
Order("created_at DESC").
|
||||
Limit(limit).
|
||||
Find(&knowledge).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to get recent knowledge entries")
|
||||
return nil, fmt.Errorf("failed to get recent knowledge entries: %w", err)
|
||||
}
|
||||
return knowledge, nil
|
||||
}
|
||||
|
||||
// FindBestMatch finds the best matching knowledge base entry for a query
|
||||
func (s *KnowledgeService) FindBestMatch(query string) (*models.KnowledgeBase, error) {
|
||||
// This is a simple implementation that looks for exact matches in tags
|
||||
// In a real implementation, this would use more sophisticated algorithms like TF-IDF or embeddings
|
||||
|
||||
var knowledge models.KnowledgeBase
|
||||
if err := s.db.Where("active = ? AND tags ILIKE ?", true, "%"+query+"%").
|
||||
Order("priority DESC, view_count DESC, helpful DESC").
|
||||
First(&knowledge).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
// Try to find a match in the question
|
||||
if err := s.db.Where("active = ? AND question ILIKE ?", true, "%"+query+"%").
|
||||
Order("priority DESC, view_count DESC, helpful DESC").
|
||||
First(&knowledge).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
// Try to find a match in the answer
|
||||
if err := s.db.Where("active = ? AND answer ILIKE ?", true, "%"+query+"%").
|
||||
Order("priority DESC, view_count DESC, helpful DESC").
|
||||
First(&knowledge).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("no matching knowledge entry found")
|
||||
}
|
||||
logger.WithError(err).WithField("query", query).Error("Failed to find best match in answer")
|
||||
return nil, fmt.Errorf("failed to find best match in answer: %w", err)
|
||||
}
|
||||
}
|
||||
logger.WithError(err).WithField("query", query).Error("Failed to find best match in question")
|
||||
return nil, fmt.Errorf("failed to find best match in question: %w", err)
|
||||
}
|
||||
}
|
||||
logger.WithError(err).WithField("query", query).Error("Failed to find best match in tags")
|
||||
return nil, fmt.Errorf("failed to find best match in tags: %w", err)
|
||||
}
|
||||
|
||||
return &knowledge, nil
|
||||
}
|
||||
|
||||
// GetKnowledgeStats retrieves statistics for the knowledge base
|
||||
func (s *KnowledgeService) GetKnowledgeStats() (*models.KnowledgeBaseStats, error) {
|
||||
var stats models.KnowledgeBaseStats
|
||||
|
||||
// Get total entries
|
||||
if err := s.db.Model(&models.KnowledgeBase{}).Where("active = ?", true).Count(&stats.TotalEntries).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to count knowledge entries")
|
||||
return nil, fmt.Errorf("failed to count knowledge entries: %w", err)
|
||||
}
|
||||
|
||||
// Get total views
|
||||
var totalViews sql.NullInt64
|
||||
if err := s.db.Model(&models.KnowledgeBase{}).Where("active = ?", true).Select("SUM(view_count)").Scan(&totalViews).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to calculate total views")
|
||||
return nil, fmt.Errorf("failed to calculate total views: %w", err)
|
||||
}
|
||||
if totalViews.Valid {
|
||||
stats.TotalViews = totalViews.Int64
|
||||
}
|
||||
|
||||
// Get average helpful percentage
|
||||
var avgHelpful sql.NullFloat64
|
||||
if err := s.db.Model(&models.KnowledgeBase{}).Where("active = ? AND helpful + not_helpful > 0", true).
|
||||
Select("AVG(helpful::float / (helpful + not_helpful)::float * 100)").Scan(&avgHelpful).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to calculate average helpful percentage")
|
||||
return nil, fmt.Errorf("failed to calculate average helpful percentage: %w", err)
|
||||
}
|
||||
if avgHelpful.Valid {
|
||||
stats.AverageHelpful = avgHelpful.Float64
|
||||
}
|
||||
|
||||
// Get top categories
|
||||
var categoryStats []models.CategoryStat
|
||||
if err := s.db.Model(&models.KnowledgeBase{}).
|
||||
Where("active = ?", true).
|
||||
Select("category, COUNT(*) as count").
|
||||
Group("category").
|
||||
Order("count DESC").
|
||||
Limit(5).
|
||||
Scan(&categoryStats).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to get category statistics")
|
||||
return nil, fmt.Errorf("failed to get category statistics: %w", err)
|
||||
}
|
||||
stats.TopCategories = categoryStats
|
||||
|
||||
// Get top tags
|
||||
var tagStats []models.TagStat
|
||||
if err := s.db.Model(&models.KnowledgeBase{}).
|
||||
Where("active = ? AND tags != ''", true).
|
||||
Select("unnest(string_to_array(tags, ',')) as tag, COUNT(*) as count").
|
||||
Group("tag").
|
||||
Order("count DESC").
|
||||
Limit(10).
|
||||
Scan(&tagStats).Error; err != nil {
|
||||
logger.WithError(err).Error("Failed to get tag statistics")
|
||||
return nil, fmt.Errorf("failed to get tag statistics: %w", err)
|
||||
}
|
||||
stats.TopTags = tagStats
|
||||
|
||||
return &stats, nil
|
||||
}
|
||||
|
||||
// calculateRelevanceScore calculates a relevance score for a knowledge base entry against a query
|
||||
func (s *KnowledgeService) calculateRelevanceScore(query string, entry models.KnowledgeBase) float64 {
|
||||
if query == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
query = strings.ToLower(query)
|
||||
score := 0.0
|
||||
|
||||
// Check for exact match in question
|
||||
if strings.Contains(strings.ToLower(entry.Question), query) {
|
||||
score += 10.0
|
||||
}
|
||||
|
||||
// Check for exact match in answer
|
||||
if strings.Contains(strings.ToLower(entry.Answer), query) {
|
||||
score += 5.0
|
||||
}
|
||||
|
||||
// Check for exact match in tags
|
||||
if strings.Contains(strings.ToLower(entry.Tags), query) {
|
||||
score += 7.0
|
||||
}
|
||||
|
||||
// Check for word matches
|
||||
queryWords := strings.Fields(query)
|
||||
questionWords := strings.Fields(strings.ToLower(entry.Question))
|
||||
answerWords := strings.Fields(strings.ToLower(entry.Answer))
|
||||
tagsWords := strings.Fields(strings.ToLower(entry.Tags))
|
||||
|
||||
for _, word := range queryWords {
|
||||
// Check question words
|
||||
for _, qWord := range questionWords {
|
||||
if strings.EqualFold(word, qWord) {
|
||||
score += 2.0
|
||||
}
|
||||
}
|
||||
|
||||
// Check answer words
|
||||
for _, aWord := range answerWords {
|
||||
if strings.EqualFold(word, aWord) {
|
||||
score += 1.0
|
||||
}
|
||||
}
|
||||
|
||||
// Check tag words
|
||||
for _, tWord := range tagsWords {
|
||||
if strings.EqualFold(word, tWord) {
|
||||
score += 3.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Boost score based on priority
|
||||
score += float64(entry.Priority) * 0.5
|
||||
|
||||
// Boost score based on helpfulness
|
||||
if entry.Helpful+entry.NotHelpful > 0 {
|
||||
helpfulness := float64(entry.Helpful) / float64(entry.Helpful+entry.NotHelpful)
|
||||
score += helpfulness * 2.0
|
||||
}
|
||||
|
||||
return score
|
||||
}
|
||||
|
||||
// getMatchedFields returns the fields that matched the query
|
||||
func (s *KnowledgeService) getMatchedFields(query string, entry models.KnowledgeBase) []string {
|
||||
if query == "" {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
query = strings.ToLower(query)
|
||||
matchedFields := []string{}
|
||||
|
||||
// Check question
|
||||
if strings.Contains(strings.ToLower(entry.Question), query) {
|
||||
matchedFields = append(matchedFields, "question")
|
||||
}
|
||||
|
||||
// Check answer
|
||||
if strings.Contains(strings.ToLower(entry.Answer), query) {
|
||||
matchedFields = append(matchedFields, "answer")
|
||||
}
|
||||
|
||||
// Check tags
|
||||
if strings.Contains(strings.ToLower(entry.Tags), query) {
|
||||
matchedFields = append(matchedFields, "tags")
|
||||
}
|
||||
|
||||
return matchedFields
|
||||
}
|
Reference in New Issue
Block a user