- RenderModlistHTML: generates compatible preset HTML from a modlist - GET /api/modlists/:id/export: returns downloadable .html file - Export button on ModlistEditor page - Skips local mods (no workshop ID), includes only Steam workshop mods
224 lines
5.4 KiB
Go
224 lines
5.4 KiB
Go
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"arma3-web-server/internal/models"
|
|
"arma3-web-server/internal/services"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type createModlistInput struct {
|
|
Name string `json:"name" binding:"required"`
|
|
}
|
|
|
|
type updateModlistInput struct {
|
|
Name string `json:"name" binding:"required"`
|
|
Mods []models.ModEntry `json:"mods"`
|
|
}
|
|
|
|
type duplicateModlistInput struct {
|
|
Name string `json:"name" binding:"required"`
|
|
}
|
|
|
|
func (h *Handler) ListModlists(c *gin.Context) {
|
|
items, err := h.modlists.List()
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, items)
|
|
}
|
|
|
|
func (h *Handler) CreateModlist(c *gin.Context) {
|
|
var input createModlistInput
|
|
if err := c.ShouldBindJSON(&input); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ml, err := h.modlists.Create(input.Name)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, ml)
|
|
}
|
|
|
|
func (h *Handler) GetModlist(c *gin.Context) {
|
|
ml, err := h.modlists.Get(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, ml)
|
|
}
|
|
|
|
func (h *Handler) UpdateModlist(c *gin.Context) {
|
|
var input updateModlistInput
|
|
if err := c.ShouldBindJSON(&input); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ml, err := h.modlists.Update(c.Param("id"), input.Name, input.Mods)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, ml)
|
|
}
|
|
|
|
func (h *Handler) DeleteModlist(c *gin.Context) {
|
|
if err := h.modlists.Delete(c.Param("id")); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusNoContent, nil)
|
|
}
|
|
|
|
func (h *Handler) DuplicateModlist(c *gin.Context) {
|
|
var input duplicateModlistInput
|
|
if err := c.ShouldBindJSON(&input); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ml, err := h.modlists.Duplicate(c.Param("id"), input.Name)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, ml)
|
|
}
|
|
|
|
func (h *Handler) ImportModlist(c *gin.Context) {
|
|
file, header, err := c.Request.FormFile("file")
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "file field required"})
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
_, mods, err := services.ParseModlistHTML(file)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "parse html: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
listName := services.FileNameToModlistName(header.Filename)
|
|
|
|
ml, err := h.modlists.Create(listName)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
ml, err = h.modlists.Update(ml.ID, ml.Name, mods)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, ml)
|
|
}
|
|
|
|
func (h *Handler) ExportModlist(c *gin.Context) {
|
|
ml, err := h.modlists.Get(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
html, err := services.RenderModlistHTML(ml.Name, ml.Mods)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
filename := fmt.Sprintf("%s.html", strings.ReplaceAll(ml.Name, `"`, `_`))
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename))
|
|
c.String(http.StatusOK, html)
|
|
}
|
|
|
|
type modStatus struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Enabled bool `json:"enabled"`
|
|
Downloaded bool `json:"downloaded"`
|
|
}
|
|
|
|
func (h *Handler) CheckModlistMods(c *gin.Context) {
|
|
ml, err := h.modlists.Get(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
dir := h.process.ServerfileDir()
|
|
var result []modStatus
|
|
for _, m := range ml.Mods {
|
|
result = append(result, modStatus{
|
|
ID: m.ID,
|
|
Name: m.Name,
|
|
Enabled: m.Enabled,
|
|
Downloaded: services.CheckWorkshopMod(dir, m.ID),
|
|
})
|
|
}
|
|
c.JSON(http.StatusOK, result)
|
|
}
|
|
|
|
func (h *Handler) DownloadMissingMods(c *gin.Context) {
|
|
ml, err := h.modlists.Get(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
dir := h.process.ServerfileDir()
|
|
var missing []string
|
|
for _, m := range ml.Mods {
|
|
if m.ID != "" && !services.CheckWorkshopMod(dir, m.ID) {
|
|
missing = append(missing, m.ID)
|
|
}
|
|
}
|
|
|
|
if len(missing) == 0 {
|
|
c.JSON(http.StatusOK, gin.H{"status": "all mods present"})
|
|
return
|
|
}
|
|
|
|
if err := h.steamcmd.DownloadMods(missing); err != nil {
|
|
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"status": "downloading", "count": len(missing)})
|
|
}
|
|
|
|
func (h *Handler) UpdateAllMods(c *gin.Context) {
|
|
ml, err := h.modlists.Get(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
var ids []string
|
|
for _, m := range ml.Mods {
|
|
if m.ID != "" {
|
|
ids = append(ids, m.ID)
|
|
}
|
|
}
|
|
|
|
if len(ids) == 0 {
|
|
c.JSON(http.StatusOK, gin.H{"status": "no mods with workshop ids"})
|
|
return
|
|
}
|
|
|
|
if err := h.steamcmd.DownloadMods(ids); err != nil {
|
|
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"status": "updating", "count": len(ids)})
|
|
}
|