Skip to content

fix(media): fix video file_type fallback and persist fallback_title on attachments (EVO-999)#47

Merged
dpaes merged 2 commits into
developfrom
fix/EVO-999
May 13, 2026
Merged

fix(media): fix video file_type fallback and persist fallback_title on attachments (EVO-999)#47
dpaes merged 2 commits into
developfrom
fix/EVO-999

Conversation

@marcelogorutuba
Copy link
Copy Markdown
Member

@marcelogorutuba marcelogorutuba commented May 6, 2026

Summary

  • message_type_from_media (Evolution Go handler): falls back to structure-based message_type when Info.MediaType is absent, preventing inbound videos from being stored as file_type=file and rendering as a generic file bubble
  • create_attachment (Evolution Go + Evolution API handlers): persists fallback_title from generate_filename_with_extension so that document/video filenames are displayed in the UI instead of the i18n fallback string "file"

Validation

  • evo-ai-crm-community: ruby -c app/services/whatsapp/evolution_go_handlers/messages_upsert.rb → Syntax OK
  • evo-ai-crm-community: ruby -c app/services/whatsapp/evolution_handlers/attachment_processor.rb → Syntax OK

Changed Files

  • app/services/whatsapp/evolution_go_handlers/messages_upsert.rb
  • app/services/whatsapp/evolution_handlers/attachment_processor.rb

Related PRs

Linked Issue

  • EVO-999

…tachments (EVO-999)

- message_type_from_media: fall back to structure-based message_type when
  Info.MediaType is absent, preventing videos from being stored as file_type=file
- create_attachment (evolution_go + evolution handlers): persist fallback_title
  from generate_filename_with_extension so document filenames are displayed
  instead of the i18n fallback string

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 6, 2026

Reviewer's Guide

Updates WhatsApp Evolution media handling to infer message_type from existing structure when MediaType is missing, and ensures generated filenames are persisted as attachment fallback titles for both Evolution Go and Evolution handlers.

Sequence diagram for updated WhatsApp Evolution Go media handling and attachment creation

sequenceDiagram
  actor WhatsAppUser
  participant WhatsAppAPI
  participant EvolutionGo
  participant MessagesUpsertHandler
  participant ActiveStorageBlob
  participant AttachmentRecord

  WhatsAppUser->>WhatsAppAPI: Send media message (image/video/audio/document)
  WhatsAppAPI->>EvolutionGo: Deliver inbound message payload
  EvolutionGo->>MessagesUpsertHandler: Call handle_message with info and media

  MessagesUpsertHandler->>MessagesUpsertHandler: message_type = message_type
  MessagesUpsertHandler->>MessagesUpsertHandler: media_type = evolution_go_info.dig(MediaType)
  alt MediaType missing or blank
    MessagesUpsertHandler->>MessagesUpsertHandler: struct_type = message_type
    MessagesUpsertHandler->>MessagesUpsertHandler: media_type = struct_type == file ? document : struct_type
  end

  MessagesUpsertHandler->>MessagesUpsertHandler: normalized_type = message_type_from_media(media_type.downcase)

  MessagesUpsertHandler->>ActiveStorageBlob: create_before_direct_upload
  ActiveStorageBlob-->>MessagesUpsertHandler: blob

  MessagesUpsertHandler->>MessagesUpsertHandler: filename = generate_filename_with_extension

  MessagesUpsertHandler->>AttachmentRecord: attachments.build(file_type: file_content_type, fallback_title: filename)
  AttachmentRecord->>ActiveStorageBlob: file.attach(blob)

  Note over AttachmentRecord,WhatsAppUser: Attachment stored with accurate file_type and fallback_title used as UI filename

  AttachmentRecord-->>MessagesUpsertHandler: attachment
  MessagesUpsertHandler-->>EvolutionGo: message persisted with correct media rendering
  EvolutionGo-->>WhatsAppUser: Media appears as image/video/audio/file with filename instead of generic label
Loading

Sequence diagram for updated Evolution attachment processor create_attachment flow

sequenceDiagram
  actor WhatsAppUser
  participant EvolutionBackend
  participant AttachmentProcessor
  participant ActiveStorageBlob
  participant AttachmentRecord

  WhatsAppUser->>EvolutionBackend: Send media message
  EvolutionBackend->>AttachmentProcessor: Process attachment_file

  AttachmentProcessor->>ActiveStorageBlob: create_before_direct_upload
  ActiveStorageBlob-->>AttachmentProcessor: blob

  AttachmentProcessor->>AttachmentProcessor: filename = generate_filename_with_extension

  AttachmentProcessor->>AttachmentRecord: attachments.build(file_type: file_content_type, fallback_title: filename)
  AttachmentRecord->>ActiveStorageBlob: file.attach(blob)

  AttachmentRecord-->>AttachmentProcessor: attachment with fallback_title
  AttachmentProcessor-->>EvolutionBackend: attachment ready for message
  EvolutionBackend-->>WhatsAppUser: UI shows media bubble with generated filename
Loading

Class diagram for updated WhatsApp Evolution media handlers

classDiagram
  class MessagesUpsertHandler {
    - evolution_go_info
    + file_content_type() String
    + message_type() String
    + message_type_from_media() String
    + generate_filename_with_extension() String
    + create_attachment(attachment_file) Attachment
  }

  class AttachmentProcessor {
    - message
    + file_content_type() String
    + generate_filename_with_extension() String
    + create_attachment(attachment_file) Attachment
  }

  class Attachment {
    + file_type String
    + fallback_title String
    + file Blob
  }

  class Message {
    + attachments Attachment[*]
  }

  class ActiveStorageBlob {
    + create_before_direct_upload(filename, byte_size, checksum, content_type) ActiveStorageBlob
  }

  MessagesUpsertHandler --> Message : builds
  AttachmentProcessor --> Message : builds
  Message "1" --> "*" Attachment : has_many
  Attachment --> ActiveStorageBlob : attaches file
  MessagesUpsertHandler ..> ActiveStorageBlob : uses
  AttachmentProcessor ..> ActiveStorageBlob : uses
Loading

File-Level Changes

Change Details Files
Improve media message_type inference when Evolution Go MediaType is missing or inconsistent.
  • Use safe dig access for MediaType from @evolution_go_info to avoid errors when the key or hash is missing.
  • Fallback to the existing struct-based message_type when MediaType is blank, mapping a struct type of 'file' to a media_type of 'document'.
  • Normalize media_type with downcase before mapping to internal message_type values.
  • Extend the case mapping to explicitly handle document/file and sticker types, defaulting all unknown types to 'file'.
app/services/whatsapp/evolution_go_handlers/messages_upsert.rb
Persist generated filenames as attachment fallback_title so the UI shows meaningful document/video names instead of a generic label.
  • When building a new attachment, pass fallback_title: generate_filename_with_extension alongside file_type.
  • Apply the same fallback_title behavior in both Evolution Go and Evolution handlers to keep attachment behavior consistent.
app/services/whatsapp/evolution_go_handlers/messages_upsert.rb
app/services/whatsapp/evolution_handlers/attachment_processor.rb

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 left some high level feedback:

  • In create_attachment, generate_filename_with_extension is now used for fallback_title; if this method has any non-determinism (timestamps, random suffixes), consider computing it once and reusing the same value for both blob filename and fallback title to avoid mismatches.
  • In message_type_from_media, the struct_type == 'file' ? 'document' : struct_type reassignment is later normalized back to 'file' in the case statement; if this distinction is important for other callers it might be worth adding a brief comment explaining why the intermediate 'document' value is needed, otherwise it could be simplified.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `create_attachment`, `generate_filename_with_extension` is now used for `fallback_title`; if this method has any non-determinism (timestamps, random suffixes), consider computing it once and reusing the same value for both blob filename and fallback title to avoid mismatches.
- In `message_type_from_media`, the `struct_type == 'file' ? 'document' : struct_type` reassignment is later normalized back to `'file'` in the case statement; if this distinction is important for other callers it might be worth adding a brief comment explaining why the intermediate `'document'` value is needed, otherwise it could be simplified.

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.

- Propagate fallback_title to Z-API, Notificame, and conversation sync handlers
- Fix nil guard in audio_voice_note? to prevent NoMethodError when evolution_go_info is nil
- Fix Notificame fallback_title to strip query params via URI.parse
- Add spec for message_type_from_media with nil/blank MediaType (all struct types)
- Update attachment_processor_spec to assert fallback_title in build call

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dpaes dpaes merged commit 9d82b0d into develop May 13, 2026
1 check passed
@dpaes dpaes deleted the fix/EVO-999 branch May 13, 2026 21:41
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