Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Dashboard ambient layer, comrade presence, Mission Deck and War Room, Emberwake supply chain, spread/docs publishing, fleet policy and modules API, CI docker mining, and refreshed USB pack.
107 lines
2.4 KiB
Go
107 lines
2.4 KiB
Go
package api
|
|
|
|
import (
|
|
"archive/zip"
|
|
"bytes"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
var slugSanitize = regexp.MustCompile(`[^a-zA-Z0-9._-]+`)
|
|
|
|
// sanitizeExportSlug lowercases and strips unsafe characters for filenames and campaign segments.
|
|
func sanitizeExportSlug(s string) string {
|
|
s = strings.TrimSpace(s)
|
|
s = strings.ToLower(s)
|
|
s = slugSanitize.ReplaceAllString(s, "-")
|
|
s = strings.Trim(s, "-.")
|
|
if s == "" {
|
|
return "site"
|
|
}
|
|
if len(s) > 48 {
|
|
s = s[:48]
|
|
}
|
|
return s
|
|
}
|
|
|
|
// zipTemplateReplacements walks templateDir, applies repl to file contents, and writes a ZIP archive.
|
|
// remap rewrites archive entry paths (e.g. plugin-template → my-site).
|
|
func zipTemplateReplacements(templateDir string, repl map[string]string, remap func(rel string) string) ([]byte, error) {
|
|
templateDir, err := filepath.Abs(templateDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var buf bytes.Buffer
|
|
zw := zip.NewWriter(&buf)
|
|
err = filepath.Walk(templateDir, func(path string, info os.FileInfo, walkErr error) error {
|
|
if walkErr != nil || info.IsDir() {
|
|
return walkErr
|
|
}
|
|
rel, err := filepath.Rel(templateDir, path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rel = filepath.ToSlash(rel)
|
|
if remap != nil {
|
|
rel = remap(rel)
|
|
}
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
content := string(data)
|
|
for k, v := range repl {
|
|
content = strings.ReplaceAll(content, k, v)
|
|
}
|
|
w, err := zw.Create(rel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = io.WriteString(w, content)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := zw.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
func writeZipAttachment(w http.ResponseWriter, filename string, data []byte) {
|
|
w.Header().Set("Content-Type", "application/zip")
|
|
w.Header().Set("Content-Disposition", `attachment; filename="`+filename+`"`)
|
|
w.Write(data)
|
|
}
|
|
|
|
func slugDisplayName(slug string) string {
|
|
parts := strings.Split(slug, "-")
|
|
for i, p := range parts {
|
|
if p == "" {
|
|
continue
|
|
}
|
|
parts[i] = strings.ToUpper(p[:1]) + p[1:]
|
|
}
|
|
return strings.Join(parts, " ")
|
|
}
|
|
|
|
func buildQuerySuffix(buildID, campaign string) (querySuffix, getQuerySuffix string) {
|
|
var qparts []string
|
|
if buildID != "" {
|
|
qparts = append(qparts, "pin="+buildID)
|
|
}
|
|
if campaign != "" {
|
|
qparts = append(qparts, "c="+campaign)
|
|
}
|
|
if len(qparts) == 0 {
|
|
return "", ""
|
|
}
|
|
joined := strings.Join(qparts, "&")
|
|
return "?" + joined, "&" + joined
|
|
}
|