439 lines
11 KiB
Go
439 lines
11 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"eslogad-be/internal/appcontext"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"eslogad-be/internal/contract"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type LetterService interface {
|
|
CreateIncomingLetter(ctx context.Context, req *contract.CreateIncomingLetterRequest) (*contract.IncomingLetterResponse, error)
|
|
GetIncomingLetterByID(ctx context.Context, id uuid.UUID) (*contract.IncomingLetterResponse, error)
|
|
ListIncomingLetters(ctx context.Context, req *contract.ListIncomingLettersRequest) (*contract.ListIncomingLettersResponse, error)
|
|
GetLetterUnreadCounts(ctx context.Context) (*contract.LetterUnreadCountResponse, error)
|
|
MarkIncomingLetterAsRead(ctx context.Context, letterID uuid.UUID) (*contract.MarkLetterReadResponse, error)
|
|
MarkOutgoingLetterAsRead(ctx context.Context, letterID uuid.UUID) (*contract.MarkLetterReadResponse, error)
|
|
UpdateIncomingLetter(ctx context.Context, id uuid.UUID, req *contract.UpdateIncomingLetterRequest) (*contract.IncomingLetterResponse, error)
|
|
SoftDeleteIncomingLetter(ctx context.Context, id uuid.UUID) error
|
|
BulkArchiveIncomingLetters(ctx context.Context, letterIDs []uuid.UUID) (*contract.BulkArchiveLettersResponse, error)
|
|
|
|
CreateDispositions(ctx context.Context, req *contract.CreateLetterDispositionRequest) (*contract.ListDispositionsResponse, error)
|
|
GetEnhancedDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListEnhancedDispositionsResponse, error)
|
|
|
|
CreateDiscussion(ctx context.Context, letterID uuid.UUID, req *contract.CreateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error)
|
|
UpdateDiscussion(ctx context.Context, letterID uuid.UUID, discussionID uuid.UUID, req *contract.UpdateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error)
|
|
|
|
GetDepartmentDispositionStatus(ctx context.Context, req *contract.GetDepartmentDispositionStatusRequest) (*contract.ListDepartmentDispositionStatusResponse, error)
|
|
UpdateDispositionStatus(ctx context.Context, req *contract.UpdateDispositionStatusRequest) (*contract.DepartmentDispositionStatusResponse, error)
|
|
|
|
GetLetterCTA(ctx context.Context, letterID uuid.UUID) (*contract.LetterCTAResponse, error)
|
|
}
|
|
|
|
type LetterHandler struct {
|
|
svc LetterService
|
|
}
|
|
|
|
func NewLetterHandler(svc LetterService) *LetterHandler {
|
|
return &LetterHandler{svc: svc}
|
|
}
|
|
|
|
// Helper functions for common patterns
|
|
func (h *LetterHandler) parseUUID(c *gin.Context, param string) (uuid.UUID, bool) {
|
|
id, err := uuid.Parse(c.Param(param))
|
|
if err != nil {
|
|
h.respondError(c, http.StatusBadRequest, "invalid "+param)
|
|
return uuid.Nil, false
|
|
}
|
|
return id, true
|
|
}
|
|
|
|
func (h *LetterHandler) bindJSON(c *gin.Context, req interface{}) bool {
|
|
if err := c.ShouldBindJSON(req); err != nil {
|
|
h.respondError(c, http.StatusBadRequest, "invalid request body")
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (h *LetterHandler) bindQuery(c *gin.Context, req interface{}) bool {
|
|
if err := c.ShouldBindQuery(req); err != nil {
|
|
h.respondError(c, http.StatusBadRequest, "invalid query parameters")
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (h *LetterHandler) respondError(c *gin.Context, code int, message string) {
|
|
c.JSON(code, &contract.ErrorResponse{
|
|
Error: message,
|
|
Code: code,
|
|
})
|
|
}
|
|
|
|
func (h *LetterHandler) respondSuccess(c *gin.Context, code int, data interface{}) {
|
|
c.JSON(code, contract.BuildSuccessResponse(data))
|
|
}
|
|
|
|
func (h *LetterHandler) handleServiceError(c *gin.Context, err error) {
|
|
if err != nil {
|
|
h.respondError(c, http.StatusInternalServerError, err.Error())
|
|
}
|
|
}
|
|
|
|
func (h *LetterHandler) CreateIncomingLetter(c *gin.Context) {
|
|
var req contract.CreateIncomingLetterRequest
|
|
if !h.bindJSON(c, &req) {
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.CreateIncomingLetter(c.Request.Context(), &req)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusCreated, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) GetIncomingLetter(c *gin.Context) {
|
|
id, ok := h.parseUUID(c, "id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.GetIncomingLetterByID(c.Request.Context(), id)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) ListIncomingLetters(c *gin.Context) {
|
|
req := h.parseListRequest(c)
|
|
|
|
resp, err := h.svc.ListIncomingLetters(c.Request.Context(), req)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) GetLetterUnreadCounts(c *gin.Context) {
|
|
resp, err := h.svc.GetLetterUnreadCounts(c.Request.Context())
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) MarkIncomingLetterAsRead(c *gin.Context) {
|
|
id, ok := h.parseUUID(c, "id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.MarkIncomingLetterAsRead(c.Request.Context(), id)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) MarkOutgoingLetterAsRead(c *gin.Context) {
|
|
id, ok := h.parseUUID(c, "id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.MarkOutgoingLetterAsRead(c.Request.Context(), id)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) parseListRequest(c *gin.Context) *contract.ListIncomingLettersRequest {
|
|
//appCtx := appcontext.FromGinContext(c)
|
|
//departmentID := appCtx.DepartmentID
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
|
|
|
|
// Ensure valid pagination values
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
if limit < 1 {
|
|
limit = 10
|
|
}
|
|
if limit > 100 {
|
|
limit = 100
|
|
}
|
|
|
|
req := &contract.ListIncomingLettersRequest{
|
|
Page: page,
|
|
Limit: limit,
|
|
}
|
|
|
|
if status := c.Query("status"); status != "" {
|
|
req.Status = &status
|
|
}
|
|
|
|
if query := c.Query("q"); query != "" {
|
|
req.Query = &query
|
|
}
|
|
|
|
// Parse is_read filter
|
|
if isReadStr := c.Query("is_read"); isReadStr != "" {
|
|
isRead := isReadStr == "true" || isReadStr == "1"
|
|
req.IsRead = &isRead
|
|
}
|
|
|
|
// Parse priority_ids filter
|
|
if priorityIDsStr := c.QueryArray("priority_ids[]"); len(priorityIDsStr) > 0 {
|
|
priorityIDs := make([]uuid.UUID, 0, len(priorityIDsStr))
|
|
for _, idStr := range priorityIDsStr {
|
|
if id, err := uuid.Parse(idStr); err == nil {
|
|
priorityIDs = append(priorityIDs, id)
|
|
}
|
|
}
|
|
req.PriorityIDs = priorityIDs
|
|
} else if priorityIDStr := c.Query("priority_ids"); priorityIDStr != "" {
|
|
// Also support comma-separated format
|
|
idStrs := strings.Split(priorityIDStr, ",")
|
|
priorityIDs := make([]uuid.UUID, 0, len(idStrs))
|
|
for _, idStr := range idStrs {
|
|
if id, err := uuid.Parse(strings.TrimSpace(idStr)); err == nil {
|
|
priorityIDs = append(priorityIDs, id)
|
|
}
|
|
}
|
|
req.PriorityIDs = priorityIDs
|
|
}
|
|
|
|
// Parse is_dispositioned filter
|
|
if isDispositionedStr := c.Query("is_dispositioned"); isDispositionedStr != "" {
|
|
isDispositioned := isDispositionedStr == "true" || isDispositionedStr == "1"
|
|
req.IsDispositioned = &isDispositioned
|
|
}
|
|
|
|
// Parse is_archived filter
|
|
if isArchivedStr := c.Query("is_archived"); isArchivedStr != "" {
|
|
isArchived := isArchivedStr == "true" || isArchivedStr == "1"
|
|
req.IsArchived = &isArchived
|
|
}
|
|
|
|
//req.DepartmentID = &departmentID
|
|
|
|
return req
|
|
}
|
|
|
|
func (h *LetterHandler) UpdateIncomingLetter(c *gin.Context) {
|
|
id, ok := h.parseUUID(c, "id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
var req contract.UpdateIncomingLetterRequest
|
|
if !h.bindJSON(c, &req) {
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.UpdateIncomingLetter(c.Request.Context(), id, &req)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) DeleteIncomingLetter(c *gin.Context) {
|
|
id, ok := h.parseUUID(c, "id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
if err := h.svc.SoftDeleteIncomingLetter(c.Request.Context(), id); err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, &contract.SuccessResponse{
|
|
Message: "Letter deleted successfully",
|
|
})
|
|
}
|
|
|
|
func (h *LetterHandler) CreateDispositions(c *gin.Context) {
|
|
var req contract.CreateLetterDispositionRequest
|
|
if !h.bindJSON(c, &req) {
|
|
return
|
|
}
|
|
|
|
appCtx := appcontext.FromGinContext(c.Request.Context())
|
|
req.FromDepartment = appCtx.DepartmentID
|
|
|
|
resp, err := h.svc.CreateDispositions(c.Request.Context(), &req)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusCreated, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) GetEnhancedDispositionsByLetter(c *gin.Context) {
|
|
letterID, ok := h.parseUUID(c, "letter_id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.GetEnhancedDispositionsByLetter(c.Request.Context(), letterID)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) CreateDiscussion(c *gin.Context) {
|
|
letterID, ok := h.parseUUID(c, "letter_id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
var req contract.CreateLetterDiscussionRequest
|
|
if !h.bindJSON(c, &req) {
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.CreateDiscussion(c.Request.Context(), letterID, &req)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusCreated, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) UpdateDiscussion(c *gin.Context) {
|
|
letterID, ok := h.parseUUID(c, "letter_id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
discussionID, ok := h.parseUUID(c, "discussion_id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
var req contract.UpdateLetterDiscussionRequest
|
|
if !h.bindJSON(c, &req) {
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.UpdateDiscussion(c.Request.Context(), letterID, discussionID, &req)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) GetDepartmentDispositionStatus(c *gin.Context) {
|
|
letterID, ok := h.parseUUID(c, "letter_id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
departmentID := appcontext.FromGinContext(c.Request.Context()).DepartmentID
|
|
|
|
req := &contract.GetDepartmentDispositionStatusRequest{
|
|
LetterIncomingID: letterID,
|
|
DepartmentID: departmentID,
|
|
}
|
|
|
|
resp, err := h.svc.GetDepartmentDispositionStatus(c.Request.Context(), req)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) UpdateDispositionStatus(c *gin.Context) {
|
|
letterID, ok := h.parseUUID(c, "letter_id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
var req contract.UpdateDispositionStatusRequest
|
|
if !h.bindJSON(c, &req) {
|
|
return
|
|
}
|
|
|
|
req.LetterIncomingID = letterID
|
|
|
|
resp, err := h.svc.UpdateDispositionStatus(c.Request.Context(), &req)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) GetLetterCTA(c *gin.Context) {
|
|
letterID, ok := h.parseUUID(c, "letter_id")
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.GetLetterCTA(c.Request.Context(), letterID)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *LetterHandler) BulkArchiveIncomingLetters(c *gin.Context) {
|
|
var req contract.BulkArchiveLettersRequest
|
|
if !h.bindJSON(c, &req) {
|
|
return
|
|
}
|
|
|
|
if len(req.LetterIDs) == 0 {
|
|
h.respondError(c, http.StatusBadRequest, "at least one letter ID is required")
|
|
return
|
|
}
|
|
|
|
resp, err := h.svc.BulkArchiveIncomingLetters(c.Request.Context(), req.LetterIDs)
|
|
if err != nil {
|
|
h.handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
h.respondSuccess(c, http.StatusOK, resp)
|
|
}
|