Skip to content

SetPresence#23

Closed
brunobeise wants to merge 5 commits intoEvolutionAPI:mainfrom
brunobeise:imobdeal-patches
Closed

SetPresence#23
brunobeise wants to merge 5 commits intoEvolutionAPI:mainfrom
brunobeise:imobdeal-patches

Conversation

@brunobeise
Copy link
Copy Markdown

@brunobeise brunobeise commented Apr 13, 2026

Description

Related Issue

Closes #(issue_number)

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement

Testing

  • Manual testing completed
  • Functionality verified in development environment
  • No breaking changes introduced

Screenshots (if applicable)

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have tested my changes thoroughly
  • Any dependent changes have been merged and published

Additional Notes

Summary by Sourcery

Add support for managing WhatsApp presence state via the API and fix message editing compatibility with previously sent messages.

New Features:

  • Expose an HTTP endpoint to set an instance's presence state to available or unavailable without disconnecting the session.

Bug Fixes:

  • Adjust message editing to use ExtendedTextMessage so edits are applied correctly to messages originally sent as extended text.

Enhancements:

  • Extend the instance service and handler interfaces to support presence management and wire the new presence route into the API router.

Bruno Beise added 2 commits April 13, 2026 19:38
WhatsApp silently ignores edits when the message type differs from
the original. SendText sends as ExtendedTextMessage, so edits must
match that type instead of Conversation.

This patch matches the fix already deployed in production via SSH
on 2026-04-07.
Adds a new authenticated endpoint to expose whatsmeow's SendPresence
function so the client can be marked as available/unavailable without
disconnecting.

This mirrors WhatsApp Web's behavior when minimized — the linked
device stays connected but the phone resumes receiving push
notifications because WhatsApp server sees the device as inactive.

Use case: ImobDeal marks the instance unavailable when the user
leaves the WhatsApp screen, and available when they return. Enables
brokers on iPhone to receive normal push notifications without
having to manually unlink the device.

- POST /instance/presence with {"state": "available" | "unavailable"}
- Returns 400 on invalid state, 500 on internal error
- Requires the standard instance auth (apikey header)
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Apr 13, 2026

Reviewer's Guide

Adds a new presence management capability for WhatsApp instances via an HTTP endpoint and fixes message editing to use the same message type as original sends so edits are honored by WhatsApp.

Sequence diagram for the new /instance/presence HTTP endpoint

sequenceDiagram
    actor ApiClient
    participant GinRouter
    participant InstanceHandler
    participant InstanceService
    participant WhatsmeowClient
    participant Logger

    ApiClient->>GinRouter: POST /instance/presence { state }
    GinRouter->>InstanceHandler: SetPresence(ctx)
    InstanceHandler->>InstanceHandler: ctx.MustGet(instance)
    InstanceHandler->>InstanceHandler: ctx.ShouldBindJSON(SetPresenceStruct)
    InstanceHandler->>InstanceService: SetPresence(data, instance)

    InstanceService->>InstanceService: ensureClientConnected(instance.Id)
    InstanceService->>WhatsmeowClient: IsConnected()
    InstanceService->>WhatsmeowClient: IsLoggedIn()
    InstanceService->>WhatsmeowClient: SendPresence(state)
    WhatsmeowClient-->>InstanceService: result

    InstanceService->>Logger: LogInfo("Presence set to state")
    InstanceService-->>InstanceHandler: nil
    InstanceHandler-->>ApiClient: 200 { message: success, state }
Loading

File-Level Changes

Change Details Files
Expose WhatsApp presence control as a service method and HTTP endpoint.
  • Extend InstanceService interface with a SetPresence method that accepts a state payload.
  • Introduce SetPresenceStruct to validate incoming presence state as required JSON field.
  • Implement instances.SetPresence to ensure client is connected/logged-in, map string state to whatsmeow Presence values, send presence, and log success/failure.
  • Add SetPresence handler that resolves the instance from context, binds/validates JSON payload, delegates to service, and returns appropriate HTTP responses.
  • Register POST /instance/presence route to the new handler in the routes configuration.
pkg/instance/service/instance_service.go
pkg/instance/handler/instance_handler.go
pkg/routes/routes.go
Align EditMessage behavior with SendText by using ExtendedTextMessage instead of Conversation so edits are applied.
  • Change the EditMessage implementation to send a waE2E.Message with ExtendedTextMessage.Text instead of Conversation when editing messages.
  • Preserve existing logging and error handling behavior around the SendMessage call.
pkg/message/service/message_service.go

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

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

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 SetPresence, invalid presence state values currently bubble up from the service as a 500; consider classifying this as a client error (e.g., validate in the handler or inspect the error and return 400) so the API contract better reflects misuse vs server failure.
  • The new SetPresence and EditMessage flows use context.Background() for WhatsApp client calls; passing a request-scoped context (e.g., derived from the gin context) would allow cancellations/timeouts to propagate correctly.
  • The log message in EditMessage still says error revoking message, which is misleading for an edit operation; update the message to reflect that the edit failed.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `SetPresence`, invalid presence state values currently bubble up from the service as a 500; consider classifying this as a client error (e.g., validate in the handler or inspect the error and return 400) so the API contract better reflects misuse vs server failure.
- The new `SetPresence` and `EditMessage` flows use `context.Background()` for WhatsApp client calls; passing a request-scoped context (e.g., derived from the gin context) would allow cancellations/timeouts to propagate correctly.
- The log message in `EditMessage` still says `error revoking message`, which is misleading for an edit operation; update the message to reflect that the edit failed.

## Individual Comments

### Comment 1
<location path="pkg/instance/handler/instance_handler.go" line_range="237-238" />
<code_context>
+		return
+	}
+
+	if err := i.instanceService.SetPresence(&data, instance); err != nil {
+		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+		return
+	}
</code_context>
<issue_to_address>
**🚨 issue (security):** Map validation-style errors to 4xx and avoid returning raw internal error messages to clients.

Currently any `SetPresence` error results in a 500 with `err.Error()` in the response. That causes two problems: user-input errors (e.g. invalid state) should be 4xx and are documented as 400 in Swagger, and exposing `err.Error()` may leak internal details.

It’d be better to distinguish validation vs internal errors (e.g. via sentinel errors or a small error type), then:
- return 400 with a client-facing message for invalid input/state, and
- return 500 with a generic message for unexpected/internal errors, logging the detailed error server-side instead of returning it.
</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.

- SetPresence: validate state in HTTP handler so invalid input returns
  400 instead of bubbling up to 500. Service layer now trusts its input
  and any error it emits is treated as 5xx.

- SetPresence: accept a request-scoped context.Context parameter so
  cancellations/timeouts from the HTTP layer propagate down to whatsmeow's
  SendPresence call, instead of using context.Background().

- EditMessage: fix misleading log message — was 'error revoking message',
  now reads 'error editing message'.
@brunobeise brunobeise closed this Apr 13, 2026
@brunobeise brunobeise reopened this Apr 13, 2026
These files are used by developers to run Evolution Go locally with
docker-compose without touching the Dockerfile or affecting the
upstream repo. Keep them out of the fork so they don't conflict with
a potential future upstream docker-compose setup.
@brunobeise brunobeise changed the title Imobdeal patches SetPresence Apr 14, 2026
@brunobeise brunobeise closed this Apr 14, 2026
@brunobeise brunobeise deleted the imobdeal-patches branch April 14, 2026 13:48
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.

1 participant