Skip to content

Commit 0ba5829

Browse files
authored
fixes #1978 [WhatsApp]: fix message deserialization errors (#1979)
1 parent 13db252 commit 0ba5829

File tree

6 files changed

+101
-8
lines changed

6 files changed

+101
-8
lines changed

bot/connector-whatsapp-cloud/src/main/kotlin/WhatsAppConnectorCloudConnector.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class WhatsAppConnectorCloudConnector internal constructor(
9494
val verifyTokenMeta = queryParams.get("hub.verify_token")
9595
val challenge = queryParams.get("hub.challenge")
9696
if (modeHub == WEBHOOK_SUBSCRIBE_MODE && verifyToken == verifyTokenMeta) {
97-
logger.info("WEBHOOK_VERIFIED")
97+
logger.info { "WhatsApp Cloud API webhook verified for $connectorId" }
9898
context.response().setStatusCode(200).end(challenge)
9999
} else {
100100
context.response().end("Invalid verify token")
@@ -113,7 +113,6 @@ class WhatsAppConnectorCloudConnector internal constructor(
113113
val requestTimerData = BotRepository.requestTimer.start("whatsapp_cloud_webhook")
114114
try {
115115
val body = context.body().asString()
116-
logger.info { body }
117116
val requestBody = mapper.readValue<WebHookEventReceiveMessage>(body)
118117

119118
handleWebHook(requestBody, controller)
@@ -136,12 +135,10 @@ class WhatsAppConnectorCloudConnector internal constructor(
136135
val requestTimerData = BotRepository.requestTimer.start("whatsapp_cloud_create_template")
137136
try {
138137
val body = context.body().asString()
139-
logger.info { body }
138+
logger.debug { "creating template: $body" }
140139
val requestBody = mapper.readValue<WhatsappTemplate>(body)
141140

142141
whatsAppCloudApiService.createOrUpdateTemplate(requestBody)
143-
144-
logger.info { "ok" }
145142
} catch (e: Throwable) {
146143
logger.logError(e, requestTimerData)
147144
} finally {
@@ -213,6 +210,7 @@ class WhatsAppConnectorCloudConnector internal constructor(
213210
change.value.messages.filter {
214211
restrictedPhoneNumbers?.contains(it.from) ?: true
215212
}.forEach { message: WhatsAppCloudMessage ->
213+
logger.debug { "received message $message" }
216214
executor.executeBlocking {
217215
val event = WebhookActionConverter.toEvent(message, connectorId, whatsAppCloudApiService)
218216
if (event != null) {

bot/connector-whatsapp-cloud/src/main/kotlin/model/webhook/message/WhatsAppCloudAudioMessage.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ data class WhatsAppCloudAudioMessage(
2929
override val context: ContextContent? = null,
3030
override val referral: Referral? = null,
3131
override val errors: List<ErrorItem>? = emptyList(),
32-
) : WhatsAppCloudMessage(WhatsAppCloudMessageType.text)
32+
) : WhatsAppCloudMessage(WhatsAppCloudMessageType.audio)

bot/connector-whatsapp-cloud/src/main/kotlin/model/webhook/message/WhatsAppCloudDocumentMessage.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import ai.tock.bot.connector.whatsapp.cloud.model.webhook.message.content.ErrorI
2222
import ai.tock.bot.connector.whatsapp.cloud.model.webhook.message.content.Referral
2323

2424
data class WhatsAppCloudDocumentMessage(
25-
val text: DocumentContent,
25+
val text: DocumentContent?,
2626
override val id: String,
2727
override val from: String,
2828
override val timestamp: String,

bot/connector-whatsapp-cloud/src/main/kotlin/model/webhook/message/WhatsAppCloudMessage.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo
2626
use = JsonTypeInfo.Id.NAME,
2727
include = JsonTypeInfo.As.EXISTING_PROPERTY,
2828
property = "type",
29+
visible = true,
30+
defaultImpl = WhatsAppCloudUnknownMessage::class,
2931
)
3032
@JsonSubTypes(
3133
JsonSubTypes.Type(value = WhatsAppCloudTextMessage::class, name = "text"),
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (C) 2017/2025 SNCF Connect & Tech
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package ai.tock.bot.connector.whatsapp.cloud.model.webhook.message
18+
19+
import ai.tock.bot.connector.whatsapp.cloud.model.webhook.message.content.ContextContent
20+
import ai.tock.bot.connector.whatsapp.cloud.model.webhook.message.content.ErrorItem
21+
import ai.tock.bot.connector.whatsapp.cloud.model.webhook.message.content.Referral
22+
import com.fasterxml.jackson.annotation.JsonAnyGetter
23+
import com.fasterxml.jackson.annotation.JsonAnySetter
24+
import com.fasterxml.jackson.annotation.JsonProperty
25+
26+
/**
27+
* Unsupported or unknown message
28+
*/
29+
data class WhatsAppCloudUnknownMessage(
30+
override val id: String,
31+
override val from: String,
32+
override val timestamp: String,
33+
override val context: ContextContent? = null,
34+
override val referral: Referral? = null,
35+
override val errors: List<ErrorItem>? = emptyList(),
36+
@JsonProperty("type")
37+
val rawType: String = WhatsAppCloudMessageType.unknown.name,
38+
@JsonAnySetter
39+
@JsonAnyGetter
40+
val additionalProperties: MutableMap<String, Any> = mutableMapOf(),
41+
) : WhatsAppCloudMessage(WhatsAppCloudMessageType.unknown)

bot/connector-whatsapp-cloud/src/test/kotlin/model/webhook/WhatsAppCloudMessagesDeserializationTest.kt

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,56 @@
1616

1717
package model.webhook
1818

19-
class WhatsAppCloudMessagesDeserializationTest
19+
import ai.tock.bot.connector.whatsapp.cloud.model.common.TextContent
20+
import ai.tock.bot.connector.whatsapp.cloud.model.webhook.message.WhatsAppCloudMessage
21+
import ai.tock.bot.connector.whatsapp.cloud.model.webhook.message.WhatsAppCloudTextMessage
22+
import ai.tock.bot.connector.whatsapp.cloud.model.webhook.message.WhatsAppCloudUnknownMessage
23+
import ai.tock.shared.jackson.mapper
24+
import com.fasterxml.jackson.module.kotlin.readValue
25+
import org.junit.jupiter.api.Assertions.assertEquals
26+
import org.junit.jupiter.api.Test
27+
import org.junit.jupiter.api.assertNotNull
28+
import java.time.Instant
29+
30+
class WhatsAppCloudMessagesDeserializationTest {
31+
@Test
32+
fun testMessageWebhookDeserialization() {
33+
val m =
34+
WhatsAppCloudTextMessage(
35+
text = TextContent("Hello, World!"),
36+
id = "aaa",
37+
from = "bbb",
38+
timestamp = Instant.now().toString(),
39+
)
40+
val s = mapper.writeValueAsString(m)
41+
assertEquals(m, mapper.readValue<WhatsAppCloudMessage>(s))
42+
}
43+
44+
@Test
45+
fun testUnknownMessageDeserialization() {
46+
val m =
47+
WhatsAppCloudUnknownMessage(
48+
id = "aaa",
49+
from = "bbb",
50+
timestamp = "2025-12-30T10:50:52.355219Z",
51+
rawType = "unsupported",
52+
additionalProperties =
53+
mutableMapOf(
54+
"thing" to "Hello, World!",
55+
),
56+
)
57+
val s =
58+
"""
59+
{
60+
"thing" : "Hello, World!",
61+
"id" : "aaa",
62+
"from" : "bbb",
63+
"timestamp" : "2025-12-30T10:50:52.355219Z",
64+
"errors" : [ ],
65+
"type" : "unsupported"
66+
}
67+
""".trimIndent()
68+
assertNotNull(mapper.writeValueAsString(m))
69+
assertEquals(m, mapper.readValue<WhatsAppCloudMessage>(s))
70+
}
71+
}

0 commit comments

Comments
 (0)