Skip to content

Commit 4277ed8

Browse files
authored
feat: Add work objects support (#1783)
1 parent 998ee04 commit 4277ed8

File tree

8 files changed

+1747
-14
lines changed

8 files changed

+1747
-14
lines changed

integration_tests/web/test_message_metadata.py

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,32 @@
22
import os
33
import time
44
import unittest
5+
import json
56

67
from integration_tests.env_variable_names import SLACK_SDK_TEST_BOT_TOKEN
7-
from slack_sdk.models.metadata import Metadata
8+
from slack_sdk.models.metadata import (
9+
Metadata,
10+
EventAndEntityMetadata,
11+
EntityMetadata,
12+
ExternalRef,
13+
EntityPayload,
14+
EntityAttributes,
15+
EntityTitle,
16+
TaskEntityFields,
17+
EntityStringField,
18+
EntityTitle,
19+
EntityAttributes,
20+
EntityFullSizePreview,
21+
TaskEntityFields,
22+
EntityTypedField,
23+
EntityStringField,
24+
EntityTimestampField,
25+
EntityEditSupport,
26+
EntityEditTextConfig,
27+
EntityCustomField,
28+
EntityUserIDField,
29+
ExternalRef,
30+
)
831
from slack_sdk.web import WebClient
932

1033

@@ -125,3 +148,97 @@ def test_publishing_message_metadata_using_models(self):
125148
)
126149
self.assertIsNone(scheduled.get("error"))
127150
self.assertIsNotNone(scheduled.get("message").get("metadata"))
151+
152+
def test_publishing_entity_metadata(self):
153+
client: WebClient = WebClient(token=self.bot_token)
154+
new_message = client.chat_postMessage(
155+
channel="C014KLZN9M0",
156+
text="Message with entity metadata",
157+
metadata={
158+
"entities": [
159+
{
160+
"entity_type": "slack#/entities/task",
161+
"url": "https://abc.com/123",
162+
"external_ref": {"id": "123"},
163+
"entity_payload": {
164+
"attributes": {"title": {"text": "My task"}, "product_name": "We reference only"},
165+
"fields": {
166+
"due_date": {"value": "2026-06-06", "type": "slack#/types/date", "edit": {"enabled": True}},
167+
"created_by": {"type": "slack#/types/user", "user": {"user_id": "U014KLZE350"}},
168+
"date_created": {"value": 1760629278},
169+
},
170+
"custom_fields": [
171+
{
172+
"label": "img",
173+
"key": "img",
174+
"type": "slack#/types/image",
175+
"image_url": "https://s3-media2.fl.yelpcdn.com/bphoto/korel-1YjNtFtJlMTaC26A/o.jpg",
176+
}
177+
],
178+
},
179+
}
180+
]
181+
},
182+
)
183+
184+
self.assertIsNone(new_message.get("error"))
185+
self.assertIsNone(new_message.get("warning"))
186+
187+
def test_publishing_entity_metadata_using_models(self):
188+
# Build the metadata
189+
190+
title = EntityTitle(text="My title")
191+
full_size_preview = EntityFullSizePreview(
192+
is_supported=True,
193+
preview_url="https://s3-media3.fl.yelpcdn.com/bphoto/c7ed05m9lC2EmA3Aruue7A/o.jpg",
194+
mime_type="image/jpeg",
195+
)
196+
attributes = EntityAttributes(title=title, product_name="My Product", full_size_preview=full_size_preview)
197+
description = EntityStringField(
198+
value="Description of the task.",
199+
long=True,
200+
edit=EntityEditSupport(enabled=True, text=EntityEditTextConfig(min_length=5, max_length=100)),
201+
)
202+
due_date = EntityTypedField(value="2026-06-06", type="slack#/types/date", edit=EntityEditSupport(enabled=True))
203+
created_by = EntityTypedField(
204+
type="slack#/types/user",
205+
user=EntityUserIDField(user_id="USLACKBOT"),
206+
)
207+
date_created = EntityTimestampField(value=1762450663, type="slack#/types/timestamp")
208+
date_updated = EntityTimestampField(value=1762450663, type="slack#/types/timestamp")
209+
fields = TaskEntityFields(
210+
description=description,
211+
due_date=due_date,
212+
created_by=created_by,
213+
date_created=date_created,
214+
date_updated=date_updated,
215+
)
216+
custom_fields = []
217+
custom_fields.append(
218+
EntityCustomField(
219+
label="My Image",
220+
key="my-image",
221+
type="slack#/types/image",
222+
image_url="https://s3-media3.fl.yelpcdn.com/bphoto/c7ed05m9lC2EmA3Aruue7A/o.jpg",
223+
)
224+
)
225+
entity = EntityPayload(attributes=attributes, fields=fields, custom_fields=custom_fields)
226+
227+
client: WebClient = WebClient(token=self.bot_token)
228+
new_message = client.chat_postMessage(
229+
channel="#random",
230+
text="Message with entity metadata",
231+
metadata=EventAndEntityMetadata(
232+
entities=[
233+
EntityMetadata(
234+
entity_type="slack#/entities/task",
235+
external_ref=ExternalRef(id="abc123"),
236+
url="https://myappdomain.com",
237+
entity_payload=entity,
238+
)
239+
]
240+
),
241+
)
242+
243+
self.assertIsNone(new_message.get("error"))
244+
self.assertIsNone(new_message.get("warning"))

slack_sdk/models/basic_objects.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ def validate_json(self) -> None:
4040
if callable(method) and hasattr(method, "validator"):
4141
method()
4242

43+
def get_object_attribute(self, key: str):
44+
return getattr(self, key, None)
45+
4346
def get_non_null_attributes(self) -> dict:
4447
"""
4548
Construct a dictionary out of non-null keys (from attributes property)
@@ -57,7 +60,7 @@ def to_dict_compatible(value: Union[dict, list, object, tuple]) -> Union[dict, l
5760
return value
5861

5962
def is_not_empty(self, key: str) -> bool:
60-
value = getattr(self, key, None)
63+
value = self.get_object_attribute(key)
6164
if value is None:
6265
return False
6366

@@ -75,7 +78,9 @@ def is_not_empty(self, key: str) -> bool:
7578
return value is not None
7679

7780
return {
78-
key: to_dict_compatible(getattr(self, key, None)) for key in sorted(self.attributes) if is_not_empty(self, key)
81+
key: to_dict_compatible(value=self.get_object_attribute(key))
82+
for key in sorted(self.attributes)
83+
if is_not_empty(self, key)
7984
}
8085

8186
def to_dict(self, *args) -> dict:

0 commit comments

Comments
 (0)