diff --git a/src/cmd/root.go b/src/cmd/root.go index e22607f..47aeced 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -98,11 +98,13 @@ func runRest(_ *cobra.Command, _ []string) { appService := services.NewAppService(cli, db) sendService := services.NewSendService(cli) userService := services.NewUserService(cli) + messageService := services.NewMessageService(cli) // Rest rest.InitRestApp(app, appService) rest.InitRestSend(app, sendService) rest.InitRestUser(app, userService) + rest.InitRestMessage(app, messageService) app.Get("/", func(c *fiber.Ctx) error { return c.Render("index", fiber.Map{ diff --git a/src/domains/message/message.go b/src/domains/message/message.go new file mode 100644 index 0000000..a65a44f --- /dev/null +++ b/src/domains/message/message.go @@ -0,0 +1,9 @@ +package message + +import "context" + +type IMessageService interface { + ReactMessage(ctx context.Context, request ReactionRequest) (response ReactionResponse, err error) + RevokeMessage(ctx context.Context, request RevokeRequest) (response RevokeResponse, err error) + UpdateMessage(ctx context.Context, request UpdateMessageRequest) (response UpdateMessageResponse, err error) +} diff --git a/src/domains/send/reaction.go b/src/domains/message/reaction.go similarity index 94% rename from src/domains/send/reaction.go rename to src/domains/message/reaction.go index ad5f09b..45a5c8f 100644 --- a/src/domains/send/reaction.go +++ b/src/domains/message/reaction.go @@ -1,4 +1,4 @@ -package send +package message type ReactionRequest struct { MessageID string `json:"message_id" form:"message_id"` diff --git a/src/domains/message/revoke.go b/src/domains/message/revoke.go new file mode 100644 index 0000000..e7567e9 --- /dev/null +++ b/src/domains/message/revoke.go @@ -0,0 +1,11 @@ +package message + +type RevokeRequest struct { + MessageID string `json:"message_id" uri:"message_id"` + Phone string `json:"phone" form:"phone"` +} + +type RevokeResponse struct { + MessageID string `json:"message_id"` + Status string `json:"status"` +} diff --git a/src/domains/message/update.go b/src/domains/message/update.go new file mode 100644 index 0000000..5321055 --- /dev/null +++ b/src/domains/message/update.go @@ -0,0 +1,12 @@ +package message + +type UpdateMessageRequest struct { + MessageID string `json:"message_id" uri:"message_id"` + Message string `json:"message" form:"message"` + Phone string `json:"phone" form:"phone"` +} + +type UpdateMessageResponse struct { + MessageID string `json:"message_id"` + Status string `json:"status"` +} diff --git a/src/domains/send/message.go b/src/domains/send/message.go index 441ce95..a746a4d 100644 --- a/src/domains/send/message.go +++ b/src/domains/send/message.go @@ -1,15 +1,5 @@ package send -type RevokeRequest struct { - MessageID string `json:"message_id" uri:"message_id"` - Phone string `json:"phone" form:"phone"` -} - -type RevokeResponse struct { - MessageID string `json:"message_id"` - Status string `json:"status"` -} - type UpdateMessageRequest struct { MessageID string `json:"message_id" uri:"message_id"` Message string `json:"message" form:"message"` diff --git a/src/domains/send/send.go b/src/domains/send/send.go index 306898d..2054e0d 100644 --- a/src/domains/send/send.go +++ b/src/domains/send/send.go @@ -12,7 +12,4 @@ type ISendService interface { SendContact(ctx context.Context, request ContactRequest) (response ContactResponse, err error) SendLink(ctx context.Context, request LinkRequest) (response LinkResponse, err error) SendLocation(ctx context.Context, request LocationRequest) (response LocationResponse, err error) - SendReaction(ctx context.Context, request ReactionRequest) (response ReactionResponse, err error) - Revoke(ctx context.Context, request RevokeRequest) (response RevokeResponse, err error) - UpdateMessage(ctx context.Context, request UpdateMessageRequest) (response UpdateMessageResponse, err error) } diff --git a/src/internal/rest/message.go b/src/internal/rest/message.go new file mode 100644 index 0000000..71e6329 --- /dev/null +++ b/src/internal/rest/message.go @@ -0,0 +1,78 @@ +package rest + +import ( + "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/message" + domainMessage "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/message" + "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils" + "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp" + "github.com/gofiber/fiber/v2" +) + +type Message struct { + Service domainMessage.IMessageService +} + +func InitRestMessage(app *fiber.App, service domainMessage.IMessageService) Message { + rest := Message{Service: service} + app.Post("/message/:message_id/reaction", rest.ReactMessage) + app.Post("/message/:message_id/revoke", rest.RevokeMessage) + app.Post("/message/:message_id/update", rest.UpdateMessage) + return rest +} + +func (controller *Message) RevokeMessage(c *fiber.Ctx) error { + var request domainMessage.RevokeRequest + err := c.BodyParser(&request) + utils.PanicIfNeeded(err) + + request.MessageID = c.Params("message_id") + whatsapp.SanitizePhone(&request.Phone) + + response, err := controller.Service.RevokeMessage(c.UserContext(), request) + utils.PanicIfNeeded(err) + + return c.JSON(utils.ResponseData{ + Status: 200, + Code: "SUCCESS", + Message: response.Status, + Results: response, + }) +} + +func (controller *Message) UpdateMessage(c *fiber.Ctx) error { + var request domainMessage.UpdateMessageRequest + err := c.BodyParser(&request) + utils.PanicIfNeeded(err) + + request.MessageID = c.Params("message_id") + whatsapp.SanitizePhone(&request.Phone) + + response, err := controller.Service.UpdateMessage(c.UserContext(), request) + utils.PanicIfNeeded(err) + + return c.JSON(utils.ResponseData{ + Status: 200, + Code: "SUCCESS", + Message: response.Status, + Results: response, + }) +} + +func (controller *Message) ReactMessage(c *fiber.Ctx) error { + var request message.ReactionRequest + err := c.BodyParser(&request) + utils.PanicIfNeeded(err) + + request.MessageID = c.Params("message_id") + whatsapp.SanitizePhone(&request.Phone) + + response, err := controller.Service.ReactMessage(c.UserContext(), request) + utils.PanicIfNeeded(err) + + return c.JSON(utils.ResponseData{ + Status: 200, + Code: "SUCCESS", + Message: response.Status, + Results: response, + }) +} diff --git a/src/internal/rest/send.go b/src/internal/rest/send.go index c5ccbe8..efcec4f 100644 --- a/src/internal/rest/send.go +++ b/src/internal/rest/send.go @@ -20,9 +20,6 @@ func InitRestSend(app *fiber.App, service domainSend.ISendService) Send { app.Post("/send/contact", rest.SendContact) app.Post("/send/link", rest.SendLink) app.Post("/send/location", rest.SendLocation) - app.Post("/message/:message_id/reaction", rest.ReactionMessage) - app.Post("/message/:message_id/revoke", rest.RevokeMessage) - app.Post("/message/:message_id/update", rest.UpdateMessage) return rest } @@ -165,60 +162,3 @@ func (controller *Send) SendLocation(c *fiber.Ctx) error { Results: response, }) } - -func (controller *Send) RevokeMessage(c *fiber.Ctx) error { - var request domainSend.RevokeRequest - err := c.BodyParser(&request) - utils.PanicIfNeeded(err) - - request.MessageID = c.Params("message_id") - whatsapp.SanitizePhone(&request.Phone) - - response, err := controller.Service.Revoke(c.UserContext(), request) - utils.PanicIfNeeded(err) - - return c.JSON(utils.ResponseData{ - Status: 200, - Code: "SUCCESS", - Message: response.Status, - Results: response, - }) -} - -func (controller *Send) UpdateMessage(c *fiber.Ctx) error { - var request domainSend.UpdateMessageRequest - err := c.BodyParser(&request) - utils.PanicIfNeeded(err) - - request.MessageID = c.Params("message_id") - whatsapp.SanitizePhone(&request.Phone) - - response, err := controller.Service.UpdateMessage(c.UserContext(), request) - utils.PanicIfNeeded(err) - - return c.JSON(utils.ResponseData{ - Status: 200, - Code: "SUCCESS", - Message: response.Status, - Results: response, - }) -} - -func (controller *Send) ReactionMessage(c *fiber.Ctx) error { - var request domainSend.ReactionRequest - err := c.BodyParser(&request) - utils.PanicIfNeeded(err) - - request.MessageID = c.Params("message_id") - whatsapp.SanitizePhone(&request.Phone) - - response, err := controller.Service.SendReaction(c.UserContext(), request) - utils.PanicIfNeeded(err) - - return c.JSON(utils.ResponseData{ - Status: 200, - Code: "SUCCESS", - Message: response.Status, - Results: response, - }) -} diff --git a/src/services/message.go b/src/services/message.go new file mode 100644 index 0000000..a796b80 --- /dev/null +++ b/src/services/message.go @@ -0,0 +1,95 @@ +package services + +import ( + "context" + "fmt" + "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/message" + domainMessage "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/message" + "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp" + "github.com/aldinokemal/go-whatsapp-web-multidevice/validations" + "go.mau.fi/whatsmeow" + waProto "go.mau.fi/whatsmeow/binary/proto" + "go.mau.fi/whatsmeow/types" + "google.golang.org/protobuf/proto" + "time" +) + +type serviceMessage struct { + WaCli *whatsmeow.Client +} + +func NewMessageService(waCli *whatsmeow.Client) domainMessage.IMessageService { + return &serviceMessage{ + WaCli: waCli, + } +} + +func (service serviceMessage) ReactMessage(ctx context.Context, request message.ReactionRequest) (response message.ReactionResponse, err error) { + if err = validations.ValidateReactMessage(ctx, request); err != nil { + return response, err + } + dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone) + if err != nil { + return response, err + } + + msg := &waProto.Message{ + ReactionMessage: &waProto.ReactionMessage{ + Key: &waProto.MessageKey{ + FromMe: proto.Bool(true), + Id: proto.String(request.MessageID), + RemoteJid: proto.String(dataWaRecipient.String()), + }, + Text: proto.String(request.Emoji), + SenderTimestampMs: proto.Int64(time.Now().UnixMilli()), + }, + } + ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msg) + if err != nil { + return response, err + } + + response.MessageID = ts.ID + response.Status = fmt.Sprintf("Reaction sent to %s (server timestamp: %s)", request.Phone, ts) + return response, nil +} + +func (service serviceMessage) RevokeMessage(ctx context.Context, request domainMessage.RevokeRequest) (response domainMessage.RevokeResponse, err error) { + if err = validations.ValidateRevokeMessage(ctx, request); err != nil { + return response, err + } + dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone) + if err != nil { + return response, err + } + + ts, err := service.WaCli.SendMessage(context.Background(), dataWaRecipient, service.WaCli.BuildRevoke(dataWaRecipient, types.EmptyJID, request.MessageID)) + if err != nil { + return response, err + } + + response.MessageID = ts.ID + response.Status = fmt.Sprintf("Revoke success %s (server timestamp: %s)", request.Phone, ts) + return response, nil +} + +func (service serviceMessage) UpdateMessage(ctx context.Context, request domainMessage.UpdateMessageRequest) (response domainMessage.UpdateMessageResponse, err error) { + if err = validations.ValidateUpdateMessage(ctx, request); err != nil { + return response, err + } + + dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone) + if err != nil { + return response, err + } + + msg := &waProto.Message{Conversation: proto.String(request.Message)} + ts, err := service.WaCli.SendMessage(context.Background(), dataWaRecipient, service.WaCli.BuildEdit(dataWaRecipient, request.MessageID, msg)) + if err != nil { + return response, err + } + + response.MessageID = ts.ID + response.Status = fmt.Sprintf("Update message success %s (server timestamp: %s)", request.Phone, ts) + return response, nil +} diff --git a/src/services/send.go b/src/services/send.go index 587d8d6..7d4635d 100644 --- a/src/services/send.go +++ b/src/services/send.go @@ -14,12 +14,10 @@ import ( "github.com/valyala/fasthttp" "go.mau.fi/whatsmeow" waProto "go.mau.fi/whatsmeow/binary/proto" - "go.mau.fi/whatsmeow/types" "google.golang.org/protobuf/proto" "net/http" "os" "os/exec" - "time" ) type serviceSend struct { @@ -399,71 +397,3 @@ func (service serviceSend) SendLocation(ctx context.Context, request domainSend. response.Status = fmt.Sprintf("Send location success %s (server timestamp: %s)", request.Phone, ts) return response, nil } - -func (service serviceSend) SendReaction(ctx context.Context, request domainSend.ReactionRequest) (response domainSend.ReactionResponse, err error) { - dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone) - if err != nil { - return response, err - } - - msg := &waProto.Message{ - ReactionMessage: &waProto.ReactionMessage{ - Key: &waProto.MessageKey{ - FromMe: proto.Bool(true), - Id: proto.String(request.MessageID), - RemoteJid: proto.String(dataWaRecipient.String()), - }, - Text: proto.String(request.Emoji), - SenderTimestampMs: proto.Int64(time.Now().UnixMilli()), - }, - } - ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msg) - if err != nil { - return response, err - } - - response.MessageID = ts.ID - response.Status = fmt.Sprintf("Reaction sent to %s (server timestamp: %s)", request.Phone, ts) - return response, nil -} - -func (service serviceSend) Revoke(ctx context.Context, request domainSend.RevokeRequest) (response domainSend.RevokeResponse, err error) { - err = validations.ValidateRevokeMessage(ctx, request) - if err != nil { - return response, err - } - dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone) - if err != nil { - return response, err - } - - ts, err := service.WaCli.SendMessage(context.Background(), dataWaRecipient, service.WaCli.BuildRevoke(dataWaRecipient, types.EmptyJID, request.MessageID)) - if err != nil { - return response, err - } - - response.MessageID = ts.ID - response.Status = fmt.Sprintf("Revoke success %s (server timestamp: %s)", request.Phone, ts) - return response, nil -} - -func (service serviceSend) UpdateMessage(ctx context.Context, request domainSend.UpdateMessageRequest) (response domainSend.UpdateMessageResponse, err error) { - err = validations.ValidateUpdateMessage(ctx, request) - if err != nil { - return response, err - } - dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone) - if err != nil { - return response, err - } - - msg := &waProto.Message{Conversation: proto.String(request.Message)} - ts, err := service.WaCli.SendMessage(context.Background(), dataWaRecipient, service.WaCli.BuildEdit(dataWaRecipient, request.MessageID, msg)) - if err != nil { - return response, err - } - - response.MessageID = ts.ID - response.Status = fmt.Sprintf("Update message success %s (server timestamp: %s)", request.Phone, ts) - return response, nil -} diff --git a/src/validations/message_validation.go b/src/validations/message_validation.go new file mode 100644 index 0000000..b7caabe --- /dev/null +++ b/src/validations/message_validation.go @@ -0,0 +1,50 @@ +package validations + +import ( + "context" + "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/message" + domainMessage "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/message" + pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +func ValidateRevokeMessage(ctx context.Context, request domainMessage.RevokeRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, + validation.Field(&request.Phone, validation.Required), + validation.Field(&request.MessageID, validation.Required), + ) + + if err != nil { + return pkgError.ValidationError(err.Error()) + } + + return nil +} + +func ValidateUpdateMessage(ctx context.Context, request domainMessage.UpdateMessageRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, + validation.Field(&request.Phone, validation.Required), + validation.Field(&request.MessageID, validation.Required), + validation.Field(&request.Message, validation.Required), + ) + + if err != nil { + return pkgError.ValidationError(err.Error()) + } + + return nil +} + +func ValidateReactMessage(ctx context.Context, request message.ReactionRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, + validation.Field(&request.Phone, validation.Required), + validation.Field(&request.MessageID, validation.Required), + validation.Field(&request.Emoji, validation.Required), + ) + + if err != nil { + return pkgError.ValidationError(err.Error()) + } + + return nil +} diff --git a/src/validations/send_validation.go b/src/validations/send_validation.go index 5078201..cbef06a 100644 --- a/src/validations/send_validation.go +++ b/src/validations/send_validation.go @@ -133,30 +133,3 @@ func ValidateSendLocation(ctx context.Context, request domainSend.LocationReques return nil } - -func ValidateRevokeMessage(ctx context.Context, request domainSend.RevokeRequest) error { - err := validation.ValidateStructWithContext(ctx, &request, - validation.Field(&request.Phone, validation.Required), - validation.Field(&request.MessageID, validation.Required), - ) - - if err != nil { - return pkgError.ValidationError(err.Error()) - } - - return nil -} - -func ValidateUpdateMessage(ctx context.Context, request domainSend.UpdateMessageRequest) error { - err := validation.ValidateStructWithContext(ctx, &request, - validation.Field(&request.Phone, validation.Required), - validation.Field(&request.MessageID, validation.Required), - validation.Field(&request.Message, validation.Required), - ) - - if err != nil { - return pkgError.ValidationError(err.Error()) - } - - return nil -}