package main import ( "fmt" "io" "net/http" "os" "path/filepath" "time" "github.com/gin-gonic/gin" "github.com/google/uuid" ) const ( UPLOAD_DIR = "./uploads" MAX_FILE_SIZE = 10 << 20 ) func main() { if err := os.MkdirAll(UPLOAD_DIR, 0755); err != nil { panic(fmt.Sprintf("Failed to create upload directory: %v", err)) } router := gin.Default() router.LoadHTMLGlob("templates/*") router.GET("/", homeHandler) router.POST("/upload", uploadHandler) router.Static("/static", "./static") router.Run(":8787") } func homeHandler(c *gin.Context) { c.HTML(http.StatusOK, "index.html", gin.H{ "title": "town share", }) } func uploadHandler(c *gin.Context) { file, header, err := c.Request.FormFile("image") if err != nil { renderError(c, "melancholy") return } defer file.Close() if header.Size > MAX_FILE_SIZE { renderError(c, "max size is 10mb") return } contentType := header.Header.Get("Content-Type") if !isValidImageType(contentType) { renderError(c, "only jpg, png, and gif are supported") return } // TODO tweak this extension := filepath.Ext(header.Filename) uniqueFilename := fmt.Sprintf("%s-%s%s", uuid.New().String(), time.Now().Format("20060102-150405"), extension, ) destPath := filepath.Join(UPLOAD_DIR, uniqueFilename) dest, err := os.Create(destPath) if err != nil { renderError(c, "Failed to save file") return } defer dest.Close() if _, err := io.Copy(dest, file); err != nil { renderError(c, "Failed to save file") return } // TODO global const for title c.HTML(http.StatusOK, "index.html", gin.H{ "title": "town share", "success": fmt.Sprintf("file uploaded successfully as %s", uniqueFilename), }) } // renderError renders the home page with an error message func renderError(c *gin.Context, message string) { c.HTML(http.StatusOK, "index.html", gin.H{ "title": "town share", "error": message, }) } // isValidImageType checks if the content type is a supported image format func isValidImageType(contentType string) bool { validTypes := map[string]bool{ "image/jpeg": true, "image/jpg": true, "image/png": true, "image/gif": true, } return validTypes[contentType] }