Skip to content

Commit e4ccb13

Browse files
authored
Fix #1236 Add video block to Block Kit model classes (#1237)
1 parent 5d509e0 commit e4ccb13

File tree

3 files changed

+178
-0
lines changed

3 files changed

+178
-0
lines changed

slack_sdk/models/blocks/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
from .blocks import ImageBlock
4949
from .blocks import InputBlock
5050
from .blocks import SectionBlock
51+
from .blocks import VideoBlock
5152

5253
__all__ = [
5354
"ButtonStyles",
@@ -92,4 +93,5 @@
9293
"ImageBlock",
9394
"InputBlock",
9495
"SectionBlock",
96+
"VideoBlock",
9597
]

slack_sdk/models/blocks/blocks.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ def parse(cls, block: Union[dict, "Block"]) -> Optional["Block"]:
8686
return CallBlock(**block)
8787
elif type == HeaderBlock.type:
8888
return HeaderBlock(**block)
89+
elif type == VideoBlock.type:
90+
return VideoBlock(**block)
8991
else:
9092
cls.logger.warning(f"Unknown block detected and skipped ({block})")
9193
return None
@@ -492,3 +494,100 @@ def _validate_text(self):
492494
@JsonValidator(f"text attribute cannot exceed {text_max_length} characters")
493495
def _validate_alt_text_length(self):
494496
return self.text is None or len(self.text.text) <= self.text_max_length
497+
498+
499+
class VideoBlock(Block):
500+
type = "video"
501+
title_max_length = 200
502+
author_name_max_length = 50
503+
504+
@property
505+
def attributes(self) -> Set[str]:
506+
return super().attributes.union(
507+
{
508+
"alt_text",
509+
"video_url",
510+
"thumbnail_url",
511+
"title",
512+
"title_url",
513+
"description",
514+
"provider_icon_url",
515+
"provider_name",
516+
"author_name",
517+
}
518+
)
519+
520+
def __init__(
521+
self,
522+
*,
523+
block_id: Optional[str] = None,
524+
alt_text: Optional[str] = None,
525+
video_url: Optional[str] = None,
526+
thumbnail_url: Optional[str] = None,
527+
title: Optional[Union[str, dict, PlainTextObject]] = None,
528+
title_url: Optional[str] = None,
529+
description: Optional[Union[str, dict, PlainTextObject]] = None,
530+
provider_icon_url: Optional[str] = None,
531+
provider_name: Optional[str] = None,
532+
author_name: Optional[str] = None,
533+
**others: dict,
534+
):
535+
"""A video block is designed to embed videos in all app surfaces
536+
(e.g. link unfurls, messages, modals, App Home) —
537+
anywhere you can put blocks! To use the video block within your app,
538+
you must have the links.embed:write scope.
539+
https://api.slack.com/reference/block-kit/blocks#video
540+
541+
Args:
542+
block_id: A string acting as a unique identifier for a block. If not specified, one will be generated.
543+
Maximum length for this field is 255 characters.
544+
block_id should be unique for each message and each iteration of a message.
545+
If a message is updated, use a new block_id.
546+
alt_text (required): A tooltip for the video. Required for accessibility
547+
video_url (required): The URL to be embedded. Must match any existing unfurl domains within the app
548+
and point to a HTTPS URL.
549+
thumbnail_url (required): The thumbnail image URL
550+
title (required): Video title in plain text format. Must be less than 200 characters.
551+
title_url: Hyperlink for the title text. Must correspond to the non-embeddable URL for the video.
552+
Must go to an HTTPS URL.
553+
description: Description for video in plain text format.
554+
provider_icon_url: Icon for the video provider - ex. Youtube icon
555+
provider_name: The originating application or domain of the video ex. Youtube
556+
author_name: Author name to be displayed. Must be less than 50 characters.
557+
"""
558+
super().__init__(type=self.type, block_id=block_id)
559+
show_unknown_key_warning(self, others)
560+
561+
self.alt_text = alt_text
562+
self.video_url = video_url
563+
self.thumbnail_url = thumbnail_url
564+
self.title = TextObject.parse(title, default_type=PlainTextObject.type)
565+
self.title_url = title_url
566+
self.description = TextObject.parse(description, default_type=PlainTextObject.type)
567+
self.provider_icon_url = provider_icon_url
568+
self.provider_name = provider_name
569+
self.author_name = author_name
570+
571+
@JsonValidator("alt_text attribute must be specified")
572+
def _validate_alt_text(self):
573+
return self.alt_text is not None
574+
575+
@JsonValidator("video_url attribute must be specified")
576+
def _validate_video_url(self):
577+
return self.video_url is not None
578+
579+
@JsonValidator("thumbnail_url attribute must be specified")
580+
def _validate_thumbnail_url(self):
581+
return self.thumbnail_url is not None
582+
583+
@JsonValidator("title attribute must be specified")
584+
def _validate_title(self):
585+
return self.title is not None
586+
587+
@JsonValidator(f"title attribute cannot exceed {title_max_length} characters")
588+
def _validate_title_length(self):
589+
return self.title is None or len(self.title.text) < self.title_max_length
590+
591+
@JsonValidator(f"author_name attribute cannot exceed {author_name_max_length} characters")
592+
def _validate_author_name_length(self):
593+
return self.author_name is None or len(self.author_name) < self.author_name_max_length

tests/slack_sdk/models/test_blocks.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
PlainTextObject,
2121
MarkdownTextObject,
2222
HeaderBlock,
23+
VideoBlock,
2324
Option,
2425
)
2526
from . import STRING_3001_CHARS
@@ -694,3 +695,79 @@ def test_text_length_151(self):
694695
}
695696
with self.assertRaises(SlackObjectFormationError):
696697
HeaderBlock(**input).validate_json()
698+
699+
700+
# ----------------------------------------------
701+
# Video
702+
# ----------------------------------------------
703+
704+
705+
class VideoBlockTests(unittest.TestCase):
706+
def test_document(self):
707+
input = {
708+
"type": "video",
709+
"title": {"type": "plain_text", "text": "How to use Slack.", "emoji": True},
710+
"title_url": "https://www.youtube.com/watch?v=RRxQQxiM7AA",
711+
"description": {
712+
"type": "plain_text",
713+
"text": "Slack is a new way to communicate with your team. "
714+
"It's faster, better organized and more secure than email.",
715+
"emoji": True,
716+
},
717+
"video_url": "https://www.youtube.com/embed/RRxQQxiM7AA?feature=oembed&autoplay=1",
718+
"alt_text": "How to use Slack?",
719+
"thumbnail_url": "https://i.ytimg.com/vi/RRxQQxiM7AA/hqdefault.jpg",
720+
"author_name": "Arcado Buendia",
721+
"provider_name": "YouTube",
722+
"provider_icon_url": "https://a.slack-edge.com/80588/img/unfurl_icons/youtube.png",
723+
}
724+
self.assertDictEqual(input, VideoBlock(**input).to_dict())
725+
self.assertDictEqual(input, Block.parse(input).to_dict())
726+
727+
def test_required(self):
728+
input = {
729+
"type": "video",
730+
"title": {"type": "plain_text", "text": "How to use Slack.", "emoji": True},
731+
"video_url": "https://www.youtube.com/embed/RRxQQxiM7AA?feature=oembed&autoplay=1",
732+
"alt_text": "How to use Slack?",
733+
"thumbnail_url": "https://i.ytimg.com/vi/RRxQQxiM7AA/hqdefault.jpg",
734+
}
735+
VideoBlock(**input).validate_json()
736+
737+
def test_required_error(self):
738+
# title is missing
739+
input = {
740+
"type": "video",
741+
"video_url": "https://www.youtube.com/embed/RRxQQxiM7AA?feature=oembed&autoplay=1",
742+
"alt_text": "How to use Slack?",
743+
"thumbnail_url": "https://i.ytimg.com/vi/RRxQQxiM7AA/hqdefault.jpg",
744+
}
745+
with self.assertRaises(SlackObjectFormationError):
746+
VideoBlock(**input).validate_json()
747+
748+
def test_title_length_199(self):
749+
input = {
750+
"type": "video",
751+
"title": {
752+
"type": "plain_text",
753+
"text": "1234567890" * 19 + "123456789",
754+
},
755+
"video_url": "https://www.youtube.com/embed/RRxQQxiM7AA?feature=oembed&autoplay=1",
756+
"alt_text": "How to use Slack?",
757+
"thumbnail_url": "https://i.ytimg.com/vi/RRxQQxiM7AA/hqdefault.jpg",
758+
}
759+
VideoBlock(**input).validate_json()
760+
761+
def test_title_length_200(self):
762+
input = {
763+
"type": "video",
764+
"title": {
765+
"type": "plain_text",
766+
"text": "1234567890" * 20,
767+
},
768+
"video_url": "https://www.youtube.com/embed/RRxQQxiM7AA?feature=oembed&autoplay=1",
769+
"alt_text": "How to use Slack?",
770+
"thumbnail_url": "https://i.ytimg.com/vi/RRxQQxiM7AA/hqdefault.jpg",
771+
}
772+
with self.assertRaises(SlackObjectFormationError):
773+
VideoBlock(**input).validate_json()

0 commit comments

Comments
 (0)