mirror of
https://github.com/Dvorinka/PPve.git
synced 2026-06-04 04:22:58 +00:00
294 lines
8.0 KiB
Go
294 lines
8.0 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// Initialize banner data
|
|
func init() {
|
|
// Create data directory if it doesn't exist
|
|
if err := os.MkdirAll("data", 0755); err != nil {
|
|
log.Printf("Warning: Failed to create data directory: %v", err)
|
|
}
|
|
|
|
// Create uploads directory if it doesn't exist
|
|
if err := os.MkdirAll(uploadDir, 0755); err != nil {
|
|
log.Printf("Warning: Failed to create uploads directory: %v", err)
|
|
}
|
|
|
|
// Load banner data from file if it exists
|
|
if data, err := ioutil.ReadFile(bannerDataFile); err == nil {
|
|
if err := json.Unmarshal(data, &banner); err != nil {
|
|
log.Printf("Error loading banner data: %v", err)
|
|
initDefaultBanner()
|
|
}
|
|
} else {
|
|
initDefaultBanner()
|
|
}
|
|
}
|
|
|
|
const (
|
|
bannerDataFile = "data/banner.json"
|
|
uploadDir = "uploads"
|
|
)
|
|
|
|
// Ensure directories exist
|
|
func ensureDirs() error {
|
|
if err := os.MkdirAll(filepath.Dir(bannerDataFile), 0755); err != nil {
|
|
return err
|
|
}
|
|
if err := os.MkdirAll(uploadDir, 0755); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type BannerContent struct {
|
|
Text string `json:"text"`
|
|
Image string `json:"image,omitempty"`
|
|
Link string `json:"link,omitempty"`
|
|
Style BannerStyle `json:"style"`
|
|
}
|
|
|
|
type BannerStyle struct {
|
|
BackgroundColor string `json:"backgroundColor"`
|
|
TextColor string `json:"textColor"`
|
|
TextAlign string `json:"textAlign"`
|
|
FontSize string `json:"fontSize"`
|
|
Padding string `json:"padding"`
|
|
Margin string `json:"margin"`
|
|
BorderRadius string `json:"borderRadius"`
|
|
IsVisible bool `json:"isVisible"`
|
|
}
|
|
|
|
var (
|
|
banner BannerContent
|
|
bannerLock sync.RWMutex
|
|
)
|
|
|
|
func init() {
|
|
// Ensure directories exist
|
|
if err := ensureDirs(); err != nil {
|
|
log.Printf("Warning: Failed to create required directories: %v", err)
|
|
}
|
|
|
|
// Load banner data from file if it exists
|
|
if data, err := ioutil.ReadFile(bannerDataFile); err == nil {
|
|
if err := json.Unmarshal(data, &banner); err != nil {
|
|
log.Printf("Error loading banner data: %v", err)
|
|
initDefaultBanner()
|
|
}
|
|
} else {
|
|
initDefaultBanner()
|
|
}
|
|
}
|
|
|
|
func initDefaultBanner() {
|
|
banner = BannerContent{
|
|
Text: "Vítejte na našem webu!",
|
|
Style: BannerStyle{
|
|
BackgroundColor: "#f8d7da",
|
|
TextColor: "#721c24",
|
|
TextAlign: "center",
|
|
FontSize: "18px",
|
|
Padding: "20px",
|
|
Margin: "20px",
|
|
BorderRadius: "8px",
|
|
IsVisible: true,
|
|
},
|
|
}
|
|
saveBannerData()
|
|
}
|
|
|
|
func saveBannerData() error {
|
|
bannerLock.Lock()
|
|
defer bannerLock.Unlock()
|
|
|
|
data, err := json.MarshalIndent(banner, "", " ")
|
|
if err != nil {
|
|
log.Printf("Error marshaling banner data to JSON: %v", err)
|
|
return fmt.Errorf("failed to marshal banner data: %w", err)
|
|
}
|
|
|
|
if err := ioutil.WriteFile(bannerDataFile, data, 0644); err != nil {
|
|
log.Printf("Error writing banner data to file %s: %v", bannerDataFile, err)
|
|
return fmt.Errorf("failed to write banner data to file: %w", err)
|
|
}
|
|
|
|
log.Printf("Successfully saved banner data to %s", bannerDataFile)
|
|
return nil
|
|
}
|
|
|
|
func GetBannerHandler(w http.ResponseWriter, r *http.Request) {
|
|
bannerLock.RLock()
|
|
defer bannerLock.RUnlock()
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
json.NewEncoder(w).Encode(banner)
|
|
}
|
|
|
|
func UpdateBannerHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == http.MethodOptions {
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
|
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
|
w.WriteHeader(http.StatusOK)
|
|
return
|
|
}
|
|
|
|
if r.Method != http.MethodPost {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
// Set CORS headers
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
// Parse multipart form for file uploads
|
|
if err := r.ParseMultipartForm(10 << 20); err != nil { // 10 MB max
|
|
log.Printf("Error parsing form data: %v", err)
|
|
http.Error(w, "Error parsing form data: "+err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Log form values for debugging
|
|
log.Printf("Form values: %+v", r.Form)
|
|
|
|
// Create a new banner with default values
|
|
newBanner := BannerContent{
|
|
Text: r.FormValue("text"),
|
|
Link: r.FormValue("link"),
|
|
Style: BannerStyle{
|
|
BackgroundColor: r.FormValue("style[backgroundColor]"),
|
|
TextColor: r.FormValue("style[textColor]"),
|
|
TextAlign: r.FormValue("style[textAlign]"),
|
|
FontSize: r.FormValue("style[fontSize]"),
|
|
Padding: r.FormValue("style[padding]"),
|
|
Margin: r.FormValue("style[margin]"),
|
|
BorderRadius: r.FormValue("style[borderRadius]"),
|
|
IsVisible: r.FormValue("style[isVisible]") == "true",
|
|
},
|
|
}
|
|
|
|
// Log the banner data for debugging
|
|
log.Printf("Parsed banner data: %+v", newBanner)
|
|
|
|
// Handle file upload
|
|
file, handler, err := r.FormFile("image")
|
|
if err == nil {
|
|
log.Println("Processing file upload...")
|
|
defer file.Close()
|
|
|
|
// Ensure uploads directory exists
|
|
if err := ensureDirs(); err != nil {
|
|
log.Printf("Error ensuring directories exist: %v", err)
|
|
http.Error(w, "Error preparing upload directory", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Get the file extension
|
|
ext := filepath.Ext(handler.Filename)
|
|
if ext == "" {
|
|
ext = ".jpg" // Default extension if none provided
|
|
}
|
|
|
|
// Create a new file in the uploads directory with a unique name
|
|
tempFile, err := ioutil.TempFile(uploadDir, "banner-*"+ext)
|
|
if err != nil {
|
|
log.Printf("Error creating temp file: %v", err)
|
|
http.Error(w, "Error creating file", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
defer tempFile.Close()
|
|
|
|
// Copy the uploaded file to the destination file
|
|
if _, err := io.Copy(tempFile, file); err != nil {
|
|
log.Printf("Error saving file: %v", err)
|
|
http.Error(w, "Error saving file", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Get the relative path for the web
|
|
relPath := "/uploads/" + filepath.Base(tempFile.Name())
|
|
log.Printf("File uploaded successfully: %s", relPath)
|
|
newBanner.Image = relPath
|
|
} else if r.FormValue("removeImage") == "true" {
|
|
// If removeImage is set, clear the image
|
|
log.Println("Removing banner image")
|
|
newBanner.Image = ""
|
|
} else {
|
|
// Keep the existing image if no new one is uploaded
|
|
bannerLock.RLock()
|
|
newBanner.Image = banner.Image
|
|
bannerLock.RUnlock()
|
|
log.Printf("Keeping existing image: %s", newBanner.Image)
|
|
}
|
|
|
|
// Update banner data
|
|
bannerLock.Lock()
|
|
banner = newBanner
|
|
err = saveBannerData()
|
|
bannerLock.Unlock()
|
|
|
|
if err != nil {
|
|
http.Error(w, "Error saving banner data", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(banner)
|
|
}
|
|
|
|
// ServeUploads handles serving uploaded files
|
|
func ServeUploads(w http.ResponseWriter, r *http.Request) {
|
|
// Clean the path to prevent directory traversal
|
|
path := filepath.Clean(r.URL.Path)
|
|
|
|
// Only serve files from the uploads directory
|
|
if !strings.HasPrefix(path, "/uploads/") {
|
|
log.Printf("Access denied: %s is outside uploads directory", path)
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
|
|
// Remove the /uploads/ prefix to get the actual file path
|
|
filename := filepath.Join(uploadDir, strings.TrimPrefix(path, "/uploads/"))
|
|
|
|
// Ensure the file exists and is within the uploads directory
|
|
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
|
log.Printf("File not found: %s", filename)
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
|
|
// Set cache control headers (cache for 1 day)
|
|
w.Header().Set("Cache-Control", "public, max-age=86400")
|
|
// Set content type based on file extension
|
|
ext := filepath.Ext(filename)
|
|
if ext == ".jpg" || ext == ".jpeg" {
|
|
w.Header().Set("Content-Type", "image/jpeg")
|
|
} else if ext == ".png" {
|
|
w.Header().Set("Content-Type", "image/png")
|
|
} else if ext == ".gif" {
|
|
w.Header().Set("Content-Type", "image/gif")
|
|
} else if ext == ".svg" {
|
|
w.Header().Set("Content-Type", "image/svg+xml")
|
|
} else {
|
|
w.Header().Set("Content-Type", "application/octet-stream")
|
|
}
|
|
|
|
http.ServeFile(w, r, filename)
|
|
log.Printf("Served file: %s", filename)
|
|
}
|