fix(gateway): classify email document attachments as DOCUMENT
Email cached document attachments and placed them in media_urls, but msg_type only flipped on image attachments — documents stayed TEXT and run.py's document-context injection (gated on MessageType.DOCUMENT) silently dropped them. Same bug class as Signal #12845. DOCUMENT wins over PHOTO for mixed attachments since image handling keys off per-path mime types while document injection gates strictly on message_type.
This commit is contained in:
@@ -470,8 +470,15 @@ class EmailAdapter(BasePlatformAdapter):
|
|||||||
for att in attachments:
|
for att in attachments:
|
||||||
media_urls.append(att["path"])
|
media_urls.append(att["path"])
|
||||||
media_types.append(att["media_type"])
|
media_types.append(att["media_type"])
|
||||||
if att["type"] == "image":
|
if att["type"] == "image" and msg_type == MessageType.TEXT:
|
||||||
msg_type = MessageType.PHOTO
|
msg_type = MessageType.PHOTO
|
||||||
|
elif att["type"] == "document":
|
||||||
|
# Document wins over PHOTO for mixed attachments: run.py's
|
||||||
|
# image handling keys off the per-path image/* mime type
|
||||||
|
# regardless of message_type, but document-context injection
|
||||||
|
# gates strictly on MessageType.DOCUMENT — so DOCUMENT is the
|
||||||
|
# only classification that surfaces both.
|
||||||
|
msg_type = MessageType.DOCUMENT
|
||||||
|
|
||||||
# Store thread context for reply threading
|
# Store thread context for reply threading
|
||||||
self._thread_context[sender_addr] = {
|
self._thread_context[sender_addr] = {
|
||||||
|
|||||||
@@ -393,6 +393,68 @@ class TestDispatchMessage(unittest.TestCase):
|
|||||||
self.assertEqual(captured_events[0].message_type, MessageType.PHOTO)
|
self.assertEqual(captured_events[0].message_type, MessageType.PHOTO)
|
||||||
self.assertEqual(captured_events[0].media_urls, ["/tmp/img.jpg"])
|
self.assertEqual(captured_events[0].media_urls, ["/tmp/img.jpg"])
|
||||||
|
|
||||||
|
def test_document_attachment_sets_document_type(self):
|
||||||
|
"""Email with a document attachment must set DOCUMENT so run.py injects file context."""
|
||||||
|
import asyncio
|
||||||
|
from gateway.platforms.base import MessageType
|
||||||
|
adapter = self._make_adapter()
|
||||||
|
captured_events = []
|
||||||
|
|
||||||
|
async def capture_handle(event):
|
||||||
|
captured_events.append(event)
|
||||||
|
|
||||||
|
adapter.handle_message = capture_handle
|
||||||
|
|
||||||
|
msg_data = {
|
||||||
|
"uid": b"6",
|
||||||
|
"sender_addr": "user@test.com",
|
||||||
|
"sender_name": "User",
|
||||||
|
"subject": "Re: report",
|
||||||
|
"message_id": "<msg6@test.com>",
|
||||||
|
"in_reply_to": "",
|
||||||
|
"body": "See attached",
|
||||||
|
"attachments": [{"path": "/tmp/report.pdf", "filename": "report.pdf", "type": "document", "media_type": "application/pdf"}],
|
||||||
|
"date": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
asyncio.run(adapter._dispatch_message(msg_data))
|
||||||
|
self.assertEqual(len(captured_events), 1)
|
||||||
|
self.assertEqual(captured_events[0].message_type, MessageType.DOCUMENT)
|
||||||
|
self.assertEqual(captured_events[0].media_urls, ["/tmp/report.pdf"])
|
||||||
|
|
||||||
|
def test_mixed_image_and_document_prefers_document(self):
|
||||||
|
"""DOCUMENT wins for mixed attachments — image handling keys off per-path
|
||||||
|
mime types, but document injection gates strictly on MessageType.DOCUMENT."""
|
||||||
|
import asyncio
|
||||||
|
from gateway.platforms.base import MessageType
|
||||||
|
adapter = self._make_adapter()
|
||||||
|
captured_events = []
|
||||||
|
|
||||||
|
async def capture_handle(event):
|
||||||
|
captured_events.append(event)
|
||||||
|
|
||||||
|
adapter.handle_message = capture_handle
|
||||||
|
|
||||||
|
msg_data = {
|
||||||
|
"uid": b"7",
|
||||||
|
"sender_addr": "user@test.com",
|
||||||
|
"sender_name": "User",
|
||||||
|
"subject": "Re: both",
|
||||||
|
"message_id": "<msg7@test.com>",
|
||||||
|
"in_reply_to": "",
|
||||||
|
"body": "Photo and PDF",
|
||||||
|
"attachments": [
|
||||||
|
{"path": "/tmp/img.jpg", "filename": "img.jpg", "type": "image", "media_type": "image/jpeg"},
|
||||||
|
{"path": "/tmp/report.pdf", "filename": "report.pdf", "type": "document", "media_type": "application/pdf"},
|
||||||
|
],
|
||||||
|
"date": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
asyncio.run(adapter._dispatch_message(msg_data))
|
||||||
|
self.assertEqual(len(captured_events), 1)
|
||||||
|
self.assertEqual(captured_events[0].message_type, MessageType.DOCUMENT)
|
||||||
|
self.assertEqual(len(captured_events[0].media_urls), 2)
|
||||||
|
|
||||||
def test_source_built_correctly(self):
|
def test_source_built_correctly(self):
|
||||||
"""Session source should have correct chat_id and user info."""
|
"""Session source should have correct chat_id and user info."""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|||||||
Reference in New Issue
Block a user