Files
gobeyhan/internal/handler/admin/blog_handler.go
Beyhan Oğur f34e54c5a5 first commit
2026-04-26 21:43:40 +03:00

538 lines
16 KiB
Go

package admin
import (
"gobeyhan/config"
"gobeyhan/database"
"gobeyhan/database/models"
"gobeyhan/pkg/utils"
"gobeyhan/views/admin/blog"
"log"
"net/http"
"path/filepath"
"strconv"
"github.com/gin-gonic/gin"
)
type BlogHandler struct{}
func NewBlogHandler() *BlogHandler {
return &BlogHandler{}
}
// List displays all blog posts
func (h *BlogHandler) List(c *gin.Context) {
var posts []models.Post
err := database.DB.
Preload("User").
Preload("Categories").
Preload("Tags").
Order("created_at DESC").
Find(&posts).Error
if err != nil {
log.Printf("[BlogHandler.List] Error fetching posts: %v", err)
c.String(http.StatusInternalServerError, "Error fetching posts")
return
}
blog.List(posts).Render(c.Request.Context(), c.Writer)
}
// New displays the create form
func (h *BlogHandler) New(c *gin.Context) {
var categories []models.Category
var tags []models.Tag
database.DB.Where("is_active = ?", true).Find(&categories)
database.DB.Where("is_active = ?", true).Find(&tags)
blog.Create(categories, tags, nil).Render(c.Request.Context(), c.Writer)
}
// Create handles post creation
func (h *BlogHandler) Create(c *gin.Context) {
title := c.PostForm("title")
content := c.PostForm("content")
keywords := c.PostForm("keywords")
isActive := c.PostForm("is_active") == "on"
isFront := c.PostForm("is_front") == "on"
log.Printf("[BlogHandler.Create] Received: Title=%s, ContentSize=%d, Active=%v", title, len(content), isActive)
// Validation
errors := make(map[string]string)
if title == "" {
errors["title"] = "Title is required"
}
if content == "" {
errors["content"] = "Content is required"
}
if len(errors) > 0 {
log.Printf("[BlogHandler.Create] Validation failed: %v", errors)
var categories []models.Category
var tags []models.Tag
database.DB.Where("is_active = ?", true).Find(&categories)
database.DB.Where("is_active = ?", true).Find(&tags)
blog.Create(categories, tags, errors).Render(c.Request.Context(), c.Writer)
return
}
// Handle image upload
imagePath := c.PostForm("image") // Fallback to manual link if provided
file, err := c.FormFile("image_file")
if err == nil && file != nil {
opts := &utils.ImageOptions{
Width: config.AppConfig.PostImageWidth,
Height: config.AppConfig.PostImageHeight,
Quality: float32(config.AppConfig.PostImageQuality),
Format: config.AppConfig.PostImageFormat,
Mode: config.AppConfig.PostImageMode,
}
path, err := utils.SaveOptimizedImage(file, filepath.Join("uploads", "blog"), "post", opts)
if err == nil {
imagePath = path
log.Printf("[BlogHandler.Create] Image saved to: %s", imagePath)
} else {
log.Printf("[BlogHandler.Create] Image upload error: %v", err)
}
}
// Create post
post := models.Post{
Title: title,
Content: content,
Keywords: keywords,
Image: imagePath,
IsActive: isActive,
IsFront: isFront,
}
if err := database.DB.Create(&post).Error; err != nil {
log.Printf("[BlogHandler.Create] DB Create error: %v", err)
errors["general"] = "Error creating post: " + err.Error()
var categories []models.Category
var tags []models.Tag
database.DB.Where("is_active = ?", true).Find(&categories)
database.DB.Where("is_active = ?", true).Find(&tags)
blog.Create(categories, tags, errors).Render(c.Request.Context(), c.Writer)
return
}
log.Printf("[BlogHandler.Create] Post created successfully: ID=%d", post.ID)
// Handle categories
categoryIDs := c.PostFormArray("category_ids")
if len(categoryIDs) > 0 {
var categories []*models.Category
for _, idStr := range categoryIDs {
id, _ := strconv.ParseUint(idStr, 10, 64)
categories = append(categories, &models.Category{ID: id})
}
if err := database.DB.Model(&post).Association("Categories").Replace(categories); err != nil {
log.Printf("[BlogHandler.Create] Error associating categories: %v", err)
}
}
// Handle tags
tagIDs := c.PostFormArray("tag_ids")
if len(tagIDs) > 0 {
var tags []*models.Tag
for _, idStr := range tagIDs {
id, _ := strconv.ParseUint(idStr, 10, 64)
tags = append(tags, &models.Tag{ID: id})
}
if err := database.DB.Model(&post).Association("Tags").Replace(tags); err != nil {
log.Printf("[BlogHandler.Create] Error associating tags: %v", err)
}
}
c.Redirect(http.StatusSeeOther, "/admin/blog")
}
// Edit displays the edit form
func (h *BlogHandler) Edit(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
c.String(http.StatusBadRequest, "Invalid ID")
return
}
var post models.Post
err = database.DB.
Preload("Categories").
Preload("Tags").
First(&post, id).Error
if err != nil {
log.Printf("[BlogHandler.Edit] Post not found: ID=%d, error=%v", id, err)
c.String(http.StatusNotFound, "Post not found")
return
}
var categories []models.Category
var tags []models.Tag
database.DB.Where("is_active = ?", true).Find(&categories)
database.DB.Where("is_active = ?", true).Find(&tags)
blog.Edit(&post, categories, tags, nil).Render(c.Request.Context(), c.Writer)
}
// Update handles post updates
func (h *BlogHandler) Update(c *gin.Context) {
id := c.Param("id")
idUint, _ := strconv.ParseUint(id, 10, 64)
title := c.PostForm("title")
content := c.PostForm("content")
keywords := c.PostForm("keywords")
isActive := c.PostForm("is_active") == "on"
isFront := c.PostForm("is_front") == "on"
log.Printf("[BlogHandler.Update] Received update for ID=%s: Title=%s, ContentSize=%d", id, title, len(content))
// Validation
errors := make(map[string]string)
if title == "" {
errors["title"] = "Title is required"
}
if content == "" {
errors["content"] = "Content is required"
}
if len(errors) > 0 {
log.Printf("[BlogHandler.Update] Validation failed: %v", errors)
var post models.Post
database.DB.Preload("Categories").Preload("Tags").First(&post, idUint)
var categories []models.Category
var tags []models.Tag
database.DB.Where("is_active = ?", true).Find(&categories)
database.DB.Where("is_active = ?", true).Find(&tags)
blog.Edit(&post, categories, tags, errors).Render(c.Request.Context(), c.Writer)
return
}
// Handle image upload
imagePath := c.PostForm("image") // Keep existing or use manual link
file, err := c.FormFile("image_file")
if err == nil && file != nil {
opts := &utils.ImageOptions{
Width: config.AppConfig.PostImageWidth,
Height: config.AppConfig.PostImageHeight,
Quality: float32(config.AppConfig.PostImageQuality),
Format: config.AppConfig.PostImageFormat,
Mode: config.AppConfig.PostImageMode,
}
path, err := utils.SaveOptimizedImage(file, filepath.Join("uploads", "blog"), "post", opts)
if err == nil {
imagePath = path
log.Printf("[BlogHandler.Update] Image updated to: %s", imagePath)
} else {
log.Printf("[BlogHandler.Update] Image upload error: %v", err)
}
}
// Update post
updates := map[string]interface{}{
"title": title,
"content": content,
"keywords": keywords,
"image": imagePath,
"is_active": isActive,
"is_front": isFront,
}
if err := database.DB.Model(&models.Post{}).Where("id = ?", id).Updates(updates).Error; err != nil {
log.Printf("[BlogHandler.Update] DB Update error: %v", err)
errors["general"] = "Error updating post"
var post models.Post
database.DB.Preload("Categories").Preload("Tags").First(&post, idUint)
var categories []models.Category
var tags []models.Tag
database.DB.Where("is_active = ?", true).Find(&categories)
database.DB.Where("is_active = ?", true).Find(&tags)
blog.Edit(&post, categories, tags, errors).Render(c.Request.Context(), c.Writer)
return
}
// Update categories and tags separately (GORM Associations)
var post models.Post
if err := database.DB.First(&post, idUint).Error; err == nil {
// Categories
categoryIDs := c.PostFormArray("category_ids")
var categories []*models.Category
for _, idStr := range categoryIDs {
catID, _ := strconv.ParseUint(idStr, 10, 64)
categories = append(categories, &models.Category{ID: catID})
}
database.DB.Model(&post).Association("Categories").Replace(categories)
// Tags
tagIDs := c.PostFormArray("tag_ids")
var tags []*models.Tag
for _, idStr := range tagIDs {
tagID, _ := strconv.ParseUint(idStr, 10, 64)
tags = append(tags, &models.Tag{ID: tagID})
}
database.DB.Model(&post).Association("Tags").Replace(tags)
}
log.Printf("[BlogHandler.Update] Post updated successfully: ID=%s", id)
c.Redirect(http.StatusSeeOther, "/admin/blog")
}
// Delete handles post deletion
func (h *BlogHandler) Delete(c *gin.Context) {
id := c.Param("id")
log.Printf("[BlogHandler.Delete] Deleting ID=%s", id)
if err := database.DB.Delete(&models.Post{}, "id = ?", id).Error; err != nil {
log.Printf("[BlogHandler.Delete] Error: %v", err)
c.String(http.StatusInternalServerError, "Error deleting post")
return
}
c.Redirect(http.StatusSeeOther, "/admin/blog")
}
// ============================================
// CATEGORY HANDLERS
// ============================================
func (h *BlogHandler) ListCategories(c *gin.Context) {
var categories []models.Category
database.DB.Order("`order` ASC").Find(&categories)
blog.CategoryList(categories).Render(c.Request.Context(), c.Writer)
}
func (h *BlogHandler) NewCategory(c *gin.Context) {
var categories []models.Category
database.DB.Find(&categories)
blog.CategoryForm(&models.Category{}, categories, nil).Render(c.Request.Context(), c.Writer)
}
func (h *BlogHandler) CreateCategory(c *gin.Context) {
var cat models.Category
cat.Title = c.PostForm("title")
cat.Slug = c.PostForm("slug")
cat.Desc = c.PostForm("description")
cat.Keywords = c.PostForm("keywords")
cat.IsActive = c.PostForm("is_active") == "on"
order, _ := strconv.Atoi(c.PostForm("order"))
cat.Order = order
parentIDStr := c.PostForm("parent_id")
if parentIDStr != "" {
pID, _ := strconv.ParseUint(parentIDStr, 10, 64)
cat.ParentID = &pID
}
if cat.Title == "" {
errors := map[string]string{"title": "Title is required"}
var categories []models.Category
database.DB.Find(&categories)
blog.CategoryForm(&cat, categories, errors).Render(c.Request.Context(), c.Writer)
return
}
if err := database.DB.Create(&cat).Error; err != nil {
errors := map[string]string{"general": err.Error()}
var categories []models.Category
database.DB.Find(&categories)
blog.CategoryForm(&cat, categories, errors).Render(c.Request.Context(), c.Writer)
return
}
c.Redirect(http.StatusSeeOther, "/admin/blog/categories")
}
func (h *BlogHandler) EditCategory(c *gin.Context) {
id := c.Param("id")
var cat models.Category
if err := database.DB.First(&cat, id).Error; err != nil {
c.String(http.StatusNotFound, "Category not found")
return
}
var categories []models.Category
database.DB.Find(&categories)
blog.CategoryForm(&cat, categories, nil).Render(c.Request.Context(), c.Writer)
}
func (h *BlogHandler) UpdateCategory(c *gin.Context) {
id := c.Param("id")
var cat models.Category
if err := database.DB.First(&cat, id).Error; err != nil {
c.String(http.StatusNotFound, "Category not found")
return
}
cat.Title = c.PostForm("title")
cat.Slug = c.PostForm("slug")
cat.Desc = c.PostForm("description")
cat.Keywords = c.PostForm("keywords")
cat.IsActive = c.PostForm("is_active") == "on"
order, _ := strconv.Atoi(c.PostForm("order"))
cat.Order = order
parentIDStr := c.PostForm("parent_id")
if parentIDStr != "" {
pID, _ := strconv.ParseUint(parentIDStr, 10, 64)
cat.ParentID = &pID
} else {
cat.ParentID = nil
}
if cat.Title == "" {
errors := map[string]string{"title": "Title is required"}
var categories []models.Category
database.DB.Find(&categories)
blog.CategoryForm(&cat, categories, errors).Render(c.Request.Context(), c.Writer)
return
}
if err := database.DB.Save(&cat).Error; err != nil {
errors := map[string]string{"general": err.Error()}
var categories []models.Category
database.DB.Find(&categories)
blog.CategoryForm(&cat, categories, errors).Render(c.Request.Context(), c.Writer)
return
}
c.Redirect(http.StatusSeeOther, "/admin/blog/categories")
}
func (h *BlogHandler) DeleteCategory(c *gin.Context) {
id := c.Param("id")
database.DB.Delete(&models.Category{}, id)
c.Redirect(http.StatusSeeOther, "/admin/blog/categories")
}
// ============================================
// TAG HANDLERS
// ============================================
func (h *BlogHandler) ListTags(c *gin.Context) {
var tags []models.Tag
database.DB.Order("tag ASC").Find(&tags)
blog.TagList(tags).Render(c.Request.Context(), c.Writer)
}
func (h *BlogHandler) NewTag(c *gin.Context) {
blog.TagForm(&models.Tag{}, nil).Render(c.Request.Context(), c.Writer)
}
func (h *BlogHandler) CreateTag(c *gin.Context) {
var tag models.Tag
tag.Tag = c.PostForm("tag")
tag.Slug = c.PostForm("slug")
tag.IsActive = true // Default
if tag.Tag == "" {
errors := map[string]string{"tag": "Tag name is required"}
blog.TagForm(&tag, errors).Render(c.Request.Context(), c.Writer)
return
}
if err := database.DB.Create(&tag).Error; err != nil {
errors := map[string]string{"general": err.Error()}
blog.TagForm(&tag, errors).Render(c.Request.Context(), c.Writer)
return
}
c.Redirect(http.StatusSeeOther, "/admin/blog/tags")
}
func (h *BlogHandler) EditTag(c *gin.Context) {
id := c.Param("id")
var tag models.Tag
if err := database.DB.First(&tag, id).Error; err != nil {
c.String(http.StatusNotFound, "Tag not found")
return
}
blog.TagForm(&tag, nil).Render(c.Request.Context(), c.Writer)
}
func (h *BlogHandler) UpdateTag(c *gin.Context) {
id := c.Param("id")
var tag models.Tag
if err := database.DB.First(&tag, id).Error; err != nil {
c.String(http.StatusNotFound, "Tag not found")
return
}
tag.Tag = c.PostForm("tag")
tag.Slug = c.PostForm("slug")
if tag.Tag == "" {
errors := map[string]string{"tag": "Tag name is required"}
blog.TagForm(&tag, errors).Render(c.Request.Context(), c.Writer)
return
}
if err := database.DB.Save(&tag).Error; err != nil {
errors := map[string]string{"general": err.Error()}
blog.TagForm(&tag, errors).Render(c.Request.Context(), c.Writer)
return
}
c.Redirect(http.StatusSeeOther, "/admin/blog/tags")
}
func (h *BlogHandler) DeleteTag(c *gin.Context) {
id := c.Param("id")
database.DB.Delete(&models.Tag{}, id)
c.Redirect(http.StatusSeeOther, "/admin/blog/tags")
}
// ============================================
// COMMENT HANDLERS
// ============================================
func (h *BlogHandler) ListComments(c *gin.Context) {
var comments []models.Comment
database.DB.Preload("Product").Order("created_at DESC").Find(&comments)
blog.CommentList(comments).Render(c.Request.Context(), c.Writer)
}
func (h *BlogHandler) EditComment(c *gin.Context) {
id := c.Param("id")
var comment models.Comment
if err := database.DB.Preload("Product").First(&comment, id).Error; err != nil {
c.String(http.StatusNotFound, "Comment not found")
return
}
blog.CommentForm(&comment, nil).Render(c.Request.Context(), c.Writer)
}
func (h *BlogHandler) UpdateComment(c *gin.Context) {
id := c.Param("id")
var comment models.Comment
if err := database.DB.First(&comment, id).Error; err != nil {
c.String(http.StatusNotFound, "Comment not found")
return
}
comment.Body = c.PostForm("body")
comment.IsActive = c.PostForm("is_active") == "on"
if err := database.DB.Save(&comment).Error; err != nil {
errors := map[string]string{"general": err.Error()}
blog.CommentForm(&comment, errors).Render(c.Request.Context(), c.Writer)
return
}
c.Redirect(http.StatusSeeOther, "/admin/blog/comments")
}
func (h *BlogHandler) DeleteComment(c *gin.Context) {
id := c.Param("id")
database.DB.Delete(&models.Comment{}, id)
c.Redirect(http.StatusSeeOther, "/admin/blog/comments")
}