Init All Docs

This commit is contained in:
Aditya Siregar
2025-09-08 12:24:37 +07:00
parent aa662a321f
commit 2319019eb2
68 changed files with 5417 additions and 437 deletions
+69 -3
View File
@@ -12,10 +12,13 @@ import (
type DispositionRouteService interface {
Create(ctx context.Context, req *contract.CreateDispositionRouteRequest) (*contract.DispositionRouteResponse, error)
CreateOrUpdate(ctx context.Context, req *contract.CreateDispositionRouteRequest) (*contract.BulkCreateDispositionRouteResponse, error)
Update(ctx context.Context, id uuid.UUID, req *contract.UpdateDispositionRouteRequest) (*contract.DispositionRouteResponse, error)
Get(ctx context.Context, id uuid.UUID) (*contract.DispositionRouteResponse, error)
ListByFromDept(ctx context.Context, from uuid.UUID) (*contract.ListDispositionRoutesResponse, error)
SetActive(ctx context.Context, id uuid.UUID, active bool) error
ListGrouped(ctx context.Context) (*contract.ListDispositionRoutesGroupedResponse, error)
ListAll(ctx context.Context) (*contract.ListDispositionRoutesDetailedResponse, error)
}
type DispositionRouteHandler struct{ svc DispositionRouteService }
@@ -24,18 +27,61 @@ func NewDispositionRouteHandler(svc DispositionRouteService) *DispositionRouteHa
return &DispositionRouteHandler{svc: svc}
}
// Create handles both single and bulk route creation with upsert logic
func (h *DispositionRouteHandler) Create(c *gin.Context) {
var req contract.CreateDispositionRouteRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, &contract.ErrorResponse{Error: "invalid body", Code: 400})
c.JSON(400, &contract.ErrorResponse{Error: "invalid body: " + err.Error(), Code: 400})
return
}
resp, err := h.svc.Create(c.Request.Context(), &req)
// Validate request
if len(req.ToDepartmentIDs) == 0 {
c.JSON(400, &contract.ErrorResponse{Error: "to_department_ids cannot be empty", Code: 400})
return
}
// If single route, use Create for backward compatibility
if len(req.ToDepartmentIDs) == 1 {
resp, err := h.svc.Create(c.Request.Context(), &req)
if err != nil {
c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
return
}
c.JSON(201, contract.BuildSuccessResponse(resp))
return
}
// For multiple routes, use bulk create/update
bulkResp, err := h.svc.CreateOrUpdate(c.Request.Context(), &req)
if err != nil {
c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
return
}
c.JSON(201, contract.BuildSuccessResponse(resp))
c.JSON(201, contract.BuildSuccessResponse(bulkResp))
}
// BulkCreateOrUpdate explicitly handles bulk create/update operations
func (h *DispositionRouteHandler) BulkCreateOrUpdate(c *gin.Context) {
var req contract.CreateDispositionRouteRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, &contract.ErrorResponse{Error: "invalid body: " + err.Error(), Code: 400})
return
}
// Validate request
if len(req.ToDepartmentIDs) == 0 {
c.JSON(400, &contract.ErrorResponse{Error: "to_department_ids cannot be empty", Code: 400})
return
}
resp, err := h.svc.CreateOrUpdate(c.Request.Context(), &req)
if err != nil {
c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
return
}
c.JSON(200, contract.BuildSuccessResponse(resp))
}
func (h *DispositionRouteHandler) Update(c *gin.Context) {
@@ -96,3 +142,23 @@ func (h *DispositionRouteHandler) SetActive(c *gin.Context) {
}
c.JSON(200, &contract.SuccessResponse{Message: "updated"})
}
// ListGrouped returns all disposition routes grouped by from_department_id
func (h *DispositionRouteHandler) ListGrouped(c *gin.Context) {
resp, err := h.svc.ListGrouped(c.Request.Context())
if err != nil {
c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
return
}
c.JSON(200, contract.BuildSuccessResponse(resp))
}
// ListAll returns all disposition routes with department details
func (h *DispositionRouteHandler) ListAll(c *gin.Context) {
resp, err := h.svc.ListAll(c.Request.Context())
if err != nil {
c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
return
}
c.JSON(200, contract.BuildSuccessResponse(resp))
}
+169
View File
@@ -5,6 +5,7 @@ import (
"eslogad-be/internal/appcontext"
"net/http"
"strconv"
"strings"
"eslogad-be/internal/contract"
@@ -16,14 +17,23 @@ 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 {
@@ -119,6 +129,46 @@ func (h *LetterHandler) ListIncomingLetters(c *gin.Context) {
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
@@ -145,10 +195,50 @@ func (h *LetterHandler) parseListRequest(c *gin.Context) *contract.ListIncomingL
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
@@ -268,3 +358,82 @@ func (h *LetterHandler) UpdateDiscussion(c *gin.Context) {
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)
}
@@ -39,6 +39,7 @@ type LetterOutgoingService interface {
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)
BulkArchiveOutgoingLetters(ctx context.Context, letterIDs []uuid.UUID) (*contract.BulkArchiveLettersResponse, error)
}
type LetterOutgoingHandler struct {
@@ -479,3 +480,24 @@ func (h *LetterOutgoingHandler) GetApprovalTimeline(c *gin.Context) {
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}
func (h *LetterOutgoingHandler) BulkArchiveOutgoingLetters(c *gin.Context) {
var req contract.BulkArchiveLettersRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid request body", Code: http.StatusBadRequest})
return
}
if len(req.LetterIDs) == 0 {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "at least one letter ID is required", Code: http.StatusBadRequest})
return
}
resp, err := h.svc.BulkArchiveOutgoingLetters(c.Request.Context(), req.LetterIDs)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}
-190
View File
@@ -1,190 +0,0 @@
package handler
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"eslogad-be/internal/contract"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// MockMasterService is a mock implementation of MasterService
type MockMasterService struct {
mock.Mock
}
func (m *MockMasterService) CreateLabel(ctx context.Context, req *contract.CreateLabelRequest) (*contract.LabelResponse, error) {
args := m.Called(ctx, req)
return args.Get(0).(*contract.LabelResponse), args.Error(1)
}
func (m *MockMasterService) UpdateLabel(ctx context.Context, id uuid.UUID, req *contract.UpdateLabelRequest) (*contract.LabelResponse, error) {
args := m.Called(ctx, id, req)
return args.Get(0).(*contract.LabelResponse), args.Error(1)
}
func (m *MockMasterService) DeleteLabel(ctx context.Context, id uuid.UUID) error {
args := m.Called(ctx, id)
return args.Error(0)
}
func (m *MockMasterService) ListLabels(ctx context.Context) (*contract.ListLabelsResponse, error) {
args := m.Called(ctx)
return args.Get(0).(*contract.ListLabelsResponse), args.Error(1)
}
func (m *MockMasterService) CreatePriority(ctx context.Context, req *contract.CreatePriorityRequest) (*contract.PriorityResponse, error) {
args := m.Called(ctx, req)
return args.Get(0).(*contract.PriorityResponse), args.Error(1)
}
func (m *MockMasterService) UpdatePriority(ctx context.Context, id uuid.UUID, req *contract.UpdatePriorityRequest) (*contract.PriorityResponse, error) {
args := m.Called(ctx, id, req)
return args.Get(0).(*contract.PriorityResponse), args.Error(1)
}
func (m *MockMasterService) DeletePriority(ctx context.Context, id uuid.UUID) error {
args := m.Called(ctx, id)
return args.Error(0)
}
func (m *MockMasterService) ListPriorities(ctx context.Context) (*contract.ListPrioritiesResponse, error) {
args := m.Called(ctx)
return args.Get(0).(*contract.ListPrioritiesResponse), args.Error(1)
}
func (m *MockMasterService) CreateInstitution(ctx context.Context, req *contract.CreateInstitutionRequest) (*contract.InstitutionResponse, error) {
args := m.Called(ctx, req)
return args.Get(0).(*contract.InstitutionResponse), args.Error(1)
}
func (m *MockMasterService) UpdateInstitution(ctx context.Context, id uuid.UUID, req *contract.UpdateInstitutionRequest) (*contract.InstitutionResponse, error) {
args := m.Called(ctx, id, req)
return args.Get(0).(*contract.InstitutionResponse), args.Error(1)
}
func (m *MockMasterService) DeleteInstitution(ctx context.Context, id uuid.UUID) error {
args := m.Called(ctx, id)
return args.Error(0)
}
func (m *MockMasterService) ListInstitutions(ctx context.Context, req *contract.ListInstitutionsRequest) (*contract.ListInstitutionsResponse, error) {
args := m.Called(ctx, req)
return args.Get(0).(*contract.ListInstitutionsResponse), args.Error(1)
}
func (m *MockMasterService) CreateDispositionAction(ctx context.Context, req *contract.CreateDispositionActionRequest) (*contract.DispositionActionResponse, error) {
args := m.Called(ctx, req)
return args.Get(0).(*contract.DispositionActionResponse), args.Error(1)
}
func (m *MockMasterService) UpdateDispositionAction(ctx context.Context, id uuid.UUID, req *contract.UpdateDispositionActionRequest) (*contract.DispositionActionResponse, error) {
args := m.Called(ctx, id, req)
return args.Get(0).(*contract.DispositionActionResponse), args.Error(1)
}
func (m *MockMasterService) DeleteDispositionAction(ctx context.Context, id uuid.UUID) error {
args := m.Called(ctx, id)
return args.Error(0)
}
func (m *MockMasterService) ListDispositionActions(ctx context.Context) (*contract.ListDispositionActionsResponse, error) {
args := m.Called(ctx)
return args.Get(0).(*contract.ListDispositionActionsResponse), args.Error(1)
}
func TestMasterHandler_ListInstitutions_WithSearch(t *testing.T) {
// Setup
gin.SetMode(gin.TestMode)
mockService := new(MockMasterService)
handler := NewMasterHandler(mockService)
// Test data
searchTerm := "university"
expectedResponse := &contract.ListInstitutionsResponse{
Institutions: []contract.InstitutionResponse{
{
ID: "123",
Name: "Test University",
Type: "university",
},
},
}
// Setup mock expectations
mockService.On("ListInstitutions", mock.Anything, &contract.ListInstitutionsRequest{
Search: &searchTerm,
}).Return(expectedResponse, nil)
// Create request
req, _ := http.NewRequest("GET", "/institutions?search="+searchTerm, nil)
w := httptest.NewRecorder()
// Create gin context
c, _ := gin.CreateTestContext(w)
c.Request = req
// Execute
handler.ListInstitutions(c)
// Assertions
assert.Equal(t, http.StatusOK, w.Code)
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
// Verify mock was called correctly
mockService.AssertExpectations(t)
}
func TestMasterHandler_ListInstitutions_WithoutSearch(t *testing.T) {
// Setup
gin.SetMode(gin.TestMode)
mockService := new(MockMasterService)
handler := NewMasterHandler(mockService)
// Test data
expectedResponse := &contract.ListInstitutionsResponse{
Institutions: []contract.InstitutionResponse{
{
ID: "123",
Name: "Test Institution",
Type: "company",
},
},
}
// Setup mock expectations
mockService.On("ListInstitutions", mock.Anything, &contract.ListInstitutionsRequest{
Search: nil,
}).Return(expectedResponse, nil)
// Create request
req, _ := http.NewRequest("GET", "/institutions", nil)
w := httptest.NewRecorder()
// Create gin context
c, _ := gin.CreateTestContext(w)
c.Request = req
// Execute
handler.ListInstitutions(c)
// Assertions
assert.Equal(t, http.StatusOK, w.Code)
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
// Verify mock was called correctly
mockService.AssertExpectations(t)
}
+230
View File
@@ -0,0 +1,230 @@
package handler
import (
"net/http"
"eslogad-be/internal/contract"
"eslogad-be/internal/service"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type NotificationHandler struct {
notificationService service.NotificationService
}
func NewNotificationHandler(notificationService service.NotificationService) *NotificationHandler {
return &NotificationHandler{
notificationService: notificationService,
}
}
// TriggerNotification handles single notification trigger
func (h *NotificationHandler) TriggerNotification(c *gin.Context) {
var req contract.TriggerNotificationRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
resp, err := h.notificationService.TriggerNotification(c.Request.Context(), &req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if !resp.Success {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": resp.Message,
})
return
}
c.JSON(http.StatusOK, resp)
}
// BulkTriggerNotification handles bulk notification trigger
func (h *NotificationHandler) BulkTriggerNotification(c *gin.Context) {
var req contract.BulkTriggerNotificationRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
resp, err := h.notificationService.BulkTriggerNotification(c.Request.Context(), &req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, resp)
}
// GetSubscriber retrieves subscriber information
func (h *NotificationHandler) GetSubscriber(c *gin.Context) {
userIDStr := c.Param("userId")
userID, err := uuid.Parse(userIDStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user ID"})
return
}
resp, err := h.notificationService.GetSubscriber(c.Request.Context(), userID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, resp)
}
// UpdateSubscriberChannel updates subscriber channel credentials
func (h *NotificationHandler) UpdateSubscriberChannel(c *gin.Context) {
var req contract.UpdateSubscriberChannelRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
resp, err := h.notificationService.UpdateSubscriberChannel(c.Request.Context(), &req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if !resp.Success {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": resp.Message,
})
return
}
c.JSON(http.StatusOK, resp)
}
// TriggerNotificationForCurrentUser triggers notification for the authenticated user
func (h *NotificationHandler) TriggerNotificationForCurrentUser(c *gin.Context) {
// Get current user ID from context (set by auth middleware)
userIDInterface, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
return
}
userID, ok := userIDInterface.(uuid.UUID)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user ID in context"})
return
}
var req struct {
TemplateID string `json:"template_id" validate:"required"`
TemplateData map[string]interface{} `json:"template_data,omitempty"`
Overrides *contract.NotificationOverrides `json:"overrides,omitempty"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Create trigger request with current user ID
triggerReq := &contract.TriggerNotificationRequest{
UserID: userID,
TemplateID: req.TemplateID,
TemplateData: req.TemplateData,
Overrides: req.Overrides,
}
resp, err := h.notificationService.TriggerNotification(c.Request.Context(), triggerReq)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if !resp.Success {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": resp.Message,
})
return
}
c.JSON(http.StatusOK, resp)
}
// GetCurrentUserSubscriber retrieves subscriber information for the authenticated user
func (h *NotificationHandler) GetCurrentUserSubscriber(c *gin.Context) {
// Get current user ID from context (set by auth middleware)
userIDInterface, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
return
}
userID, ok := userIDInterface.(uuid.UUID)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user ID in context"})
return
}
resp, err := h.notificationService.GetSubscriber(c.Request.Context(), userID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, resp)
}
// UpdateCurrentUserSubscriberChannel updates channel credentials for the authenticated user
func (h *NotificationHandler) UpdateCurrentUserSubscriberChannel(c *gin.Context) {
// Get current user ID from context (set by auth middleware)
userIDInterface, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
return
}
userID, ok := userIDInterface.(uuid.UUID)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user ID in context"})
return
}
var req struct {
Channel string `json:"channel" validate:"required,oneof=email sms push chat in_app"`
Credentials map[string]interface{} `json:"credentials" validate:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Create update request with current user ID
updateReq := &contract.UpdateSubscriberChannelRequest{
UserID: userID,
Channel: req.Channel,
Credentials: req.Credentials,
}
resp, err := h.notificationService.UpdateSubscriberChannel(c.Request.Context(), updateReq)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if !resp.Success {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": resp.Message,
})
return
}
c.JSON(http.StatusOK, resp)
}