Add letter and user id

This commit is contained in:
Aditya Siregar
2025-08-19 00:31:04 +07:00
parent 1964fe50de
commit f41daa63da
16 changed files with 3188 additions and 21 deletions
@@ -0,0 +1,344 @@
package handler
import (
"context"
"net/http"
"strconv"
"eslogad-be/internal/contract"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type ApprovalFlowService interface {
CreateApprovalFlow(ctx context.Context, req *contract.ApprovalFlowRequest) (*contract.ApprovalFlowResponse, error)
GetApprovalFlow(ctx context.Context, id uuid.UUID) (*contract.ApprovalFlowResponse, error)
GetApprovalFlowByDepartment(ctx context.Context, departmentID uuid.UUID) (*contract.ApprovalFlowResponse, error)
UpdateApprovalFlow(ctx context.Context, id uuid.UUID, req *contract.ApprovalFlowRequest) (*contract.ApprovalFlowResponse, error)
DeleteApprovalFlow(ctx context.Context, id uuid.UUID) error
ListApprovalFlows(ctx context.Context, req *contract.ListApprovalFlowsRequest) (*contract.ListApprovalFlowsResponse, error)
}
type AdminApprovalFlowHandler struct {
svc ApprovalFlowService
}
func NewAdminApprovalFlowHandler(svc ApprovalFlowService) *AdminApprovalFlowHandler {
return &AdminApprovalFlowHandler{svc: svc}
}
func (h *AdminApprovalFlowHandler) CreateApprovalFlow(c *gin.Context) {
var req contract.ApprovalFlowRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
// Validate that at least one step is provided
if len(req.Steps) == 0 {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "at least one approval step is required", Code: http.StatusBadRequest})
return
}
// Validate each step has either a role or user as approver
for i, step := range req.Steps {
if step.ApproverRoleID == nil && step.ApproverUserID == nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
Error: "step " + strconv.Itoa(i+1) + " must have either approver_role_id or approver_user_id",
Code: http.StatusBadRequest,
})
return
}
if step.ApproverRoleID != nil && step.ApproverUserID != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
Error: "step " + strconv.Itoa(i+1) + " cannot have both approver_role_id and approver_user_id",
Code: http.StatusBadRequest,
})
return
}
}
resp, err := h.svc.CreateApprovalFlow(c.Request.Context(), &req)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusCreated, contract.BuildSuccessResponse(resp))
}
func (h *AdminApprovalFlowHandler) GetApprovalFlow(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.GetApprovalFlow(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}
func (h *AdminApprovalFlowHandler) GetApprovalFlowByDepartment(c *gin.Context) {
departmentID, err := uuid.Parse(c.Param("department_id"))
if err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid department_id", Code: http.StatusBadRequest})
return
}
resp, err := h.svc.GetApprovalFlowByDepartment(c.Request.Context(), departmentID)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}
func (h *AdminApprovalFlowHandler) UpdateApprovalFlow(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
}
var req contract.ApprovalFlowRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
// Validate that at least one step is provided
if len(req.Steps) == 0 {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "at least one approval step is required", Code: http.StatusBadRequest})
return
}
// Validate each step has either a role or user as approver
for i, step := range req.Steps {
if step.ApproverRoleID == nil && step.ApproverUserID == nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
Error: "step " + strconv.Itoa(i+1) + " must have either approver_role_id or approver_user_id",
Code: http.StatusBadRequest,
})
return
}
if step.ApproverRoleID != nil && step.ApproverUserID != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
Error: "step " + strconv.Itoa(i+1) + " cannot have both approver_role_id and approver_user_id",
Code: http.StatusBadRequest,
})
return
}
}
resp, err := h.svc.UpdateApprovalFlow(c.Request.Context(), id, &req)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}
func (h *AdminApprovalFlowHandler) DeleteApprovalFlow(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
}
if err := h.svc.DeleteApprovalFlow(c.Request.Context(), id); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "approval flow deleted"})
}
func (h *AdminApprovalFlowHandler) ListApprovalFlows(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
offset := (page - 1) * limit
departmentIDStr := c.Query("department_id")
isActiveStr := c.Query("is_active")
var departmentID *uuid.UUID
var isActive *bool
if departmentIDStr != "" {
if id, err := uuid.Parse(departmentIDStr); err == nil {
departmentID = &id
}
}
if isActiveStr != "" {
if isActiveStr == "true" {
active := true
isActive = &active
} else if isActiveStr == "false" {
active := false
isActive = &active
}
}
req := &contract.ListApprovalFlowsRequest{
Limit: limit,
Offset: offset,
DepartmentID: departmentID,
IsActive: isActive,
}
resp, err := h.svc.ListApprovalFlows(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(resp))
}
func (h *AdminApprovalFlowHandler) ActivateApprovalFlow(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
}
// Get the current flow
flow, err := h.svc.GetApprovalFlow(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
// Update only the IsActive field
req := &contract.ApprovalFlowRequest{
DepartmentID: flow.DepartmentID,
Name: flow.Name,
Description: flow.Description,
IsActive: true,
Steps: make([]contract.ApprovalFlowStepRequest, len(flow.Steps)),
}
// Copy existing steps
for i, step := range flow.Steps {
req.Steps[i] = contract.ApprovalFlowStepRequest{
StepOrder: step.StepOrder,
ParallelGroup: step.ParallelGroup,
ApproverRoleID: step.ApproverRoleID,
ApproverUserID: step.ApproverUserID,
Required: step.Required,
}
}
resp, err := h.svc.UpdateApprovalFlow(c.Request.Context(), id, req)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}
func (h *AdminApprovalFlowHandler) DeactivateApprovalFlow(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
}
// Get the current flow
flow, err := h.svc.GetApprovalFlow(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
// Update only the IsActive field
req := &contract.ApprovalFlowRequest{
DepartmentID: flow.DepartmentID,
Name: flow.Name,
Description: flow.Description,
IsActive: false,
Steps: make([]contract.ApprovalFlowStepRequest, len(flow.Steps)),
}
// Copy existing steps
for i, step := range flow.Steps {
req.Steps[i] = contract.ApprovalFlowStepRequest{
StepOrder: step.StepOrder,
ParallelGroup: step.ParallelGroup,
ApproverRoleID: step.ApproverRoleID,
ApproverUserID: step.ApproverUserID,
Required: step.Required,
}
}
resp, err := h.svc.UpdateApprovalFlow(c.Request.Context(), id, req)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}
func (h *AdminApprovalFlowHandler) CloneApprovalFlow(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
}
var cloneReq struct {
DepartmentID uuid.UUID `json:"department_id" validate:"required"`
Name string `json:"name" validate:"required"`
}
if err := c.ShouldBindJSON(&cloneReq); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
// Get the source flow
sourceFlow, err := h.svc.GetApprovalFlow(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
// Create new flow request with cloned data
req := &contract.ApprovalFlowRequest{
DepartmentID: cloneReq.DepartmentID,
Name: cloneReq.Name,
Description: sourceFlow.Description,
IsActive: false, // New cloned flow starts as inactive
Steps: make([]contract.ApprovalFlowStepRequest, len(sourceFlow.Steps)),
}
// Copy steps from source flow
for i, step := range sourceFlow.Steps {
req.Steps[i] = contract.ApprovalFlowStepRequest{
StepOrder: step.StepOrder,
ParallelGroup: step.ParallelGroup,
ApproverRoleID: step.ApproverRoleID,
ApproverUserID: step.ApproverUserID,
Required: step.Required,
}
}
resp, err := h.svc.CreateApprovalFlow(c.Request.Context(), req)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusCreated, contract.BuildSuccessResponse(resp))
}
+420
View File
@@ -0,0 +1,420 @@
package handler
import (
"context"
"net/http"
"strconv"
"eslogad-be/internal/contract"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type LetterOutgoingService interface {
CreateOutgoingLetter(ctx context.Context, req *contract.CreateOutgoingLetterRequest) (*contract.OutgoingLetterResponse, error)
GetOutgoingLetterByID(ctx context.Context, id uuid.UUID) (*contract.OutgoingLetterResponse, error)
ListOutgoingLetters(ctx context.Context, req *contract.ListOutgoingLettersRequest) (*contract.ListOutgoingLettersResponse, error)
UpdateOutgoingLetter(ctx context.Context, id uuid.UUID, req *contract.UpdateOutgoingLetterRequest) (*contract.OutgoingLetterResponse, error)
DeleteOutgoingLetter(ctx context.Context, id uuid.UUID) error
SubmitForApproval(ctx context.Context, letterID uuid.UUID) error
ApproveOutgoingLetter(ctx context.Context, letterID uuid.UUID, req *contract.ApproveLetterRequest) error
RejectOutgoingLetter(ctx context.Context, letterID uuid.UUID, req *contract.RejectLetterRequest) error
SendOutgoingLetter(ctx context.Context, letterID uuid.UUID) error
ArchiveOutgoingLetter(ctx context.Context, letterID uuid.UUID) error
AddRecipients(ctx context.Context, letterID uuid.UUID, req *contract.AddRecipientsRequest) error
UpdateRecipient(ctx context.Context, letterID uuid.UUID, recipientID uuid.UUID, req *contract.UpdateRecipientRequest) error
RemoveRecipient(ctx context.Context, letterID uuid.UUID, recipientID uuid.UUID) error
AddAttachments(ctx context.Context, letterID uuid.UUID, req *contract.AddAttachmentsRequest) error
RemoveAttachment(ctx context.Context, letterID uuid.UUID, attachmentID uuid.UUID) error
CreateDiscussion(ctx context.Context, letterID uuid.UUID, req *contract.CreateDiscussionRequest) (*contract.DiscussionResponse, error)
UpdateDiscussion(ctx context.Context, discussionID uuid.UUID, req *contract.UpdateDiscussionRequest) error
DeleteDiscussion(ctx context.Context, discussionID uuid.UUID) error
}
type LetterOutgoingHandler struct {
svc LetterOutgoingService
}
func NewLetterOutgoingHandler(svc LetterOutgoingService) *LetterOutgoingHandler {
return &LetterOutgoingHandler{svc: svc}
}
func (h *LetterOutgoingHandler) CreateOutgoingLetter(c *gin.Context) {
var req contract.CreateOutgoingLetterRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
resp, err := h.svc.CreateOutgoingLetter(c.Request.Context(), &req)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusCreated, contract.BuildSuccessResponse(resp))
}
func (h *LetterOutgoingHandler) GetOutgoingLetter(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.GetOutgoingLetterByID(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}
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
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
}
}
req := &contract.ListOutgoingLettersRequest{
Limit: limit,
Offset: offset,
Status: statusPtr,
Query: queryPtr,
CreatedBy: createdByPtr,
ReceiverInstitutionID: receiverInstitutionPtr,
}
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
}
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}
func (h *LetterOutgoingHandler) UpdateOutgoingLetter(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
}
var req contract.UpdateOutgoingLetterRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
resp, err := h.svc.UpdateOutgoingLetter(c.Request.Context(), id, &req)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}
func (h *LetterOutgoingHandler) DeleteOutgoingLetter(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
}
if err := h.svc.DeleteOutgoingLetter(c.Request.Context(), id); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "deleted"})
}
func (h *LetterOutgoingHandler) SubmitForApproval(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
}
if err := h.svc.SubmitForApproval(c.Request.Context(), id); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "submitted for approval"})
}
func (h *LetterOutgoingHandler) ApproveOutgoingLetter(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
}
var req contract.ApproveLetterRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
if err := h.svc.ApproveOutgoingLetter(c.Request.Context(), id, &req); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "approved"})
}
func (h *LetterOutgoingHandler) RejectOutgoingLetter(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
}
var req contract.RejectLetterRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
if err := h.svc.RejectOutgoingLetter(c.Request.Context(), id, &req); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "rejected"})
}
func (h *LetterOutgoingHandler) SendOutgoingLetter(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
}
if err := h.svc.SendOutgoingLetter(c.Request.Context(), id); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "sent"})
}
func (h *LetterOutgoingHandler) ArchiveOutgoingLetter(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
}
if err := h.svc.ArchiveOutgoingLetter(c.Request.Context(), id); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "archived"})
}
func (h *LetterOutgoingHandler) AddRecipients(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
}
var req contract.AddRecipientsRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
if err := h.svc.AddRecipients(c.Request.Context(), id, &req); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "recipients added"})
}
func (h *LetterOutgoingHandler) UpdateRecipient(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid letter id", Code: http.StatusBadRequest})
return
}
recipientID, err := uuid.Parse(c.Param("recipient_id"))
if err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid recipient id", Code: http.StatusBadRequest})
return
}
var req contract.UpdateRecipientRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
if err := h.svc.UpdateRecipient(c.Request.Context(), id, recipientID, &req); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "recipient updated"})
}
func (h *LetterOutgoingHandler) RemoveRecipient(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid letter id", Code: http.StatusBadRequest})
return
}
recipientID, err := uuid.Parse(c.Param("recipient_id"))
if err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid recipient id", Code: http.StatusBadRequest})
return
}
if err := h.svc.RemoveRecipient(c.Request.Context(), id, recipientID); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "recipient removed"})
}
func (h *LetterOutgoingHandler) AddAttachments(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
}
var req contract.AddAttachmentsRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
if err := h.svc.AddAttachments(c.Request.Context(), id, &req); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "attachments added"})
}
func (h *LetterOutgoingHandler) RemoveAttachment(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid letter id", Code: http.StatusBadRequest})
return
}
attachmentID, err := uuid.Parse(c.Param("attachment_id"))
if err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid attachment id", Code: http.StatusBadRequest})
return
}
if err := h.svc.RemoveAttachment(c.Request.Context(), id, attachmentID); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "attachment removed"})
}
func (h *LetterOutgoingHandler) CreateDiscussion(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid letter id", Code: http.StatusBadRequest})
return
}
var req contract.CreateDiscussionRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
resp, err := h.svc.CreateDiscussion(c.Request.Context(), id, &req)
if err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusCreated, contract.BuildSuccessResponse(resp))
}
func (h *LetterOutgoingHandler) UpdateDiscussion(c *gin.Context) {
discussionID, err := uuid.Parse(c.Param("discussion_id"))
if err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid discussion id", Code: http.StatusBadRequest})
return
}
var req contract.UpdateDiscussionRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
return
}
if err := h.svc.UpdateDiscussion(c.Request.Context(), discussionID, &req); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "discussion updated"})
}
func (h *LetterOutgoingHandler) DeleteDiscussion(c *gin.Context) {
discussionID, err := uuid.Parse(c.Param("discussion_id"))
if err != nil {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid discussion id", Code: http.StatusBadRequest})
return
}
if err := h.svc.DeleteDiscussion(c.Request.Context(), discussionID); err != nil {
c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
return
}
c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "discussion deleted"})
}
+28 -1
View File
@@ -296,6 +296,33 @@ func (h *UserHandler) ListTitles(c *gin.Context) {
c.JSON(http.StatusOK, titles)
}
func (h *UserHandler) GetUserProfile(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := uuid.Parse(userIDStr)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::GetUserProfile -> Invalid user ID")
h.sendValidationErrorResponse(c, "Invalid user ID", constants.MalformedFieldErrorCode)
return
}
validationError, validationErrorCode := h.userValidator.ValidateUserID(userID)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::GetUserProfile -> user ID validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
profile, err := h.userService.GetProfile(c.Request.Context(), userID)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::GetUserProfile -> Failed to get user profile from service")
h.sendErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
logger.FromContext(c).Infof("UserHandler::GetUserProfile -> Successfully retrieved user profile for user ID = %s", userID)
c.JSON(http.StatusOK, contract.BuildSuccessResponse(profile))
}
func (h *UserHandler) GetActiveUsersForMention(c *gin.Context) {
search := c.Query("search")
limitStr := c.DefaultQuery("limit", "50")
@@ -307,7 +334,7 @@ func (h *UserHandler) GetActiveUsersForMention(c *gin.Context) {
if limit > 100 {
limit = 100
}
var searchPtr *string
if search != "" {
searchPtr = &search