| package admin |
|
|
| import ( |
| "strconv" |
| "strings" |
| "time" |
|
|
| "github.com/Wei-Shaw/sub2api/internal/handler/dto" |
| "github.com/Wei-Shaw/sub2api/internal/pkg/pagination" |
| "github.com/Wei-Shaw/sub2api/internal/pkg/response" |
| middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware" |
| "github.com/Wei-Shaw/sub2api/internal/service" |
|
|
| "github.com/gin-gonic/gin" |
| ) |
|
|
| |
| type AnnouncementHandler struct { |
| announcementService *service.AnnouncementService |
| } |
|
|
| |
| func NewAnnouncementHandler(announcementService *service.AnnouncementService) *AnnouncementHandler { |
| return &AnnouncementHandler{ |
| announcementService: announcementService, |
| } |
| } |
|
|
| type CreateAnnouncementRequest struct { |
| Title string `json:"title" binding:"required"` |
| Content string `json:"content" binding:"required"` |
| Status string `json:"status" binding:"omitempty,oneof=draft active archived"` |
| NotifyMode string `json:"notify_mode" binding:"omitempty,oneof=silent popup"` |
| Targeting service.AnnouncementTargeting `json:"targeting"` |
| StartsAt *int64 `json:"starts_at"` |
| EndsAt *int64 `json:"ends_at"` |
| } |
|
|
| type UpdateAnnouncementRequest struct { |
| Title *string `json:"title"` |
| Content *string `json:"content"` |
| Status *string `json:"status" binding:"omitempty,oneof=draft active archived"` |
| NotifyMode *string `json:"notify_mode" binding:"omitempty,oneof=silent popup"` |
| Targeting *service.AnnouncementTargeting `json:"targeting"` |
| StartsAt *int64 `json:"starts_at"` |
| EndsAt *int64 `json:"ends_at"` |
| } |
|
|
| |
| |
| func (h *AnnouncementHandler) List(c *gin.Context) { |
| page, pageSize := response.ParsePagination(c) |
| status := strings.TrimSpace(c.Query("status")) |
| search := strings.TrimSpace(c.Query("search")) |
| if len(search) > 200 { |
| search = search[:200] |
| } |
|
|
| params := pagination.PaginationParams{ |
| Page: page, |
| PageSize: pageSize, |
| } |
|
|
| items, paginationResult, err := h.announcementService.List( |
| c.Request.Context(), |
| params, |
| service.AnnouncementListFilters{Status: status, Search: search}, |
| ) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| out := make([]dto.Announcement, 0, len(items)) |
| for i := range items { |
| out = append(out, *dto.AnnouncementFromService(&items[i])) |
| } |
| response.Paginated(c, out, paginationResult.Total, page, pageSize) |
| } |
|
|
| |
| |
| func (h *AnnouncementHandler) GetByID(c *gin.Context) { |
| announcementID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil || announcementID <= 0 { |
| response.BadRequest(c, "Invalid announcement ID") |
| return |
| } |
|
|
| item, err := h.announcementService.GetByID(c.Request.Context(), announcementID) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, dto.AnnouncementFromService(item)) |
| } |
|
|
| |
| |
| func (h *AnnouncementHandler) Create(c *gin.Context) { |
| var req CreateAnnouncementRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| response.BadRequest(c, "Invalid request: "+err.Error()) |
| return |
| } |
|
|
| subject, ok := middleware2.GetAuthSubjectFromContext(c) |
| if !ok { |
| response.Unauthorized(c, "User not found in context") |
| return |
| } |
|
|
| input := &service.CreateAnnouncementInput{ |
| Title: req.Title, |
| Content: req.Content, |
| Status: req.Status, |
| NotifyMode: req.NotifyMode, |
| Targeting: req.Targeting, |
| ActorID: &subject.UserID, |
| } |
|
|
| if req.StartsAt != nil && *req.StartsAt > 0 { |
| t := time.Unix(*req.StartsAt, 0) |
| input.StartsAt = &t |
| } |
| if req.EndsAt != nil && *req.EndsAt > 0 { |
| t := time.Unix(*req.EndsAt, 0) |
| input.EndsAt = &t |
| } |
|
|
| created, err := h.announcementService.Create(c.Request.Context(), input) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, dto.AnnouncementFromService(created)) |
| } |
|
|
| |
| |
| func (h *AnnouncementHandler) Update(c *gin.Context) { |
| announcementID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil || announcementID <= 0 { |
| response.BadRequest(c, "Invalid announcement ID") |
| return |
| } |
|
|
| var req UpdateAnnouncementRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| response.BadRequest(c, "Invalid request: "+err.Error()) |
| return |
| } |
|
|
| subject, ok := middleware2.GetAuthSubjectFromContext(c) |
| if !ok { |
| response.Unauthorized(c, "User not found in context") |
| return |
| } |
|
|
| input := &service.UpdateAnnouncementInput{ |
| Title: req.Title, |
| Content: req.Content, |
| Status: req.Status, |
| NotifyMode: req.NotifyMode, |
| Targeting: req.Targeting, |
| ActorID: &subject.UserID, |
| } |
|
|
| if req.StartsAt != nil { |
| if *req.StartsAt == 0 { |
| var cleared *time.Time = nil |
| input.StartsAt = &cleared |
| } else { |
| t := time.Unix(*req.StartsAt, 0) |
| ptr := &t |
| input.StartsAt = &ptr |
| } |
| } |
|
|
| if req.EndsAt != nil { |
| if *req.EndsAt == 0 { |
| var cleared *time.Time = nil |
| input.EndsAt = &cleared |
| } else { |
| t := time.Unix(*req.EndsAt, 0) |
| ptr := &t |
| input.EndsAt = &ptr |
| } |
| } |
|
|
| updated, err := h.announcementService.Update(c.Request.Context(), announcementID, input) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, dto.AnnouncementFromService(updated)) |
| } |
|
|
| |
| |
| func (h *AnnouncementHandler) Delete(c *gin.Context) { |
| announcementID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil || announcementID <= 0 { |
| response.BadRequest(c, "Invalid announcement ID") |
| return |
| } |
|
|
| if err := h.announcementService.Delete(c.Request.Context(), announcementID); err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, gin.H{"message": "Announcement deleted successfully"}) |
| } |
|
|
| |
| |
| func (h *AnnouncementHandler) ListReadStatus(c *gin.Context) { |
| announcementID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil || announcementID <= 0 { |
| response.BadRequest(c, "Invalid announcement ID") |
| return |
| } |
|
|
| page, pageSize := response.ParsePagination(c) |
| params := pagination.PaginationParams{ |
| Page: page, |
| PageSize: pageSize, |
| } |
| search := strings.TrimSpace(c.Query("search")) |
| if len(search) > 200 { |
| search = search[:200] |
| } |
|
|
| items, paginationResult, err := h.announcementService.ListUserReadStatus( |
| c.Request.Context(), |
| announcementID, |
| params, |
| search, |
| ) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Paginated(c, items, paginationResult.Total, page, pageSize) |
| } |
|
|