mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
520 lines
15 KiB
Go
520 lines
15 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"bugulma/backend/internal/domain"
|
|
"bugulma/backend/internal/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type ContentHandler struct {
|
|
contentService *service.ContentService
|
|
}
|
|
|
|
func NewContentHandler(contentService *service.ContentService) *ContentHandler {
|
|
return &ContentHandler{
|
|
contentService: contentService,
|
|
}
|
|
}
|
|
|
|
// Static Pages
|
|
|
|
// ListPages lists static pages (admin only)
|
|
// @Summary List static pages
|
|
// @Tags admin
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/admin/content/pages [get]
|
|
func (h *ContentHandler) ListPages(c *gin.Context) {
|
|
pages, err := h.contentService.ListPages(c.Request.Context(), nil)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"pages": pages})
|
|
}
|
|
|
|
// GetPage gets a page by ID (admin only)
|
|
// @Summary Get page
|
|
// @Tags admin
|
|
// @Produce json
|
|
// @Param id path string true "Page ID"
|
|
// @Success 200 {object} domain.StaticPage
|
|
// @Router /api/v1/admin/content/pages/:id [get]
|
|
func (h *ContentHandler) GetPage(c *gin.Context) {
|
|
id := c.Param("id")
|
|
page, err := h.contentService.GetPage(c.Request.Context(), id)
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Page not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, page)
|
|
}
|
|
|
|
// CreatePage creates a new page (admin only)
|
|
// @Summary Create page
|
|
// @Tags admin
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body CreatePageRequest true "Page request"
|
|
// @Success 201 {object} domain.StaticPage
|
|
// @Router /api/v1/admin/content/pages [post]
|
|
func (h *ContentHandler) CreatePage(c *gin.Context) {
|
|
var req CreatePageRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
userID, _ := c.Get("user_id")
|
|
|
|
page := &domain.StaticPage{
|
|
Slug: req.Slug,
|
|
Title: req.Title,
|
|
Content: req.Content,
|
|
MetaDescription: req.MetaDescription,
|
|
Status: domain.PageStatus(req.Status),
|
|
Visibility: domain.PageVisibility(req.Visibility),
|
|
Template: req.Template,
|
|
CreatedBy: userID.(string),
|
|
UpdatedBy: userID.(string),
|
|
}
|
|
|
|
if err := h.contentService.CreatePage(c.Request.Context(), page); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, page)
|
|
}
|
|
|
|
type CreatePageRequest struct {
|
|
Slug string `json:"slug" binding:"required"`
|
|
Title string `json:"title" binding:"required"`
|
|
Content string `json:"content"`
|
|
MetaDescription string `json:"metaDescription"`
|
|
SEOKeywords []string `json:"seoKeywords"`
|
|
Status string `json:"status"`
|
|
Visibility string `json:"visibility"`
|
|
Template string `json:"template"`
|
|
}
|
|
|
|
// UpdatePage updates a page (admin only)
|
|
// @Summary Update page
|
|
// @Tags admin
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "Page ID"
|
|
// @Param request body UpdatePageRequest true "Update request"
|
|
// @Success 200 {object} domain.StaticPage
|
|
// @Router /api/v1/admin/content/pages/:id [put]
|
|
func (h *ContentHandler) UpdatePage(c *gin.Context) {
|
|
id := c.Param("id")
|
|
|
|
var req UpdatePageRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
page, err := h.contentService.GetPage(c.Request.Context(), id)
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Page not found"})
|
|
return
|
|
}
|
|
|
|
userID, _ := c.Get("user_id")
|
|
|
|
if req.Title != nil {
|
|
page.Title = *req.Title
|
|
}
|
|
if req.Content != nil {
|
|
page.Content = *req.Content
|
|
}
|
|
if req.MetaDescription != nil {
|
|
page.MetaDescription = *req.MetaDescription
|
|
}
|
|
if req.Status != nil {
|
|
page.Status = domain.PageStatus(*req.Status)
|
|
}
|
|
if req.Visibility != nil {
|
|
page.Visibility = domain.PageVisibility(*req.Visibility)
|
|
}
|
|
page.UpdatedBy = userID.(string)
|
|
|
|
if err := h.contentService.UpdatePage(c.Request.Context(), page); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, page)
|
|
}
|
|
|
|
type UpdatePageRequest struct {
|
|
Title *string `json:"title"`
|
|
Content *string `json:"content"`
|
|
MetaDescription *string `json:"metaDescription"`
|
|
Status *string `json:"status"`
|
|
Visibility *string `json:"visibility"`
|
|
}
|
|
|
|
// DeletePage deletes a page (admin only)
|
|
// @Summary Delete page
|
|
// @Tags admin
|
|
// @Success 200 {object} map[string]string
|
|
// @Router /api/v1/admin/content/pages/:id [delete]
|
|
func (h *ContentHandler) DeletePage(c *gin.Context) {
|
|
id := c.Param("id")
|
|
if err := h.contentService.DeletePage(c.Request.Context(), id); err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Page not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "Page deleted"})
|
|
}
|
|
|
|
// PublishPage publishes a page (admin only)
|
|
// @Summary Publish page
|
|
// @Tags admin
|
|
// @Success 200 {object} domain.StaticPage
|
|
// @Router /api/v1/admin/content/pages/:id/publish [post]
|
|
func (h *ContentHandler) PublishPage(c *gin.Context) {
|
|
id := c.Param("id")
|
|
if err := h.contentService.PublishPage(c.Request.Context(), id); err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Page not found"})
|
|
return
|
|
}
|
|
page, _ := h.contentService.GetPage(c.Request.Context(), id)
|
|
c.JSON(http.StatusOK, page)
|
|
}
|
|
|
|
// Announcements
|
|
|
|
// ListAnnouncements lists announcements (admin only)
|
|
// @Summary List announcements
|
|
// @Tags admin
|
|
// @Produce json
|
|
// @Param isActive query bool false "Filter by active status"
|
|
// @Param priority query string false "Filter by priority"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/admin/content/announcements [get]
|
|
func (h *ContentHandler) ListAnnouncements(c *gin.Context) {
|
|
filters := domain.AnnouncementFilters{}
|
|
|
|
if isActiveStr := c.Query("isActive"); isActiveStr != "" {
|
|
isActive := isActiveStr == "true"
|
|
filters.IsActive = &isActive
|
|
}
|
|
if priorityStr := c.Query("priority"); priorityStr != "" {
|
|
priority := domain.AnnouncementPriority(priorityStr)
|
|
filters.Priority = &priority
|
|
}
|
|
|
|
announcements, err := h.contentService.ListAnnouncements(c.Request.Context(), filters)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"announcements": announcements})
|
|
}
|
|
|
|
// GetAnnouncement gets an announcement by ID (admin only)
|
|
// @Summary Get announcement
|
|
// @Tags admin
|
|
// @Produce json
|
|
// @Param id path string true "Announcement ID"
|
|
// @Success 200 {object} domain.Announcement
|
|
// @Router /api/v1/admin/content/announcements/:id [get]
|
|
func (h *ContentHandler) GetAnnouncement(c *gin.Context) {
|
|
id := c.Param("id")
|
|
announcement, err := h.contentService.GetAnnouncement(c.Request.Context(), id)
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Announcement not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, announcement)
|
|
}
|
|
|
|
// CreateAnnouncement creates a new announcement (admin only)
|
|
// @Summary Create announcement
|
|
// @Tags admin
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body CreateAnnouncementRequest true "Announcement request"
|
|
// @Success 201 {object} domain.Announcement
|
|
// @Router /api/v1/admin/content/announcements [post]
|
|
func (h *ContentHandler) CreateAnnouncement(c *gin.Context) {
|
|
var req CreateAnnouncementRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
userID, _ := c.Get("user_id")
|
|
|
|
announcement := &domain.Announcement{
|
|
Title: req.Title,
|
|
Content: req.Content,
|
|
Priority: domain.AnnouncementPriority(req.Priority),
|
|
DisplayType: domain.AnnouncementDisplayType(req.DisplayType),
|
|
TargetAudience: domain.AnnouncementTargetAudience(req.TargetAudience),
|
|
StartDate: req.StartDate,
|
|
EndDate: req.EndDate,
|
|
IsActive: req.IsActive,
|
|
CreatedBy: userID.(string),
|
|
UpdatedBy: userID.(string),
|
|
}
|
|
|
|
if err := h.contentService.CreateAnnouncement(c.Request.Context(), announcement); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, announcement)
|
|
}
|
|
|
|
type CreateAnnouncementRequest struct {
|
|
Title string `json:"title" binding:"required"`
|
|
Content string `json:"content" binding:"required"`
|
|
Priority string `json:"priority"`
|
|
DisplayType string `json:"displayType"`
|
|
TargetAudience string `json:"targetAudience"`
|
|
StartDate *time.Time `json:"startDate"`
|
|
EndDate *time.Time `json:"endDate"`
|
|
IsActive bool `json:"isActive"`
|
|
}
|
|
|
|
// UpdateAnnouncement updates an announcement (admin only)
|
|
// @Summary Update announcement
|
|
// @Tags admin
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "Announcement ID"
|
|
// @Param request body UpdateAnnouncementRequest true "Update request"
|
|
// @Success 200 {object} domain.Announcement
|
|
// @Router /api/v1/admin/content/announcements/:id [put]
|
|
func (h *ContentHandler) UpdateAnnouncement(c *gin.Context) {
|
|
id := c.Param("id")
|
|
|
|
var req UpdateAnnouncementRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
announcement, err := h.contentService.GetAnnouncement(c.Request.Context(), id)
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Announcement not found"})
|
|
return
|
|
}
|
|
|
|
userID, _ := c.Get("user_id")
|
|
|
|
if req.Title != nil {
|
|
announcement.Title = *req.Title
|
|
}
|
|
if req.Content != nil {
|
|
announcement.Content = *req.Content
|
|
}
|
|
if req.Priority != nil {
|
|
announcement.Priority = domain.AnnouncementPriority(*req.Priority)
|
|
}
|
|
if req.IsActive != nil {
|
|
announcement.IsActive = *req.IsActive
|
|
}
|
|
announcement.UpdatedBy = userID.(string)
|
|
|
|
if err := h.contentService.UpdateAnnouncement(c.Request.Context(), announcement); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, announcement)
|
|
}
|
|
|
|
type UpdateAnnouncementRequest struct {
|
|
Title *string `json:"title"`
|
|
Content *string `json:"content"`
|
|
Priority *string `json:"priority"`
|
|
IsActive *bool `json:"isActive"`
|
|
}
|
|
|
|
// DeleteAnnouncement deletes an announcement (admin only)
|
|
// @Summary Delete announcement
|
|
// @Tags admin
|
|
// @Success 200 {object} map[string]string
|
|
// @Router /api/v1/admin/content/announcements/:id [delete]
|
|
func (h *ContentHandler) DeleteAnnouncement(c *gin.Context) {
|
|
id := c.Param("id")
|
|
if err := h.contentService.DeleteAnnouncement(c.Request.Context(), id); err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Announcement not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "Announcement deleted"})
|
|
}
|
|
|
|
// Media Assets
|
|
|
|
// ListMediaAssets lists media assets (admin only)
|
|
// @Summary List media assets
|
|
// @Tags admin
|
|
// @Produce json
|
|
// @Param type query string false "Filter by type"
|
|
// @Param tags query string false "Filter by tags (comma-separated)"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/admin/content/media [get]
|
|
func (h *ContentHandler) ListMediaAssets(c *gin.Context) {
|
|
filters := domain.MediaAssetFilters{}
|
|
|
|
if typeStr := c.Query("type"); typeStr != "" {
|
|
assetType := domain.MediaAssetType(typeStr)
|
|
filters.Type = &assetType
|
|
}
|
|
if tagsStr := c.Query("tags"); tagsStr != "" {
|
|
// Parse comma-separated tags
|
|
tags := strings.Split(tagsStr, ",")
|
|
for i := range tags {
|
|
tags[i] = strings.TrimSpace(tags[i])
|
|
}
|
|
filters.Tags = tags
|
|
}
|
|
|
|
assets, err := h.contentService.ListMediaAssets(c.Request.Context(), filters)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"assets": assets})
|
|
}
|
|
|
|
// GetMediaAsset gets a media asset by ID (admin only)
|
|
// @Summary Get media asset
|
|
// @Tags admin
|
|
// @Produce json
|
|
// @Param id path string true "Media Asset ID"
|
|
// @Success 200 {object} domain.MediaAsset
|
|
// @Router /api/v1/admin/content/media/:id [get]
|
|
func (h *ContentHandler) GetMediaAsset(c *gin.Context) {
|
|
id := c.Param("id")
|
|
asset, err := h.contentService.GetMediaAsset(c.Request.Context(), id)
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Media asset not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, asset)
|
|
}
|
|
|
|
// CreateMediaAsset creates a new media asset (admin only)
|
|
// @Summary Create media asset
|
|
// @Tags admin
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body CreateMediaAssetRequest true "Media asset request"
|
|
// @Success 201 {object} domain.MediaAsset
|
|
// @Router /api/v1/admin/content/media [post]
|
|
func (h *ContentHandler) CreateMediaAsset(c *gin.Context) {
|
|
var req CreateMediaAssetRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
userID, _ := c.Get("user_id")
|
|
|
|
asset := &domain.MediaAsset{
|
|
Filename: req.Filename,
|
|
OriginalName: req.OriginalName,
|
|
URL: req.URL,
|
|
Type: domain.MediaAssetType(req.Type),
|
|
MimeType: req.MimeType,
|
|
Size: req.Size,
|
|
Width: req.Width,
|
|
Height: req.Height,
|
|
Duration: req.Duration,
|
|
AltText: req.AltText,
|
|
UploadedBy: userID.(string),
|
|
}
|
|
|
|
if err := h.contentService.CreateMediaAsset(c.Request.Context(), asset); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, asset)
|
|
}
|
|
|
|
type CreateMediaAssetRequest struct {
|
|
Filename string `json:"filename" binding:"required"`
|
|
OriginalName string `json:"originalName" binding:"required"`
|
|
URL string `json:"url" binding:"required"`
|
|
Type string `json:"type" binding:"required"`
|
|
MimeType string `json:"mimeType"`
|
|
Size int64 `json:"size"`
|
|
Width *int `json:"width"`
|
|
Height *int `json:"height"`
|
|
Duration *int `json:"duration"`
|
|
AltText string `json:"altText"`
|
|
Tags []string `json:"tags"`
|
|
}
|
|
|
|
// UpdateMediaAsset updates a media asset (admin only)
|
|
// @Summary Update media asset
|
|
// @Tags admin
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "Media Asset ID"
|
|
// @Param request body UpdateMediaAssetRequest true "Update request"
|
|
// @Success 200 {object} domain.MediaAsset
|
|
// @Router /api/v1/admin/content/media/:id [put]
|
|
func (h *ContentHandler) UpdateMediaAsset(c *gin.Context) {
|
|
id := c.Param("id")
|
|
|
|
var req UpdateMediaAssetRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
asset, err := h.contentService.GetMediaAsset(c.Request.Context(), id)
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Media asset not found"})
|
|
return
|
|
}
|
|
|
|
if req.AltText != nil {
|
|
asset.AltText = *req.AltText
|
|
}
|
|
if req.Tags != nil {
|
|
// Tags would need JSON marshaling
|
|
}
|
|
|
|
if err := h.contentService.UpdateMediaAsset(c.Request.Context(), asset); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, asset)
|
|
}
|
|
|
|
type UpdateMediaAssetRequest struct {
|
|
AltText *string `json:"altText"`
|
|
Tags *[]string `json:"tags"`
|
|
}
|
|
|
|
// DeleteMediaAsset deletes a media asset (admin only)
|
|
// @Summary Delete media asset
|
|
// @Tags admin
|
|
// @Success 200 {object} map[string]string
|
|
// @Router /api/v1/admin/content/media/:id [delete]
|
|
func (h *ContentHandler) DeleteMediaAsset(c *gin.Context) {
|
|
id := c.Param("id")
|
|
if err := h.contentService.DeleteMediaAsset(c.Request.Context(), id); err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Media asset not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "Media asset deleted"})
|
|
}
|