validops-east-1's picture
restructure repo into production layout; add whatsapp-service, tests, ddl, docs, scripts; scrub hardcoded secrets
83d6851
Raw
History Blame Contribute Delete
11.8 kB
package message_handler
import (
"net/http"
instance_model "agentdeck-whatsapp-service/pkg/instance/model"
message_service "agentdeck-whatsapp-service/pkg/message/service"
"github.com/gin-gonic/gin"
)
type MessageHandler interface {
React(ctx *gin.Context)
ChatPresence(ctx *gin.Context)
MarkRead(ctx *gin.Context)
MarkPlayed(ctx *gin.Context)
DownloadMedia(ctx *gin.Context)
GetMessageStatus(ctx *gin.Context)
DeleteMessageEveryone(ctx *gin.Context)
EditMessage(ctx *gin.Context)
}
type messageHandler struct {
messageService message_service.MessageService
}
// React a message
// @Summary React a message
// @Description React to a message with support for fromMe field and participant field for group messages
// @Tags Message
// @Accept json
// @Produce json
// @Param message body message_service.ReactStruct true "React to a message with fromMe and participant fields"
// @Success 200 {object} gin.H "success"
// @Failure 400 {object} gin.H "Error on validation"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /message/react [post]
func (m *messageHandler) React(ctx *gin.Context) {
getInstance := ctx.MustGet("instance")
instance, ok := getInstance.(*instance_model.Instance)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"})
return
}
var data *message_service.ReactStruct
err := ctx.ShouldBindBodyWithJSON(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if data.Number == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "phone number is required"})
return
}
if data.Reaction == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "message reaction is required"})
return
}
message, err := m.messageService.React(data, instance)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
ctx.JSON(http.StatusOK, gin.H{"message": "success", "data": message})
}
// ChatPresence set chat presence
// @Summary Set chat presence
// @Description Set chat presence
// @Tags Message
// @Accept json
// @Produce json
// @Param message body message_service.ChatPresenceStruct true "Set chat presence"
// @Success 200 {object} gin.H "success"
// @Failure 400 {object} gin.H "Error on validation"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /message/presence [post]
func (m *messageHandler) ChatPresence(ctx *gin.Context) {
getInstance := ctx.MustGet("instance")
instance, ok := getInstance.(*instance_model.Instance)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"})
return
}
var data *message_service.ChatPresenceStruct
err := ctx.ShouldBindBodyWithJSON(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if data.Number == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "phone number is required"})
return
}
if data.State == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "state is required"})
return
}
ts, err := m.messageService.ChatPresence(data, instance)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
responseData := gin.H{
"timestamp": ts,
}
ctx.JSON(http.StatusOK, gin.H{"message": "success", "data": responseData})
}
// MarkRead mark a message as read
// @Summary Mark a message as read
// @Description Mark a message as read
// @Tags Message
// @Accept json
// @Produce json
// @Param message body message_service.MarkReadStruct true "Mark a message as read"
// @Success 200 {object} gin.H "success"
// @Failure 400 {object} gin.H "Error on validation"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /message/markread [post]
func (m *messageHandler) MarkRead(ctx *gin.Context) {
getInstance := ctx.MustGet("instance")
instance, ok := getInstance.(*instance_model.Instance)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"})
return
}
var data *message_service.MarkReadStruct
err := ctx.ShouldBindBodyWithJSON(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if data.Number == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "phone number is required"})
return
}
if len(data.Id) < 1 {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "id is required"})
return
}
ts, err := m.messageService.MarkRead(data, instance)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
responseData := gin.H{
"timestamp": ts,
}
ctx.JSON(http.StatusOK, gin.H{"message": "success", "data": responseData})
}
// MarkPlayed mark an audio message as played (blue mic icon)
// @Summary Mark an audio message as played
// @Description Mark an audio message as played
// @Tags Message
// @Accept json
// @Produce json
// @Param message body message_service.MarkPlayedStruct true "Mark an audio message as played"
// @Success 200 {object} gin.H "success"
// @Failure 400 {object} gin.H "Error on validation"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /message/markplayed [post]
func (m *messageHandler) MarkPlayed(ctx *gin.Context) {
getInstance := ctx.MustGet("instance")
instance, ok := getInstance.(*instance_model.Instance)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"})
return
}
var data *message_service.MarkPlayedStruct
err := ctx.ShouldBindBodyWithJSON(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if data.Number == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "phone number is required"})
return
}
if len(data.Id) < 1 {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "id is required"})
return
}
ts, err := m.messageService.MarkPlayed(data, instance)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
responseData := gin.H{
"timestamp": ts,
}
ctx.JSON(http.StatusOK, gin.H{"message": "success", "data": responseData})
}
// DownloadMedia download a media message (image, video, audio, document)
// @Summary Download media
// @Description Download the media content of a message (image, video, audio or document)
// @Tags Message
// @Accept json
// @Produce json
// @Param message body message_service.DownloadMediaStruct true "Download media"
// @Success 200 {object} gin.H "success"
// @Failure 400 {object} gin.H "Error on validation"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /message/downloadmedia [post]
func (m *messageHandler) DownloadMedia(ctx *gin.Context) {
getInstance := ctx.MustGet("instance")
instance, ok := getInstance.(*instance_model.Instance)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"})
return
}
var data *message_service.DownloadMediaStruct
err := ctx.ShouldBindBodyWithJSON(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
dataUrl, ts, err := m.messageService.DownloadMedia(data, instance, ctx.Request)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
responseData := gin.H{
"base64": dataUrl.String(),
"timestamp": ts,
}
ctx.JSON(http.StatusOK, gin.H{"message": "success", "data": responseData})
}
// GetMessageStatus get message status
// @Summary Get message status
// @Description Get message status
// @Tags Message
// @Accept json
// @Produce json
// @Param message body message_service.MessageStatusStruct true "Get message status"
// @Success 200 {object} gin.H "success"
// @Failure 400 {object} gin.H "Error on validation"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /message/status [post]
func (m *messageHandler) GetMessageStatus(ctx *gin.Context) {
getInstance := ctx.MustGet("instance")
instance, ok := getInstance.(*instance_model.Instance)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"})
return
}
var data *message_service.MessageStatusStruct
err := ctx.ShouldBindBodyWithJSON(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if data.Id == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "id is required"})
return
}
message, ts, err := m.messageService.GetMessageStatus(data, instance)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
responseData := gin.H{
"result": message,
"timestamp": ts,
}
ctx.JSON(http.StatusOK, gin.H{"message": "success", "data": responseData})
}
// DeleteMessageEveryone delete a message for everyone
// @Summary Delete a message for everyone
// @Description Delete a message for everyone
// @Tags Message
// @Accept json
// @Produce json
// @Param message body message_service.MessageStruct true "Delete a message for everyone"
// @Success 200 {object} gin.H "success"
// @Failure 400 {object} gin.H "Error on validation"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /message/delete [post]
func (m *messageHandler) DeleteMessageEveryone(ctx *gin.Context) {
getInstance := ctx.MustGet("instance")
instance, ok := getInstance.(*instance_model.Instance)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"})
return
}
var data *message_service.MessageStruct
err := ctx.ShouldBindBodyWithJSON(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if data.Chat == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "chat is required"})
return
}
if data.MessageID == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "messageId is required"})
return
}
msgId, ts, err := m.messageService.DeleteMessageEveryone(data, instance)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
responseData := gin.H{
"messageId": msgId,
"timestamp": ts,
}
ctx.JSON(http.StatusOK, gin.H{"message": "success", "data": responseData})
}
// EditMessage edit a message
// @Summary Edit a message
// @Description Edit a message
// @Tags Message
// @Accept json
// @Produce json
// @Param message body message_service.EditMessageStruct true "Edit a message"
// @Success 200 {object} gin.H "success"
// @Failure 400 {object} gin.H "Error on validation"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /message/edit [post]
func (m *messageHandler) EditMessage(ctx *gin.Context) {
getInstance := ctx.MustGet("instance")
instance, ok := getInstance.(*instance_model.Instance)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"})
return
}
var data *message_service.EditMessageStruct
err := ctx.ShouldBindBodyWithJSON(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if data.Chat == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "chat is required"})
return
}
if data.Message == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "message is required"})
return
}
if data.MessageID == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "messageId is required"})
return
}
msgId, ts, err := m.messageService.EditMessage(data, instance)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
responseData := gin.H{
"messageId": msgId,
"timestamp": ts,
}
ctx.JSON(http.StatusOK, gin.H{"message": "success", "data": responseData})
}
func NewMessageHandler(
messageService message_service.MessageService,
) MessageHandler {
return &messageHandler{
messageService: messageService,
}
}