package themes_handler import ( "errors" "fmt" "mime" "net/http" "os" "path/filepath" "strings" "autolibrary.top/webserver/backend/models/themes_model" "github.com/gin-gonic/gin" "gorm.io/gorm" ) func (h *Handler) DownloadTheme(c *gin.Context) { h.serveTheme(c, true) } func (h *Handler) AdminDownloadTheme(c *gin.Context) { h.serveTheme(c, false) } func (h *Handler) serveTheme(c *gin.Context, public bool) { id, err := parseThemeID(c) if err != nil { fail(c, http.StatusBadRequest, "Invalid theme ID") return } var theme themes_model.Theme query := h.DB if public { query = query.Where("status = ?", themes_model.ThemeApproved) } err = query.First(&theme, id).Error if errors.Is(err, gorm.ErrRecordNotFound) { fail(c, 404, "Theme not found") return } if err != nil { fail(c, 500, "Unable to load theme") return } path := h.Themes.ArchivePath(theme.ID) info, err := os.Stat(path) if err != nil || info.IsDir() { fail(c, 404, "Theme file not found") return } if public { h.DB.Model(&theme).UpdateColumn("download_count", gorm.Expr("download_count + 1")) } version := strings.TrimLeft(theme.Version, "vV") name := fmt.Sprintf("%s_v%s.altheme", theme.Name, version) c.Header("Content-Disposition", mime.FormatMediaType("attachment", map[string]string{"filename": name})) c.Header("Content-Type", "application/zip") c.File(path) } func (h *Handler) ServePreview(c *gin.Context) { name := c.Param("filename") if name == "." || name == ".." || strings.ContainsAny(name, `/\`) || filepath.Base(name) != name { fail(c, 400, "Invalid preview filename") return } path := filepath.Join(h.Files.Root(), "previews", name) info, err := os.Stat(path) if err != nil || info.IsDir() { fail(c, 404, "Preview not found") return } c.Header("Cache-Control", "public, max-age=3600") c.File(path) }