Files
Poll-system/app/internal/handlers/admin_post.go
2025-08-26 14:13:09 -06:00

160 lines
4.3 KiB
Go

// Updated admin_post.go with better image handling
package handlers
import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/patel-mann/poll-system/app/internal/models"
"github.com/patel-mann/poll-system/app/internal/utils"
)
func PostsHandler(w http.ResponseWriter, r *http.Request) {
userID := r.Context().Value("user_id").(int)
role := r.Context().Value("user_role").(int)
if r.Method == http.MethodPost {
// Parse multipart form
err := r.ParseMultipartForm(10 << 20) // 10MB max
if err != nil {
fmt.Printf("Error parsing form: %v\n", err)
http.Error(w, "Invalid form", http.StatusBadRequest)
return
}
content := r.FormValue("content")
if strings.TrimSpace(content) == "" {
http.Error(w, "Content cannot be empty", http.StatusBadRequest)
return
}
var imagePath string
file, handler, err := r.FormFile("image")
if err == nil && file != nil {
defer file.Close()
// Validate file type
allowedTypes := map[string]bool{
".jpg": true,
".jpeg": true,
".png": true,
".gif": true,
".webp": true,
}
ext := strings.ToLower(filepath.Ext(handler.Filename))
if !allowedTypes[ext] {
http.Error(w, "Invalid file type. Only images allowed.", http.StatusBadRequest)
return
}
// Ensure uploads folder exists
uploadDir := "uploads"
if err := os.MkdirAll(uploadDir, 0755); err != nil {
fmt.Printf("Error creating upload directory: %v\n", err)
http.Error(w, "Unable to create upload directory", http.StatusInternalServerError)
return
}
// Create unique filename
filename := fmt.Sprintf("%d_%d%s", userID, time.Now().UnixNano(), ext)
savePath := filepath.Join(uploadDir, filename)
out, err := os.Create(savePath)
if err != nil {
fmt.Printf("Error creating file: %v\n", err)
http.Error(w, "Unable to save file", http.StatusInternalServerError)
return
}
defer out.Close()
_, err = io.Copy(out, file)
if err != nil {
fmt.Printf("Error copying file: %v\n", err)
http.Error(w, "Failed to save file", http.StatusInternalServerError)
return
}
// Save path relative to the static route
imagePath = "/uploads/" + filename
fmt.Printf("Image saved at: %s\n", imagePath)
} else if err != http.ErrMissingFile {
fmt.Printf("Error getting file: %v\n", err)
}
// Insert post
_, err = models.DB.Exec(`INSERT INTO post (author_id, content, image_url) VALUES ($1, $2, $3)`,
userID, content, imagePath)
if err != nil {
fmt.Printf("Database error: %v\n", err)
http.Error(w, "Failed to create post", http.StatusInternalServerError)
return
}
fmt.Printf("Post created successfully with image: %s\n", imagePath)
http.Redirect(w, r, "/posts", http.StatusSeeOther)
return
}
// GET request: fetch posts
rows, err := models.DB.Query(`
SELECT p.post_id, p.author_id, u.first_name || ' ' || u.last_name AS author_name,
p.content, COALESCE(p.image_url, '') as image_url, p.created_at
FROM post p
JOIN users u ON p.author_id = u.user_id
ORDER BY p.created_at DESC
`)
if err != nil {
fmt.Printf("Database query error: %v\n", err)
http.Error(w, "Failed to fetch posts", http.StatusInternalServerError)
return
}
defer rows.Close()
var posts []models.Post
for rows.Next() {
var p models.Post
err := rows.Scan(&p.PostID, &p.AuthorID, &p.AuthorName, &p.Content, &p.ImageURL, &p.CreatedAt)
if err != nil {
fmt.Printf("Row scan error: %v\n", err)
continue
}
posts = append(posts, p)
}
// Add cache busting parameter to image URLs
for i := range posts {
if posts[i].ImageURL != "" {
posts[i].ImageURL += "?t=" + strconv.FormatInt(time.Now().UnixNano(), 10)
fmt.Printf("Post %d image URL: %s\n", posts[i].PostID, posts[i].ImageURL)
}
}
// Get navigation flags
showAdminNav, showVolunteerNav := getNavFlags(role)
fmt.Printf("Rendering %d posts\n", len(posts))
utils.Render(w, "posts.html", map[string]interface{}{
"Title": "Posts",
"IsAuthenticated": true,
"ShowAdminNav": showAdminNav,
"ShowVolunteerNav": showVolunteerNav,
"Posts": posts,
"ActiveSection": "posts",
})
}
// Helper function (add this to your main.go if not already there)
func getNavFlags(role int) (bool, bool) {
showAdminNav := role == 1 // Admin role
showVolunteerNav := role == 3 // Volunteer role
return showAdminNav, showVolunteerNav
}