second commit
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
package v1
|
||||
|
||||
// NoteHandler provides HTTP handlers for contact notes.
|
||||
// Reference: Chatwoot app/controllers/api/v1/accounts/contacts/notes_controller.rb
|
||||
//
|
||||
// Routes:
|
||||
// GET /api/v1/accounts/:account_id/contacts/:contact_id/notes -> List
|
||||
// GET /api/v1/accounts/:account_id/contacts/:contact_id/notes/:id -> Show
|
||||
// POST /api/v1/accounts/:account_id/contacts/:contact_id/notes -> Create
|
||||
// PUT /api/v1/accounts/:account_id/contacts/:contact_id/notes/:id -> Update
|
||||
// DELETE /api/v1/accounts/:account_id/contacts/:contact_id/notes/:id -> Destroy
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gochat/gochat/internal/service"
|
||||
"github.com/gochat/gochat/pkg/response"
|
||||
)
|
||||
|
||||
// NoteHandler handles HTTP requests for contact notes.
|
||||
type NoteHandler struct {
|
||||
noteService *service.NoteService
|
||||
}
|
||||
|
||||
// NewNoteHandler creates a new NoteHandler.
|
||||
func NewNoteHandler(noteService *service.NoteService) *NoteHandler {
|
||||
return &NoteHandler{noteService: noteService}
|
||||
}
|
||||
|
||||
// noteRequest represents the JSON request body for creating/updating a note.
|
||||
// Reference: Chatwoot `params.require(:note).permit(:content)`
|
||||
type noteRequest struct {
|
||||
Content string `json:"content" binding:"required"`
|
||||
}
|
||||
|
||||
// List returns all notes for a contact.
|
||||
// Reference: Chatwoot `def index`
|
||||
func (h *NoteHandler) List(c *gin.Context) {
|
||||
accountID, err := strconv.ParseUint(c.Param("account_id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid account ID")
|
||||
return
|
||||
}
|
||||
contactID, err := strconv.ParseUint(c.Param("contact_id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid contact ID")
|
||||
return
|
||||
}
|
||||
|
||||
notes, err := h.noteService.List(uint(accountID), uint(contactID))
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 500, response.ErrInternal, "Failed to list notes")
|
||||
return
|
||||
}
|
||||
response.OK(c, notes)
|
||||
}
|
||||
|
||||
// Show returns a single note by ID.
|
||||
// Reference: Chatwoot `def show; end`
|
||||
func (h *NoteHandler) Show(c *gin.Context) {
|
||||
accountID, err := strconv.ParseUint(c.Param("account_id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid account ID")
|
||||
return
|
||||
}
|
||||
contactID, err := strconv.ParseUint(c.Param("contact_id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid contact ID")
|
||||
return
|
||||
}
|
||||
noteID, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid note ID")
|
||||
return
|
||||
}
|
||||
|
||||
note, err := h.noteService.Get(uint(accountID), uint(contactID), uint(noteID))
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 404, response.ErrNotFound, "Note not found")
|
||||
return
|
||||
}
|
||||
response.OK(c, note)
|
||||
}
|
||||
|
||||
// Create creates a new note for a contact.
|
||||
// Reference: Chatwoot `def create`
|
||||
// @note = @contact.notes.create!(note_params)
|
||||
// note_params merges {contact_id: @contact.id, user_id: Current.user.id}
|
||||
func (h *NoteHandler) Create(c *gin.Context) {
|
||||
accountID, err := strconv.ParseUint(c.Param("account_id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid account ID")
|
||||
return
|
||||
}
|
||||
contactID, err := strconv.ParseUint(c.Param("contact_id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid contact ID")
|
||||
return
|
||||
}
|
||||
|
||||
// Chatwoot: params.require(:note) → {"note": {"content": "..."}}
|
||||
var wrapper struct {
|
||||
Note noteRequest `json:"note"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&wrapper); err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Content is required")
|
||||
return
|
||||
}
|
||||
req := wrapper.Note
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
response.AbortWithStatusError(c, 401, response.ErrUnauthorized, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
note, err := h.noteService.Create(uint(accountID), uint(contactID), userID.(uint), req.Content)
|
||||
if err != nil {
|
||||
if err == service.ErrNoteContentEmpty {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Content is required")
|
||||
return
|
||||
}
|
||||
response.AbortWithStatusError(c, 500, response.ErrInternal, "Failed to create note")
|
||||
return
|
||||
}
|
||||
response.Created(c, note)
|
||||
}
|
||||
|
||||
// Update updates an existing note's content.
|
||||
// Reference: Chatwoot `def update; @note.update(note_params); end`
|
||||
func (h *NoteHandler) Update(c *gin.Context) {
|
||||
accountID, err := strconv.ParseUint(c.Param("account_id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid account ID")
|
||||
return
|
||||
}
|
||||
contactID, err := strconv.ParseUint(c.Param("contact_id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid contact ID")
|
||||
return
|
||||
}
|
||||
noteID, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid note ID")
|
||||
return
|
||||
}
|
||||
|
||||
// Chatwoot: params.require(:note) → {"note": {"content": "..."}}
|
||||
var wrapper struct {
|
||||
Note noteRequest `json:"note"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&wrapper); err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Content is required")
|
||||
return
|
||||
}
|
||||
req := wrapper.Note
|
||||
|
||||
note, err := h.noteService.Update(uint(accountID), uint(contactID), uint(noteID), req.Content)
|
||||
if err != nil {
|
||||
if err == service.ErrNoteNotFound {
|
||||
response.AbortWithStatusError(c, 404, response.ErrNotFound, "Note not found")
|
||||
return
|
||||
}
|
||||
response.AbortWithStatusError(c, 500, response.ErrInternal, "Failed to update note")
|
||||
return
|
||||
}
|
||||
response.OK(c, note)
|
||||
}
|
||||
|
||||
// Destroy deletes a note.
|
||||
// Reference: Chatwoot `def destroy; @note.destroy!; head :ok; end`
|
||||
// Chatwoot returns 200 OK on destroy, NOT 204 NoContent.
|
||||
func (h *NoteHandler) Destroy(c *gin.Context) {
|
||||
accountID, err := strconv.ParseUint(c.Param("account_id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid account ID")
|
||||
return
|
||||
}
|
||||
contactID, err := strconv.ParseUint(c.Param("contact_id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid contact ID")
|
||||
return
|
||||
}
|
||||
noteID, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 400, response.ErrBadRequest, "Invalid note ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.noteService.Delete(uint(accountID), uint(contactID), uint(noteID))
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, 404, response.ErrNotFound, "Note not found")
|
||||
return
|
||||
}
|
||||
// Reference: Chatwoot returns `head :ok` → 200 OK with empty body
|
||||
response.OK(c, gin.H{})
|
||||
}
|
||||
Reference in New Issue
Block a user