Skip to content

feat(message): add POST /message/markplayed endpoint (played receipt / blue mic)#96

Open
brunohenriquecontente wants to merge 1 commit into
evolution-foundation:developfrom
brunohenriquecontente:feat/markplayed-receipt-clean
Open

feat(message): add POST /message/markplayed endpoint (played receipt / blue mic)#96
brunohenriquecontente wants to merge 1 commit into
evolution-foundation:developfrom
brunohenriquecontente:feat/markplayed-receipt-clean

Conversation

@brunohenriquecontente

@brunohenriquecontente brunohenriquecontente commented Jun 29, 2026

Copy link
Copy Markdown

O que

Adiciona o endpoint POST /message/markplayed — marca uma mensagem de áudio como reproduzida (mic azul / played receipt), via client.MarkRead(..., types.ReceiptTypePlayed).

Segue exatamente o padrão do MarkRead existente:

  • pkg/message/service/message_service.goMarkPlayedStruct{Id []string, Number string} + MarkPlayed(...)
  • pkg/message/handler/message_handler.go — handler MarkPlayed (valida number + id)
  • pkg/routes/routes.goPOST /markplayed com ValidateNumberField()

Por que esta PR substitui a #46

A #46 apontava pra main a partir de uma base desatualizada e arrastava ~56 arquivos de ruído (rename da org, sync de submódulos, bundles do manager, swagger). Esta PR é a mesma mudança isolada (3 arquivos, +81/−0) rebaseada em cima de develop, conforme review do @NeritonDias.

Pendente

  • Regenerar swagger (swag init -g cmd/evolution-go/main.go) — annotation @Router /message/markplayed já está no handler.

Summary by Sourcery

Add support for marking audio messages as played via a new POST /message/markplayed endpoint.

New Features:

  • Expose POST /message/markplayed API to register played receipts for audio messages.

Enhancements:

  • Extend message service and handler interfaces with a MarkPlayed operation aligned with existing read receipt handling.

Documentation:

  • Add Swagger annotations documenting the new /message/markplayed endpoint.

@sourcery-ai

sourcery-ai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a new POST /message/markplayed endpoint that mirrors the existing MarkRead flow to mark audio messages as played, wiring handler, service, and routing with validation and swagger annotations.

Sequence diagram for POST /message/markplayed audio played receipt flow

sequenceDiagram
    actor Client
    participant GinRouter as GinRouter
    participant JIDValidationMiddleware as JIDValidationMiddleware
    participant MessageHandler as MessageHandler
    participant MessageService as MessageService
    participant WhatsAppClient as WhatsAppClient

    Client->>GinRouter: POST /message/markplayed
    GinRouter->>JIDValidationMiddleware: ValidateNumberField
    JIDValidationMiddleware-->>GinRouter: ok / error
    GinRouter->>MessageHandler: MarkPlayed(ctx)
    MessageHandler->>MessageService: MarkPlayed(data, instance)
    MessageService->>MessageService: ensureClientConnected(instance.Id)
    MessageService->>MessageService: utils.ParseJID(data.Number)
    MessageService->>WhatsAppClient: MarkRead(context.Background(), data.Id, time.Now(), jid, jid, types.ReceiptTypePlayed)
    WhatsAppClient-->>MessageService: result / error
    MessageService-->>MessageHandler: timestamp / error
    MessageHandler-->>Client: 200 success with timestamp / error JSON
Loading

File-Level Changes

Change Details Files
Introduce MarkPlayed flow in message service to emit played receipts via WhatsApp client.
  • Extend MessageService interface with MarkPlayed method returning a timestamp string
  • Add MarkPlayedStruct payload type with id list and number fields
  • Implement MarkPlayed to validate JID from number, call client.MarkRead with ReceiptTypePlayed, and log/normalize errors
pkg/message/service/message_service.go
Expose MarkPlayed HTTP handler with input validation and swagger documentation.
  • Extend MessageHandler interface to include MarkPlayed
  • Add MarkPlayed handler that binds JSON to MarkPlayedStruct, validates number and id, retrieves instance, calls service.MarkPlayed, and returns timestamp in a standard success envelope
  • Annotate handler with swagger metadata, including @router /message/markplayed [post]
pkg/message/handler/message_handler.go
Register new /message/markplayed route under existing message group with number validation middleware.
  • Wire POST /markplayed to jidValidationMiddleware.ValidateNumberField and messageHandler.MarkPlayed within the message routes group
pkg/routes/routes.go

Possibly linked issues

  • #[Feature] Novo endpoint POST /message/markplayed (microfone azul em áudios): The PR adds POST /message/markplayed with MarkPlayed service/handler, exactly implementing the issue’s played receipt request.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In MarkPlayed, the ts variable is declared but never assigned before being returned, so the endpoint will always return the zero time string; consider mirroring MarkRead by assigning ts = time.Now() and using that both for the client call and response.
  • The error log message in MarkPlayed (Error validating message fields) is slightly misleading since only the phone number is validated at that point; consider making this log clearer or logging the actual invalid value to aid debugging.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `MarkPlayed`, the `ts` variable is declared but never assigned before being returned, so the endpoint will always return the zero time string; consider mirroring `MarkRead` by assigning `ts = time.Now()` and using that both for the client call and response.
- The error log message in `MarkPlayed` (`Error validating message fields`) is slightly misleading since only the phone number is validated at that point; consider making this log clearer or logging the actual invalid value to aid debugging.

## Individual Comments

### Comment 1
<location path="pkg/message/service/message_service.go" line_range="273-264" />
<code_context>
+		return "", err
+	}
+
+	var ts time.Time
+
+	jid, ok := utils.ParseJID(data.Number)
+	if !ok {
+		m.loggerWrapper.GetLogger(instance.Id).LogError("[%s] Error validating message fields", instance.Id)
+		return "", errors.New("invalid phone number")
+	}
+
+	err = client.MarkRead(context.Background(), data.Id, time.Now(), jid, jid, types.ReceiptTypePlayed)
+	if err != nil {
+		m.loggerWrapper.GetLogger(instance.Id).LogError("[%s] error marking message as played: %v", instance.Id, err)
+		return "", errors.New("error marking message as played")
+	}
+
+	return ts.String(), nil
+}
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Return value for timestamp is always zero-time because `ts` is never set.

In `MarkPlayed`, `ts` is declared but never assigned, so `ts.String()` will always return the zero time (`0001-01-01 ...`), which is inconsistent with `MarkRead` and likely incorrect. If you need to return the time the message was marked as played, set `ts := time.Now()` and use it both in the `MarkRead` call and for the return value. If no timestamp is needed, remove `ts` and adjust the return accordingly.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -258,6 +264,29 @@ func (m *messageService) MarkRead(data *MarkReadStruct, instance *instance_model
return ts.String(), nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Return value for timestamp is always zero-time because ts is never set.

In MarkPlayed, ts is declared but never assigned, so ts.String() will always return the zero time (0001-01-01 ...), which is inconsistent with MarkRead and likely incorrect. If you need to return the time the message was marked as played, set ts := time.Now() and use it both in the MarkRead call and for the return value. If no timestamp is needed, remove ts and adjust the return accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants