Skip to content

Comments

DEVEXP-795: Conversation Webhooks#122

Open
matsk-sinch wants to merge 3 commits intov2.0from
DEVEXP-795_Conversation-Webhooks
Open

DEVEXP-795: Conversation Webhooks#122
matsk-sinch wants to merge 3 commits intov2.0from
DEVEXP-795_Conversation-Webhooks

Conversation

@matsk-sinch
Copy link
Contributor

No description provided.


def conversation_event(self):
headers = dict(request.headers)
body_str = request.raw_body.decode("utf-8") if request.raw_body else ""

Choose a reason for hiding this comment

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

Here assuming that content-type header is not present or do not contains charset value.
(current deployed backend do not specify any charset today, so fallback to UTF8 is fine)
Ideally body should be decoded according to content-type + charset and fallback to utf-8 only if not set

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented

Copy link

@JPPortier JPPortier Feb 19, 2026

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed, moved under models/

Comment on lines 52 to 54
channel_metadata: Optional[Any] = Field(
default=None,
description="Additional metadata from the channel.",

Choose a reason for hiding this comment

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

Specification are not defining it as a common field all webhooks events

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed

default=None,
description="The ID of the conversation.",
)
status: Optional[StrictStr] = Field(

Choose a reason for hiding this comment

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

Specification are containing a list of supported values.

They should be used to create an enum

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just created MessageDeliveryStatus

default=None,
description="The ID of the contact. Empty if processing_mode is DISPATCH.",
)
submitted_message: Optional[Any] = Field(

Choose a reason for hiding this comment

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

According to specs, should be an AppMessage no ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, fixed :)

if not secret:
return False
if isinstance(payload, bytes):
payload = payload.decode("utf-8")

Choose a reason for hiding this comment

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

Same point about not processing content-type to get charset to decode payload

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Comment on lines 140 to 141
if not _has_fetched_event(context):
return

Choose a reason for hiding this comment

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

Could this conduce to a false positive during test ? (same at multiple location)

I mean: if there is never _has_fetched_event returning true, then test will be ok right ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it's returning FPs.
I will have to refactor this logic for now, and will parametrize again when other statuses are implemented.

Comment on lines 14 to 36
def process_event(context, response):
context.formatted_headers = dict(response.headers)
context.raw_event = response.text
context.event = context.conversation_webhooks.parse_event(context.raw_event)


def _fetch_and_process(context, path_suffix):
base_url = context.sinch.configuration.conversation_origin
url = f"{base_url}/webhooks/conversation/{path_suffix}"
response = requests.get(url)
process_event(context, response)


def _has_fetched_event(context):
return getattr(context, "raw_event", None) is not None


def _submitted_has(submitted, key):
if submitted is None:
return False
if isinstance(submitted, dict):
return key in submitted and submitted[key] is not None
return getattr(submitted, key, None) is not None

Choose a reason for hiding this comment

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

This pattern is different from the ones with other domains but there is crossover between them.

This should be part of a common "utility" helpers for e2e

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to helpers.py

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.

3 participants