From 1e173b22120211b7b96eee02d8b9b9ff87099410 Mon Sep 17 00:00:00 2001 From: Aldino Kemal Date: Tue, 29 Oct 2024 21:49:05 +0700 Subject: [PATCH] feat: mark as read (#208) * feat: add mark as read feat(message.go): add MarkAsRead functionality to IMessageService for marking messages as read feat(go.mod): update dependencies to newer versions for improved functionality and security feat(rest): add endpoint for MarkAsRead to handle marking messages as read through the API feat(service): implement MarkAsRead logic in serviceMessage to mark messages as read in WhatsApp feat(validations): add validation for MarkAsRead request to ensure required fields are present * chore(settings.go): bump AppVersion to v4.21.0 for new release feat(message.go): add logging for MarkAsRead function using logrus for better traceability fix(GroupManageParticipants.js): remove redundant '@' from group_id computation --- docs/openapi.yaml | 46 ++++++++++++++++++- readme.md | 3 +- src/config/settings.go | 2 +- src/domains/message/message.go | 6 +++ src/go.mod | 6 +-- src/go.sum | 6 +++ src/internal/rest/message.go | 20 ++++++++ src/services/message.go | 27 +++++++++++ src/validations/message_validation.go | 14 ++++++ .../components/GroupManageParticipants.js | 2 +- 10 files changed, 125 insertions(+), 7 deletions(-) diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 71569f6..c278281 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: WhatsApp API MultiDevice - version: 4.3.0 + version: 4.4.0 description: This API is used for sending whatsapp via API servers: - url: http://localhost:3000 @@ -835,6 +835,50 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorInternalServer' + /message/{message_id}/read: + post: + operationId: readMessage + tags: + - message + summary: Mark as read message + parameters: + - in: path + name: message_id + schema: + type: string + required: true + description: Message ID + requestBody: + content: + application/json: + schema: + type: object + properties: + phone: + type: string + example: '62819273192397132@s.whatsapp.net' + description: Phone number with country code + required: + - phone + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/SendResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBadRequest' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInternalServer' /group: post: operationId: createGroup diff --git a/readme.md b/readme.md index a27272a..4052b5c 100644 --- a/readme.md +++ b/readme.md @@ -128,6 +128,7 @@ You can fork or edit this source code ! | ✅ | React Message | POST | /message/:message_id/reaction | | ✅ | Delete Message | POST | /message/:message_id/delete | | ✅ | Edit Message | POST | /message/:message_id/update | +| ✅ | Read Message (DM) | POST | /message/:message_id/read | | ❌ | Star message | POST | /message/:message_id/star | | ✅ | Join Group With Link | POST | /group/join-with-link | | ✅ | Leave Group | POST | /group/leave | @@ -136,7 +137,7 @@ You can fork or edit this source code ! | ✅ | Remove Participant in Group | POST | /group/participants/remove | | ✅ | Promote Participant in Group | POST | /group/participants/promote | | ✅ | Demote Participant in Group | POST | /group/participants/demote | -| ✅ | Unfollow Newsletter | POST | /newsletter/unfollow | +| ✅ | Unfollow Newsletter | POST | /newsletter/unfollow | ``` ✅ = Available diff --git a/src/config/settings.go b/src/config/settings.go index 9747fa2..e09c303 100644 --- a/src/config/settings.go +++ b/src/config/settings.go @@ -5,7 +5,7 @@ import ( ) var ( - AppVersion = "v4.20.0" + AppVersion = "v4.21.0" AppPort = "3000" AppDebug = false AppOs = "AldinoKemal" diff --git a/src/domains/message/message.go b/src/domains/message/message.go index 282781f..0de494b 100644 --- a/src/domains/message/message.go +++ b/src/domains/message/message.go @@ -3,6 +3,7 @@ package message import "context" type IMessageService interface { + MarkAsRead(ctx context.Context, request MarkAsReadRequest) (response GenericResponse, err error) ReactMessage(ctx context.Context, request ReactionRequest) (response GenericResponse, err error) RevokeMessage(ctx context.Context, request RevokeRequest) (response GenericResponse, err error) UpdateMessage(ctx context.Context, request UpdateMessageRequest) (response GenericResponse, err error) @@ -35,3 +36,8 @@ type UpdateMessageRequest struct { Message string `json:"message" form:"message"` Phone string `json:"phone" form:"phone"` } + +type MarkAsReadRequest struct { + MessageID string `json:"message_id" uri:"message_id"` + Phone string `json:"phone" form:"phone"` +} diff --git a/src/go.mod b/src/go.mod index e8a0492..70139fb 100644 --- a/src/go.mod +++ b/src/go.mod @@ -18,9 +18,9 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 - github.com/valyala/fasthttp v1.56.0 + github.com/valyala/fasthttp v1.57.0 go.mau.fi/libsignal v0.1.1 - go.mau.fi/whatsmeow v0.0.0-20241009112614-70d73b690a8d + go.mau.fi/whatsmeow v0.0.0-20241027175758-cd900353e4a7 google.golang.org/protobuf v1.35.1 ) @@ -47,7 +47,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - go.mau.fi/util v0.8.0 // indirect + go.mau.fi/util v0.8.1 // indirect golang.org/x/crypto v0.28.0 // indirect golang.org/x/image v0.21.0 // indirect golang.org/x/net v0.30.0 // indirect diff --git a/src/go.sum b/src/go.sum index 371f91e..718ce15 100644 --- a/src/go.sum +++ b/src/go.sum @@ -101,6 +101,8 @@ github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8 github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= github.com/valyala/fasthttp v1.56.0 h1:bEZdJev/6LCBlpdORfrLu/WOZXXxvrUQSiyniuaoW8U= github.com/valyala/fasthttp v1.56.0/go.mod h1:sReBt3XZVnudxuLOx4J/fMrJVorWRiWY2koQKgABiVI= +github.com/valyala/fasthttp v1.57.0 h1:Xw8SjWGEP/+wAAgyy5XTvgrWlOD1+TxbbvNADYCm1Tg= +github.com/valyala/fasthttp v1.57.0/go.mod h1:h6ZBaPRlzpZ6O3H5t2gEk1Qi33+TmLvfwgLLp0t9CpE= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= @@ -111,6 +113,8 @@ go.mau.fi/util v0.7.0 h1:l31z+ivrSQw+cv/9eFebEqtQW2zhxivGypn+JT0h/ws= go.mau.fi/util v0.7.0/go.mod h1:bWYreIoTULL/UiRbZdfddPh7uWDFW5yX4YCv5FB0eE0= go.mau.fi/util v0.8.0 h1:MiSny8jgQq4XtCLAT64gDJhZVhqiDeMVIEBDFVw+M0g= go.mau.fi/util v0.8.0/go.mod h1:1Ixb8HWoVbl3rT6nAX6nV4iMkzn7KU/KXwE0Rn5RmsQ= +go.mau.fi/util v0.8.1 h1:Ga43cz6esQBYqcjZ/onRoVnYWoUwjWbsxVeJg2jOTSo= +go.mau.fi/util v0.8.1/go.mod h1:T1u/rD2rzidVrBLyaUdPpZiJdP/rsyi+aTzn0D+Q6wc= go.mau.fi/whatsmeow v0.0.0-20240821142752-3d63c6fcc1a7 h1:Aa4uov0rM0SQQ7Fc/TZZpmQEGksie2SVTv/UuCJwViI= go.mau.fi/whatsmeow v0.0.0-20240821142752-3d63c6fcc1a7/go.mod h1:BhHKalSq0qNtSCuGIUIvoJyU5KbT4a7k8DQ5yw1Ssk4= go.mau.fi/whatsmeow v0.0.0-20240911102933-bb3364aa3986 h1:7X+3826qoRBHPCtxY89tqMcYEsi9+OuWE6hHZfRc0qI= @@ -119,6 +123,8 @@ go.mau.fi/whatsmeow v0.0.0-20240927134544-69ba055bef0f h1:+gT0NSk50HaAagtyj6J/a/ go.mau.fi/whatsmeow v0.0.0-20240927134544-69ba055bef0f/go.mod h1:UvaXcdb8y5Mryj2LSXAMw7u4/exnWJIXn8Gvpmf6ndI= go.mau.fi/whatsmeow v0.0.0-20241009112614-70d73b690a8d h1:0OV2Ula2IGaoHVfvv7ns+Gn3xGT0SHn5yDecJBB8FQY= go.mau.fi/whatsmeow v0.0.0-20241009112614-70d73b690a8d/go.mod h1:UvaXcdb8y5Mryj2LSXAMw7u4/exnWJIXn8Gvpmf6ndI= +go.mau.fi/whatsmeow v0.0.0-20241027175758-cd900353e4a7 h1:0qujZcpt0G1QFCrTgrXvnVg6yQU1IG1VbmHRHkWV0iY= +go.mau.fi/whatsmeow v0.0.0-20241027175758-cd900353e4a7/go.mod h1:UvaXcdb8y5Mryj2LSXAMw7u4/exnWJIXn8Gvpmf6ndI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= diff --git a/src/internal/rest/message.go b/src/internal/rest/message.go index c14d223..22086b5 100644 --- a/src/internal/rest/message.go +++ b/src/internal/rest/message.go @@ -18,6 +18,7 @@ func InitRestMessage(app *fiber.App, service domainMessage.IMessageService) Mess app.Post("/message/:message_id/revoke", rest.RevokeMessage) app.Post("/message/:message_id/delete", rest.DeleteMessage) app.Post("/message/:message_id/update", rest.UpdateMessage) + app.Post("/message/:message_id/read", rest.MarkAsRead) return rest } @@ -96,3 +97,22 @@ func (controller *Message) ReactMessage(c *fiber.Ctx) error { Results: response, }) } + +func (controller *Message) MarkAsRead(c *fiber.Ctx) error { + var request message.MarkAsReadRequest + err := c.BodyParser(&request) + utils.PanicIfNeeded(err) + + request.MessageID = c.Params("message_id") + whatsapp.SanitizePhone(&request.Phone) + + response, err := controller.Service.MarkAsRead(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 index 9717e23..2e40aa0 100644 --- a/src/services/message.go +++ b/src/services/message.go @@ -7,6 +7,7 @@ import ( 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" + "github.com/sirupsen/logrus" "go.mau.fi/whatsmeow" "go.mau.fi/whatsmeow/appstate" "go.mau.fi/whatsmeow/proto/waCommon" @@ -27,6 +28,32 @@ func NewMessageService(waCli *whatsmeow.Client) domainMessage.IMessageService { } } +func (service serviceMessage) MarkAsRead(ctx context.Context, request domainMessage.MarkAsReadRequest) (response domainMessage.GenericResponse, err error) { + if err = validations.ValidateMarkAsRead(ctx, request); err != nil { + return response, err + } + dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone) + if err != nil { + return response, err + } + + ids := []types.MessageID{request.MessageID} + if err = service.WaCli.MarkRead(ids, time.Now(), dataWaRecipient, *service.WaCli.Store.ID); err != nil { + return response, err + } + + logrus.Info(map[string]interface{}{ + "phone": request.Phone, + "message_id": request.MessageID, + "chat": dataWaRecipient.String(), + "sender": service.WaCli.Store.ID.String(), + }) + + response.MessageID = request.MessageID + response.Status = fmt.Sprintf("Mark as read success %s", request.MessageID) + return response, nil +} + func (service serviceMessage) ReactMessage(ctx context.Context, request message.ReactionRequest) (response message.GenericResponse, err error) { if err = validations.ValidateReactMessage(ctx, request); err != nil { return response, err diff --git a/src/validations/message_validation.go b/src/validations/message_validation.go index 6e268fd..358cce2 100644 --- a/src/validations/message_validation.go +++ b/src/validations/message_validation.go @@ -8,6 +8,20 @@ import ( validation "github.com/go-ozzo/ozzo-validation/v4" ) +func ValidateMarkAsRead(ctx context.Context, request domainMessage.MarkAsReadRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, + validation.Field(&request.MessageID, validation.Required), + validation.Field(&request.Phone, validation.Required), + ) + + if err != nil { + return pkgError.ValidationError(err.Error()) + } + + return nil + +} + func ValidateRevokeMessage(ctx context.Context, request domainMessage.RevokeRequest) error { err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), diff --git a/src/views/components/GroupManageParticipants.js b/src/views/components/GroupManageParticipants.js index 914114b..3c49ff9 100644 --- a/src/views/components/GroupManageParticipants.js +++ b/src/views/components/GroupManageParticipants.js @@ -10,7 +10,7 @@ export default { }, computed: { group_id() { - return `${this.group}@${window.TYPEGROUP}`; + return `${this.group}${window.TYPEGROUP}`; }, }, methods: {