support for FE

This commit is contained in:
Sotirios Pupakis
2025-09-25 00:33:27 +02:00
parent ca169f5e7e
commit 93965d501a
12 changed files with 334 additions and 6 deletions

206
controllers/feController.go Normal file
View File

@@ -0,0 +1,206 @@
package controllers
import (
"fmt"
"net/http"
"strconv"
"gitea.tbdevent.eu/TBD/reforger_crawler_main/initializers"
"gitea.tbdevent.eu/TBD/reforger_crawler_main/models"
"github.com/gin-gonic/gin"
)
// convertToSimplifiedAddon converts a full Addon to SimplifiedAddon
func convertToSimplifiedAddon(addon models.Addon) models.SimplifiedAddon {
var simplifiedFiles []models.SimplifiedAddonFile
for _, file := range addon.AddonFiles {
simplifiedFiles = append(simplifiedFiles, models.SimplifiedAddonFile{
Path: file.Path,
Hash: file.Hash,
Version: file.Version,
AddonID: file.AddonID,
})
}
return models.SimplifiedAddon{
ID: addon.ID,
Name: addon.Name,
Type: addon.Type,
Summary: addon.Summary,
SubscriberCount: addon.SubscriberCount,
CurrentVersionNumber: addon.CurrentVersionNumber,
Preview: addon.Preview,
Author: addon.Author,
AddonFiles: simplifiedFiles,
}
}
// convertToSimplifiedAddonWithoutFiles converts a full Addon to SimplifiedAddon without files
func convertToSimplifiedAddonWithoutFiles(addon models.Addon) models.SimplifiedAddon {
return models.SimplifiedAddon{
ID: addon.ID,
Name: addon.Name,
Type: addon.Type,
Summary: addon.Summary,
SubscriberCount: addon.SubscriberCount,
CurrentVersionNumber: addon.CurrentVersionNumber,
Preview: addon.Preview,
Author: addon.Author,
AddonFiles: []models.SimplifiedAddonFile{}, // Empty slice
}
}
func GetDuplicates(c *gin.Context) {
id := c.Param("id")
fmt.Println("Fetching addon with ID:", id)
// Fetch the source addon with its files
var sourceAddon models.Addon
if err := initializers.DB.Preload("AddonFiles").First(&sourceAddon, "id = ?", id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Addon not found"})
return
}
// Convert to simplified addon
simplifiedSourceAddon := convertToSimplifiedAddon(sourceAddon)
// If the addon has no files, return early
if len(sourceAddon.AddonFiles) == 0 {
c.JSON(http.StatusOK, models.DuplicatesResponse{
SourceAddon: simplifiedSourceAddon,
DuplicateAddons: make(map[string]models.AddonWithDuplicates),
})
return
}
// Extract all hashes from source addon files
var sourceHashes []string
for _, file := range sourceAddon.AddonFiles {
if file.Hash != "" {
sourceHashes = append(sourceHashes, file.Hash)
}
}
if len(sourceHashes) == 0 {
c.JSON(http.StatusOK, models.DuplicatesResponse{
SourceAddon: simplifiedSourceAddon,
DuplicateAddons: make(map[string]models.AddonWithDuplicates),
})
return
}
// Find all addon files that have matching hashes but belong to different addons
var duplicateFiles []models.AddonFile
if err := initializers.DB.Where("hash IN ? AND addon_id != ?", sourceHashes, id).Find(&duplicateFiles).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch duplicate files"})
return
}
// Group duplicate files by addon ID
duplicatesByAddonID := make(map[string][]models.AddonFile)
for _, file := range duplicateFiles {
duplicatesByAddonID[file.AddonID] = append(duplicatesByAddonID[file.AddonID], file)
}
// Fetch addon information for each addon that has duplicates
var addonIDs []string
for addonID := range duplicatesByAddonID {
addonIDs = append(addonIDs, addonID)
}
var duplicateAddons []models.Addon
if len(addonIDs) > 0 {
if err := initializers.DB.Where("id IN ?", addonIDs).Find(&duplicateAddons).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch duplicate addons"})
return
}
}
// Build the response
response := models.DuplicatesResponse{
SourceAddon: simplifiedSourceAddon,
DuplicateAddons: make(map[string]models.AddonWithDuplicates),
}
// Create a map for easy addon lookup
addonMap := make(map[string]models.Addon)
for _, addon := range duplicateAddons {
addonMap[addon.ID] = addon
}
// Build the duplicate addons response
for addonID, files := range duplicatesByAddonID {
var duplicateFileInfos []models.DuplicateFileInfo
for _, file := range files {
duplicateFileInfos = append(duplicateFileInfos, models.DuplicateFileInfo{
Path: file.Path,
Hash: file.Hash,
Version: file.Version,
AddonID: file.AddonID,
})
}
if addon, exists := addonMap[addonID]; exists {
response.DuplicateAddons[addonID] = models.AddonWithDuplicates{
Addon: convertToSimplifiedAddonWithoutFiles(addon),
Duplicates: duplicateFileInfos,
}
}
}
c.JSON(http.StatusOK, response)
}
func GetPossibleAddons(c *gin.Context) {
query := c.Query("q")
if query == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Query parameter 'q' is required"})
return
}
// Set default limit
limit := 20
if limitParam := c.Query("limit"); limitParam != "" {
if parsedLimit, err := strconv.Atoi(limitParam); err == nil && parsedLimit > 0 && parsedLimit <= 100 {
limit = parsedLimit
}
}
fmt.Printf("Searching for addons with query: %s (limit: %d)\n", query, limit)
var addons []models.Addon
// Search by ID (exact match) or by name (case-insensitive partial match)
// Using OR condition to search both ID and name fields
dbQuery := initializers.DB.Where("id = ? OR LOWER(name) LIKE LOWER(?)", query, "%"+query+"%").
Order("subscriber_count DESC"). // Order by popularity
Limit(limit)
if err := dbQuery.Find(&addons).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to search addons"})
return
}
// Convert to search results
var results []models.AddonSearchResult
for _, addon := range addons {
results = append(results, models.AddonSearchResult{
ID: addon.ID,
Name: addon.Name,
Type: addon.Type,
Summary: addon.Summary,
Preview: addon.Preview,
SubscriberCount: addon.SubscriberCount,
CurrentVersionNumber: addon.CurrentVersionNumber,
Author: addon.Author,
})
}
response := models.SearchResponse{
Query: query,
Results: results,
Total: len(results),
}
c.JSON(http.StatusOK, response)
}