Add 404 page, add Deleted page, fix errors

This commit is contained in:
2026-02-27 19:32:37 +01:00
parent 1b2f2bb942
commit 90a2f43ab6
9 changed files with 375 additions and 36 deletions

View File

@@ -30,6 +30,9 @@ func uploadHandler(c *gin.Context) {
id := uuid.New().String()
delID := uuid.New().String()
cleanName := filepath.Base(header.Filename)
if len(cleanName) > 255 {
cleanName = cleanName[:255]
}
folderPath := filepath.Join("uploads", id)
os.MkdirAll(folderPath, 0755)
@@ -65,6 +68,7 @@ func uploadHandler(c *gin.Context) {
Filename: cleanName,
Path: storagePath,
ExpiresAt: expiry,
Size: written,
DeleteAfterDownload: c.PostForm("once") == "true",
}
@@ -79,14 +83,21 @@ func uploadHandler(c *gin.Context) {
func downloadHandler(c *gin.Context) {
var record FileRecord
if err := db.First(&record, "id = ? AND deleted = ?", c.Param("id"), false).Error; err != nil {
c.String(404, "File not found or expired")
var err = db.First(&record, "id = ? AND deleted = ?", c.Param("id"), false).Error
if err != nil {
c.HTML(200, "fileNotFound.html", gin.H{
"message": "File not found",
})
return
}
if time.Now().After(record.ExpiresAt) {
performDeletion(&record)
c.String(410, "File has expired")
//c.String(410, "File has expired")
c.HTML(404, "fileNotFound.html", gin.H{
"message": "File not found",
})
return
}
@@ -107,7 +118,8 @@ func deleteHandler(c *gin.Context) {
return
}
performDeletion(&record)
c.JSON(200, gin.H{"message": "Deleted successfully"})
//c.JSON(200, gin.H{"message": "Deleted successfully"})
c.HTML(200, "deleted.html", nil)
}
func loginHandler(c *gin.Context) {
@@ -145,3 +157,30 @@ func loginHandler(c *gin.Context) {
c.Redirect(302, "/admin")
}
func adminIndexHandler(c *gin.Context) {
var files []FileRecord
// Pagination parameters
perPage := 20
page := 1
if p := c.Query("page"); p != "" {
if v, err := strconv.Atoi(p); err == nil && v > 0 {
page = v
}
}
var total int64
db.Model(&FileRecord{}).Count(&total)
totalPages := int((total + int64(perPage) - 1) / int64(perPage)) // ceiling division
offset := (page - 1) * perPage
db.Order("created_at desc").Limit(perPage).Offset(offset).Find(&files)
c.HTML(200, "admin.html", gin.H{
"Files": files,
"Page": page,
"TotalPages": totalPages,
})
}

View File

@@ -6,7 +6,6 @@ import (
"log"
"os"
"path/filepath"
"strconv"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
@@ -34,8 +33,9 @@ func main() {
router := gin.Default()
router.MaxMultipartMemory = 10 << 30
router.SetFuncMap(template.FuncMap{
"add": func(a, b int) int { return a + b },
"sub": func(a, b int) int { return a - b },
"add": func(a, b int) int { return a + b },
"sub": func(a, b int) int { return a - b },
"humanSize": humanSize,
})
router.LoadHTMLGlob("templates/*")
var staticPath = gin.Dir("./static", false)
@@ -43,6 +43,9 @@ func main() {
router.StaticFS("/static", staticPath)
router.NoRoute(func(c *gin.Context) {
c.HTML(404, "error.html", nil)
})
// Public Routes
router.GET("/", func(c *gin.Context) { c.HTML(200, "index.html", nil) })
router.GET("/f/:id", downloadHandler)
@@ -53,34 +56,16 @@ func main() {
admin := router.Group("/admin")
admin.Use(authMiddleware())
admin.GET("/", func(c *gin.Context) {
var files []FileRecord
// Pagination parameters
perPage := 20
page := 1
if p := c.Query("page"); p != "" {
if v, err := strconv.Atoi(p); err == nil && v > 0 {
page = v
}
admin.GET("/", adminIndexHandler)
admin.GET("/delete/fr/:id", func(c *gin.Context) {
var record FileRecord
if err := db.First(&record, "id = ?", c.Param("id")).Error; err == nil {
performActualDeletion(&record)
}
var total int64
db.Model(&FileRecord{}).Count(&total)
totalPages := int((total + int64(perPage) - 1) / int64(perPage)) // ceiling division
offset := (page - 1) * perPage
db.Order("created_at desc").Limit(perPage).Offset(offset).Find(&files)
c.HTML(200, "admin.html", gin.H{
"Files": files,
"Page": page,
"TotalPages": totalPages,
})
c.Redirect(301, "/admin")
})
admin.POST("/delete/:id", func(c *gin.Context) {
admin.GET("/delete/:id", func(c *gin.Context) {
var record FileRecord
if err := db.First(&record, "id = ?", c.Param("id")).Error; err == nil {
performDeletion(&record)

View File

@@ -9,6 +9,7 @@ type FileRecord struct {
Path string `json:"-"`
ExpiresAt time.Time `json:"expires_at"`
DeleteAfterDownload bool `json:"delete_after_download"`
Size int64 `json:"size"`
DownloadCount int `json:"download_count"`
Deleted bool `json:"deleted"`
CreatedAt time.Time `json:"created_at"`

View File

@@ -1,6 +1,9 @@
package main
import (
"fmt"
"os"
"path/filepath"
"time"
"github.com/gin-gonic/gin"
@@ -12,6 +15,19 @@ func performDeletion(r *FileRecord) {
db.Save(r)
}
func performActualDeletion(r *FileRecord) {
folderPath := filepath.Join("uploads", r.ID)
err := os.RemoveAll(folderPath)
if err != nil {
fmt.Println("Error deleting file:", err)
return
}
db.Delete(r)
fmt.Println("Deleted file:", r.Filename)
}
func cleanupWorker() {
for {
time.Sleep(10 * time.Minute)
@@ -38,7 +54,7 @@ func authMiddleware() gin.HandlerFunc {
tokenStr, err := c.Cookie("auth")
if err != nil {
c.Redirect(302, "/")
c.Redirect(302, "/login")
c.Abort()
return
}
@@ -48,7 +64,7 @@ func authMiddleware() gin.HandlerFunc {
})
if err != nil || !token.Valid {
c.Redirect(302, "/")
c.Redirect(302, "/login")
c.Abort()
return
}
@@ -56,3 +72,19 @@ func authMiddleware() gin.HandlerFunc {
c.Next()
}
}
func humanSize(size int64) string {
const unit = 1024
if size < unit {
return fmt.Sprintf("%d B", size)
}
div, exp := int64(unit), 0
for n := size / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB",
float64(size)/float64(div),
"KMGTPE"[exp],
)
}