diff --git a/api/handler/send_document_message_handler.go b/api/handler/send_document_message_handler.go new file mode 100644 index 0000000..03b0c53 --- /dev/null +++ b/api/handler/send_document_message_handler.go @@ -0,0 +1,124 @@ +package handler + +import ( + "net/http" + "zapmeow/api/helper" + "zapmeow/api/model" + "zapmeow/api/response" + "zapmeow/api/service" + + "github.com/gin-gonic/gin" + "github.com/vincent-petithory/dataurl" +) + +type sendDocumentMessageBody struct { + Phone string `json:"phone"` + Base64 string `json:"base64"` + Filename string `json:"filename"` +} + +type sendDocumentMessageResponse struct { + Message response.Message `json:"message"` +} + +type sendDocumentMessageHandler struct { + whatsAppService service.WhatsAppService + messageService service.MessageService +} + +func NewSendDocumentMessageHandler( + whatsAppService service.WhatsAppService, + messageService service.MessageService, +) *sendDocumentMessageHandler { + return &sendDocumentMessageHandler{ + whatsAppService: whatsAppService, + messageService: messageService, + } +} + +// Send Image Message on WhatsApp +// +// @Summary Send Image Message on WhatsApp +// @Description Sends an image message on WhatsApp using the specified instance. +// @Tags WhatsApp Chat +// @Param instanceId path string true "Instance ID" +// @Param data body sendDocumentMessageBody true "Image message body" +// @Accept json +// @Produce json +// @Success 200 {object} sendDocumentMessageResponse "Message Send Response" +// @Router /{instanceId}/chat/send/image [post] +func (h *sendDocumentMessageHandler) Handler(c *gin.Context) { + instanceID := c.Param("instanceId") + instance, err := h.whatsAppService.GetInstance(instanceID) + if err != nil { + response.ErrorResponse(c, http.StatusInternalServerError, err.Error()) + return + } + + if !h.whatsAppService.IsAuthenticated(instance) { + response.ErrorResponse(c, http.StatusUnauthorized, "unautenticated") + return + } + + var body sendDocumentMessageBody + if err := c.ShouldBindJSON(&body); err != nil { + response.ErrorResponse(c, http.StatusBadRequest, "Error trying to validate infos. ") + return + } + + jid, ok := helper.MakeJID(body.Phone) + if !ok { + response.ErrorResponse(c, http.StatusBadRequest, "Invalid phone") + return + } + + mimitype, err := helper.GetMimeTypeFromDataURI(body.Base64) + if err != nil { + response.ErrorResponse(c, http.StatusInternalServerError, err.Error()) + return + } + + documentURL, err := dataurl.DecodeString(body.Base64) + if err != nil { + response.ErrorResponse(c, http.StatusInternalServerError, err.Error()) + return + } + + resp, err := h.whatsAppService.SendDocumentMessage(instance, jid, documentURL, mimitype, body.Filename) + if err != nil { + response.ErrorResponse(c, http.StatusInternalServerError, err.Error()) + return + } + + path, err := helper.SaveMedia( + instanceID, + resp.ID, + documentURL.Data, + mimitype, + ) + if err != nil { + response.ErrorResponse(c, http.StatusInternalServerError, err.Error()) + return + } + + message := model.Message{ + FromMe: true, + ChatJID: jid.User, + SenderJID: resp.Sender.User, + InstanceID: instanceID, + Timestamp: resp.Timestamp, + MessageID: resp.ID, + MediaType: "document", + MediaPath: path, + } + + err = h.messageService.CreateMessage(&message) + if err != nil { + response.ErrorResponse(c, http.StatusInternalServerError, err.Error()) + return + } + + response.Response(c, http.StatusOK, sendDocumentMessageResponse{ + Message: response.NewMessageResponse(message), + }) +} diff --git a/api/route/routes.go b/api/route/routes.go index ef577ef..ffac213 100644 --- a/api/route/routes.go +++ b/api/route/routes.go @@ -67,6 +67,10 @@ func SetupRouter( whatsAppService, messageService, ) + sendDocumentMessageHandler := handler.NewSendDocumentMessageHandler( + whatsAppService, + messageService, + ) group := router.Group("/api") @@ -80,6 +84,7 @@ func SetupRouter( group.POST("/:instanceId/chat/send/text", sendTextMessageHandler.Handler) group.POST("/:instanceId/chat/send/image", sendImageMessageHandler.Handler) group.POST("/:instanceId/chat/send/audio", sendAudioMessageHandler.Handler) + group.POST("/:instanceId/chat/send/document", sendDocumentMessageHandler.Handler) group.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) return router diff --git a/api/service/whatsapp_service.go b/api/service/whatsapp_service.go index ed33762..ad09e22 100644 --- a/api/service/whatsapp_service.go +++ b/api/service/whatsapp_service.go @@ -29,6 +29,7 @@ type WhatsAppService interface { Logout(instance *whatsapp.Instance) error SendTextMessage(instance *whatsapp.Instance, jid whatsapp.JID, text string) (whatsapp.MessageResponse, error) SendAudioMessage(instance *whatsapp.Instance, jid whatsapp.JID, audioURL *dataurl.DataURL, mimitype string) (whatsapp.MessageResponse, error) + SendDocumentMessage(instance *whatsapp.Instance, jid whatsapp.JID, documentURL *dataurl.DataURL, mimitype string, filename string) (whatsapp.MessageResponse, error) SendImageMessage(instance *whatsapp.Instance, jid whatsapp.JID, imageURL *dataurl.DataURL, mimitype string) (whatsapp.MessageResponse, error) GetContactInfo(instance *whatsapp.Instance, jid whatsapp.JID) (*whatsapp.ContactInfo, error) ParseEventMessage(instance *whatsapp.Instance, message *events.Message) (whatsapp.Message, error) @@ -57,6 +58,16 @@ func (w *whatsAppService) SendTextMessage( return w.whatsApp.SendTextMessage(instance, jid, text) } +func (w *whatsAppService) SendDocumentMessage( + instance *whatsapp.Instance, + jid whatsapp.JID, + documentURL *dataurl.DataURL, + mimitype string, + filename string, +) (whatsapp.MessageResponse, error) { + return w.whatsApp.SendDocumentMessage(instance, jid, documentURL, mimitype, filename) +} + func (w *whatsAppService) SendAudioMessage( instance *whatsapp.Instance, jid whatsapp.JID, diff --git a/pkg/whatsapp/whatsapp.go b/pkg/whatsapp/whatsapp.go index 757bc8e..4dcee1f 100644 --- a/pkg/whatsapp/whatsapp.go +++ b/pkg/whatsapp/whatsapp.go @@ -115,6 +115,7 @@ type WhatsApp interface { SendTextMessage(instance *Instance, jid JID, text string) (MessageResponse, error) SendAudioMessage(instance *Instance, jid JID, audioURL *dataurl.DataURL, mimitype string) (MessageResponse, error) SendImageMessage(instance *Instance, jid JID, imageURL *dataurl.DataURL, mimitype string) (MessageResponse, error) + SendDocumentMessage(instance *Instance, jid JID, documentURL *dataurl.DataURL, mimitype string, filename string) (MessageResponse, error) GetContactInfo(instance *Instance, jid JID) (*ContactInfo, error) ParseEventMessage(instance *Instance, message *events.Message) (Message, error) IsOnWhatsApp(instance *Instance, phones []string) ([]IsOnWhatsAppResponse, error) @@ -257,6 +258,28 @@ func (w *whatsApp) SendImageMessage(instance *Instance, jid JID, imageURL *datau return w.sendMessage(instance, jid, message) } +func (w *whatsApp) SendDocumentMessage( + instance *Instance, jid JID, documentURL *dataurl.DataURL, mimitype string, filename string) (MessageResponse, error) { + uploaded, err := w.uploadMedia(instance, documentURL, Document) + if err != nil { + return MessageResponse{}, err + } + + message := &waProto.Message{ + DocumentMessage: &waProto.DocumentMessage{ + Url: proto.String(uploaded.URL), + FileName: &filename, + DirectPath: proto.String(uploaded.DirectPath), + MediaKey: uploaded.MediaKey, + Mimetype: proto.String(mimitype), + FileEncSha256: uploaded.FileEncSHA256, + FileSha256: uploaded.FileSHA256, + FileLength: proto.Uint64(uint64(len(documentURL.Data))), + }, + } + return w.sendMessage(instance, jid, message) +} + func (w *whatsApp) IsOnWhatsApp(instance *Instance, phones []string) ([]IsOnWhatsAppResponse, error) { isOnWhatsAppResponse, err := instance.Client.IsOnWhatsApp(phones) if err != nil { @@ -366,6 +389,8 @@ func (w *whatsApp) uploadMedia(instance *Instance, media *dataurl.DataURL, media mType = whatsmeow.MediaImage case Audio: mType = whatsmeow.MediaAudio + case Document: + mType = whatsmeow.MediaDocument default: return nil, errors.New("unknown media type") }