Update
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"eslogad-be/internal/contract"
|
||||
"eslogad-be/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AnalyticsHandler struct {
|
||||
analyticsService service.AnalyticsService
|
||||
}
|
||||
|
||||
func NewAnalyticsHandler(analyticsService service.AnalyticsService) *AnalyticsHandler {
|
||||
return &AnalyticsHandler{
|
||||
analyticsService: analyticsService,
|
||||
}
|
||||
}
|
||||
|
||||
// GetDashboard handles GET /api/v1/analytics/dashboard
|
||||
func (h *AnalyticsHandler) GetDashboard(c *gin.Context) {
|
||||
var req contract.AnalyticsDashboardRequest
|
||||
|
||||
// Bind query parameters
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
||||
Error: "Invalid query parameters",
|
||||
Code: http.StatusBadRequest,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get analytics dashboard data
|
||||
response, err := h.analyticsService.GetDashboard(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
||||
Error: err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(response))
|
||||
}
|
||||
|
||||
// GetLetterVolume handles GET /api/v1/analytics/volume
|
||||
func (h *AnalyticsHandler) GetLetterVolume(c *gin.Context) {
|
||||
response, err := h.analyticsService.GetLetterVolume(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
||||
Error: err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(response))
|
||||
}
|
||||
|
||||
// GetStatusDistribution handles GET /api/v1/analytics/status-distribution
|
||||
func (h *AnalyticsHandler) GetStatusDistribution(c *gin.Context) {
|
||||
var req contract.AnalyticsDashboardRequest
|
||||
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
||||
Error: "Invalid query parameters",
|
||||
Code: http.StatusBadRequest,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get full dashboard and extract status distribution
|
||||
response, err := h.analyticsService.GetDashboard(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
||||
Error: err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(map[string]interface{}{
|
||||
"status_distribution": response.StatusDistribution,
|
||||
}))
|
||||
}
|
||||
|
||||
// GetPriorityDistribution handles GET /api/v1/analytics/priority-distribution
|
||||
func (h *AnalyticsHandler) GetPriorityDistribution(c *gin.Context) {
|
||||
var req contract.AnalyticsDashboardRequest
|
||||
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
||||
Error: "Invalid query parameters",
|
||||
Code: http.StatusBadRequest,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get full dashboard and extract priority distribution
|
||||
response, err := h.analyticsService.GetDashboard(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
||||
Error: err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(map[string]interface{}{
|
||||
"priority_distribution": response.PriorityDistribution,
|
||||
}))
|
||||
}
|
||||
|
||||
// GetDepartmentStats handles GET /api/v1/analytics/department-stats
|
||||
func (h *AnalyticsHandler) GetDepartmentStats(c *gin.Context) {
|
||||
var req contract.AnalyticsDashboardRequest
|
||||
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
||||
Error: "Invalid query parameters",
|
||||
Code: http.StatusBadRequest,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get full dashboard and extract department stats
|
||||
response, err := h.analyticsService.GetDashboard(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
||||
Error: err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(map[string]interface{}{
|
||||
"department_stats": response.DepartmentStats,
|
||||
}))
|
||||
}
|
||||
|
||||
// GetMonthlyTrend handles GET /api/v1/analytics/monthly-trend
|
||||
func (h *AnalyticsHandler) GetMonthlyTrend(c *gin.Context) {
|
||||
var req contract.AnalyticsDashboardRequest
|
||||
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
||||
Error: "Invalid query parameters",
|
||||
Code: http.StatusBadRequest,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get full dashboard and extract monthly trend
|
||||
response, err := h.analyticsService.GetDashboard(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
||||
Error: err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(map[string]interface{}{
|
||||
"monthly_trend": response.MonthlyTrend,
|
||||
}))
|
||||
}
|
||||
|
||||
// GetApprovalMetrics handles GET /api/v1/analytics/approval-metrics
|
||||
func (h *AnalyticsHandler) GetApprovalMetrics(c *gin.Context) {
|
||||
var req contract.AnalyticsDashboardRequest
|
||||
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
|
||||
Error: "Invalid query parameters",
|
||||
Code: http.StatusBadRequest,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get full dashboard and extract approval metrics
|
||||
response, err := h.analyticsService.GetDashboard(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{
|
||||
Error: err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(map[string]interface{}{
|
||||
"approval_metrics": response.ApprovalMetrics,
|
||||
}))
|
||||
}
|
||||
@@ -3,10 +3,8 @@ package handler
|
||||
import (
|
||||
"context"
|
||||
"eslogad-be/internal/appcontext"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"eslogad-be/internal/contract"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
@@ -38,7 +36,9 @@ type LetterOutgoingService interface {
|
||||
DeleteDiscussion(ctx context.Context, discussionID uuid.UUID) error
|
||||
|
||||
GetLetterApprovalInfo(ctx context.Context, letterID uuid.UUID) (*contract.LetterApprovalInfoResponse, error)
|
||||
GetLetterApprovals(ctx context.Context, letterID uuid.UUID) (*contract.GetLetterApprovalsResponse, error)
|
||||
GetApprovalDiscussions(ctx context.Context, letterID uuid.UUID) (*contract.OutgoingLetterApprovalDiscussionsResponse, error)
|
||||
GetApprovalTimeline(ctx context.Context, letterID uuid.UUID) (*contract.ApprovalTimelineResponse, error)
|
||||
}
|
||||
|
||||
type LetterOutgoingHandler struct {
|
||||
@@ -84,47 +84,22 @@ func (h *LetterOutgoingHandler) GetOutgoingLetter(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (h *LetterOutgoingHandler) ListOutgoingLetters(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
|
||||
offset := (page - 1) * limit
|
||||
var req contract.ListOutgoingLettersRequest
|
||||
|
||||
status := c.Query("status")
|
||||
query := c.Query("q")
|
||||
createdByStr := c.Query("created_by")
|
||||
receiverInstitutionStr := c.Query("receiver_institution_id")
|
||||
|
||||
var statusPtr *string
|
||||
var queryPtr *string
|
||||
var createdByPtr *uuid.UUID
|
||||
var receiverInstitutionPtr *uuid.UUID
|
||||
|
||||
if status != "" {
|
||||
statusPtr = &status
|
||||
}
|
||||
if query != "" {
|
||||
queryPtr = &query
|
||||
}
|
||||
if createdByStr != "" {
|
||||
if createdBy, err := uuid.Parse(createdByStr); err == nil {
|
||||
createdByPtr = &createdBy
|
||||
}
|
||||
}
|
||||
if receiverInstitutionStr != "" {
|
||||
if receiverInstitution, err := uuid.Parse(receiverInstitutionStr); err == nil {
|
||||
receiverInstitutionPtr = &receiverInstitution
|
||||
}
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid query parameters", Code: http.StatusBadRequest})
|
||||
return
|
||||
}
|
||||
|
||||
req := &contract.ListOutgoingLettersRequest{
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
Status: statusPtr,
|
||||
Query: queryPtr,
|
||||
CreatedBy: createdByPtr,
|
||||
ReceiverInstitutionID: receiverInstitutionPtr,
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
|
||||
resp, err := h.svc.ListOutgoingLetters(c.Request.Context(), req)
|
||||
if req.Limit <= 0 {
|
||||
req.Limit = 10
|
||||
}
|
||||
|
||||
resp, err := h.svc.ListOutgoingLetters(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
|
||||
return
|
||||
@@ -203,7 +178,7 @@ func (h *LetterOutgoingHandler) ApproveOutgoingLetter(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "approved"})
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(&contract.SuccessResponse{Message: "approved"}))
|
||||
}
|
||||
|
||||
func (h *LetterOutgoingHandler) RejectOutgoingLetter(c *gin.Context) {
|
||||
@@ -224,7 +199,7 @@ func (h *LetterOutgoingHandler) RejectOutgoingLetter(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "rejected"})
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(&contract.SuccessResponse{Message: "rejected"}))
|
||||
}
|
||||
|
||||
func (h *LetterOutgoingHandler) SendOutgoingLetter(c *gin.Context) {
|
||||
@@ -442,6 +417,27 @@ func (h *LetterOutgoingHandler) GetLetterApprovalInfo(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
|
||||
}
|
||||
|
||||
// GetLetterApprovals returns all approvals and their status for a letter
|
||||
func (h *LetterOutgoingHandler) GetLetterApprovals(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: http.StatusBadRequest})
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.svc.GetLetterApprovals(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
c.JSON(http.StatusNotFound, &contract.ErrorResponse{Error: "letter not found", Code: http.StatusNotFound})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
|
||||
}
|
||||
|
||||
// GetApprovalDiscussions returns both approvals and discussions for an outgoing letter
|
||||
func (h *LetterOutgoingHandler) GetApprovalDiscussions(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
@@ -461,4 +457,25 @@ func (h *LetterOutgoingHandler) GetApprovalDiscussions(c *gin.Context) {
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
|
||||
}
|
||||
}
|
||||
|
||||
// GetApprovalTimeline returns a chronological timeline of approval and discussion events
|
||||
func (h *LetterOutgoingHandler) GetApprovalTimeline(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: http.StatusBadRequest})
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.svc.GetApprovalTimeline(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
c.JSON(http.StatusNotFound, &contract.ErrorResponse{Error: "letter not found", Code: http.StatusNotFound})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user