Codebase list golang-github-nlopes-slack / 45f072b
Changed interfaces to be private, updated related code and tests. Implemented getType for each interface to properly identify blocks, elements, and objects Matt authored 5 years ago James committed 5 years ago
16 changed file(s) with 128 addition(s) and 137 deletion(s). Raw diff Collapse all Expand all
33
44 // More Information: https://api.slack.com/block-kit
55
6 var (
7 // validBlockList contains a list of
8 validBlockList = []string{
9 "section",
10 "divider",
11 "image",
12 "actions",
13 "context",
14 }
6 // MessageBlockType defines a named string type to define each block type
7 // as a constant for use within the package.
8 type MessageBlockType string
9 type MessageElementType string
10 type MessageObjectType string
11
12 const (
13 mbtSection MessageBlockType = "section"
14 mbtDivider MessageBlockType = "divider"
15 mbtImage MessageBlockType = "image"
16 mbtAction MessageBlockType = "actions"
17 mbtContext MessageBlockType = "context"
18
19 metImage MessageElementType = "image"
20 metButton MessageElementType = "button"
21 metOverflow MessageElementType = "overflow"
22 metDatepicker MessageElementType = "datepicker"
23 metSelect MessageElementType = "static_select"
24
25 motImage MessageObjectType = "image"
26 motConfirmation MessageObjectType = "confirmation"
27 motOption MessageObjectType = "option"
28 motOptionGroup MessageObjectType = "option_group"
1529 )
1630
17 // Block defines an interface all block types should implement
31 // block defines an interface all block types should implement
1832 // to ensure consistency between blocks.
19 type Block interface {
20 ValidateBlock() bool
33 type block interface {
34 blockType() MessageBlockType
2135 }
2236
2337 // NewBlockMessage creates a new Message that contains one or more blocks to be displayed
24 func NewBlockMessage(blocks ...Block) Message {
38 func NewBlockMessage(blocks ...block) Message {
2539 return Message{
2640 Msg: Msg{
2741 Blocks: blocks,
2943 }
3044 }
3145
32 // isStringInSlice is a helper function used in validating the block structs to
33 // verify a valid type has been used.
34 func isStringInSlice(a []string, x string) bool {
35 for _, n := range a {
36 if x == n {
37 return true
38 }
39 }
40 return false
46 // AddBlockMessage appends a block to the end of the existing list of blocks
47 func AddBlockMessage(message Message, newBlk block) Message {
48 message.Msg.Blocks = append(message.Msg.Blocks, newBlk)
49 return message
4150 }
00 package slack
1
2 import "strings"
31
42 // ActionBlock defines data that is used to hold interactive elements.
53 //
64 // More Information: https://api.slack.com/reference/messaging/blocks#actions
75 type ActionBlock struct {
8 Type string `json:"type"`
9 BlockID string `json:"block_id,omitempty"`
10 Elements []BlockElement `json:"elements"`
6 Type MessageBlockType `json:"type"`
7 BlockID string `json:"block_id,omitempty"`
8 Elements []blockElement `json:"elements"`
119 }
1210
13 // ValidateBlock ensures that the type set to the block is found in the list of
14 // valid slack block.
15 func (s *ActionBlock) ValidateBlock() bool {
16 return isStringInSlice(validBlockList, strings.ToLower(s.Type))
11 // blockType returns the type of the block
12 func (s ActionBlock) blockType() MessageBlockType {
13 return s.Type
1714 }
1815
1916 // NewActionBlock returns a new instance of an Action Block
20 func NewActionBlock(blockID string, elements ...BlockElement) *ActionBlock {
17 func NewActionBlock(blockID string, elements ...blockElement) *ActionBlock {
2118 return &ActionBlock{
22 Type: "actions",
19 Type: mbtAction,
2320 BlockID: blockID,
2421 Elements: elements,
2522 }
1111 approveBtn := NewButtonBlockElement("", "click_me_123", approveBtnTxt)
1212
1313 actionBlock := NewActionBlock("test", approveBtn)
14 assert.Equal(t, actionBlock.Type, "actions")
14 assert.Equal(t, string(actionBlock.Type), "actions")
1515 assert.Equal(t, actionBlock.BlockID, "test")
1616 assert.Equal(t, len(actionBlock.Elements), 1)
1717
00 package slack
1
2 import "strings"
31
42 // ContextBlock defines data that is used to display message context, which can
53 // include both images and text.
64 //
75 // More Information: https://api.slack.com/reference/messaging/blocks#actions
86 type ContextBlock struct {
9 Type string `json:"type"`
10 BlockID string `json:"block_id,omitempty"`
11 Elements []BlockObject `json:"elements"`
7 Type MessageBlockType `json:"type"`
8 BlockID string `json:"block_id,omitempty"`
9 Elements []blockObject `json:"elements"`
1210 }
1311
14 // ValidateBlock ensures that the type set to the block is found in the list of
15 // valid slack block.
16 func (s *ContextBlock) ValidateBlock() bool {
17 return isStringInSlice(validBlockList, strings.ToLower(s.Type))
12 // blockType returns the type of the block
13 func (s ContextBlock) blockType() MessageBlockType {
14 return s.Type
1815 }
1916
2017 // NewContextBlock returns a newinstance of a context block
21 func NewContextBlock(blockID string, elements ...BlockObject) *ContextBlock {
18 func NewContextBlock(blockID string, elements ...blockObject) *ContextBlock {
2219 return &ContextBlock{
23 Type: "context",
20 Type: mbtContext,
2421 BlockID: blockID,
2522 Elements: elements,
2623 }
1111 textExample := NewTextBlockObject("plain_text", "Location: Central Business District", true, false)
1212
1313 actionBlock := NewContextBlock("test", locationPinImage, textExample)
14 assert.Equal(t, actionBlock.Type, "context")
14 assert.Equal(t, string(actionBlock.Type), "context")
1515 assert.Equal(t, actionBlock.BlockID, "test")
1616 assert.Equal(t, len(actionBlock.Elements), 2)
1717
00 package slack
1
2 import "strings"
31
42 // DividerBlock for displaying a divider line between blocks (similar to <hr> tag in html)
53 //
64 // More Information: https://api.slack.com/reference/messaging/blocks#divider
75 type DividerBlock struct {
8 Type string `json:"type"`
9 BlockID string `json:"block_id,omitempty"`
6 Type MessageBlockType `json:"type"`
7 BlockID string `json:"block_id,omitempty"`
108 }
119
12 // ValidateBlock ensures that the type set to the block is found in the list of
13 // valid slack block.
14 func (s *DividerBlock) ValidateBlock() bool {
15 return isStringInSlice(validBlockList, strings.ToLower(s.Type))
16
10 // blockType returns the type of the block
11 func (s DividerBlock) blockType() MessageBlockType {
12 return s.Type
1713 }
1814
1915 // NewDividerBlock returns a new instance of a divider block
2016 func NewDividerBlock() *DividerBlock {
2117
2218 return &DividerBlock{
23 Type: "divider",
19 Type: mbtDivider,
2420 }
2521
2622 }
88 func TestNewDividerBlock(t *testing.T) {
99
1010 dividerBlock := NewDividerBlock()
11 assert.Equal(t, dividerBlock.Type, "divider")
11 assert.Equal(t, string(dividerBlock.Type), "divider")
1212
1313 }
11
22 // https://api.slack.com/reference/messaging/block-elements
33
4 // BlockElement defines an interface that all block element types should
4 // blockElement defines an interface that all block element types should
55 // implement.
6 type BlockElement interface {
7 ValidateElement() bool
6 type blockElement interface {
7 blockType() MessageElementType
88 }
99
1010 // ImageBlockElement An element to insert an image - this element can be used
1313 //
1414 // More Information: https://api.slack.com/reference/messaging/block-elements#image
1515 type ImageBlockElement struct {
16 Type string `json:"type"`
17 ImageURL string `json:"image_url"`
18 AltText string `json:"alt_text"`
16 Type MessageElementType `json:"type"`
17 ImageURL string `json:"image_url"`
18 AltText string `json:"alt_text"`
1919 }
2020
21 // ValidateElement performs validation checks to ensure the element is valid
22 func (s ImageBlockElement) ValidateElement() bool {
23 return true
21 // validateType enforces block objects for block parameters
22 func (s ImageBlockElement) blockType() MessageElementType {
23 return s.Type
2424 }
2525
2626 // NewImageBlockElement returns a new instance of an image block element
2727 func NewImageBlockElement(imageURL, altText string) *ImageBlockElement {
2828 return &ImageBlockElement{
29 Type: "image",
29 Type: metImage,
3030 ImageURL: imageURL,
3131 AltText: altText,
3232 }
3838 //
3939 // More Information: https://api.slack.com/reference/messaging/block-elements#button
4040 type ButtonBlockElement struct {
41 Type string `json:"type,omitempty"`
41 Type MessageElementType `json:"type,omitempty"`
4242 Text *TextBlockObject `json:"text"`
4343 ActionID string `json:"action_id,omitempty"`
4444 URL string `json:"url,omitempty"`
4646 Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
4747 }
4848
49 // ValidateElement performs validation checks to ensure the element is valid
50 func (s ButtonBlockElement) ValidateElement() bool {
51 return true
49 // validateType enforces block objects for block parameters
50 func (s ButtonBlockElement) blockType() MessageElementType {
51 return s.Type
5252 }
5353
5454 // NewButtonBlockElement returns an instance of a new button element to be used within a block
5555 func NewButtonBlockElement(actionID, value string, text *TextBlockObject) *ButtonBlockElement {
5656 return &ButtonBlockElement{
57 Type: "button",
57 Type: metButton,
5858 ActionID: actionID,
5959 Text: text,
6060 Value: value,
7575 Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
7676 }
7777
78 // ValidateElement performs validation checks to ensure the element is valid
79 func (s SelectBlockElement) ValidateElement() bool {
80 return true
78 // validateType enforces block objects for block parameters
79 func (s SelectBlockElement) blockType() MessageElementType {
80 return MessageElementType(s.Type)
8181 }
8282
8383 // NewOptionsSelectBlockElement returns a new instance of SelectBlockElement for use with
114114 //
115115 // More Information: https://api.slack.com/reference/messaging/block-elements#overflow
116116 type OverflowBlockElement struct {
117 Type string `json:"type"`
117 Type MessageElementType `json:"type"`
118118 ActionID string `json:"action_id,omitempty"`
119119 Options []*OptionBlockObject `json:"options"`
120120 Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
121121 }
122122
123 // ValidateElement performs validation checks to ensure the element is valid
124 func (s OverflowBlockElement) ValidateElement() bool {
125 return true
123 // validateType enforces block objects for block parameters
124 func (s OverflowBlockElement) blockType() MessageElementType {
125 return s.Type
126126 }
127127
128128 // NewOverflowBlockElement returns an instance of a new Overflow Block Element
129129 func NewOverflowBlockElement(actionID string, options ...*OptionBlockObject) *OverflowBlockElement {
130130 return &OverflowBlockElement{
131 Type: "overflow",
131 Type: metOverflow,
132132 ActionID: actionID,
133133 Options: options,
134134 }
140140 //
141141 // More Information: https://api.slack.com/reference/messaging/block-elements#datepicker
142142 type DatePickerBlockElement struct {
143 Type string `json:"type"`
143 Type MessageElementType `json:"type"`
144144 ActionID string `json:"action_id"`
145145 Placeholder *TextBlockObject `json:"placeholder,omitempty"`
146146 InitialDate string `json:"initial_date,omitempty"`
147147 Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
148148 }
149149
150 // ValidateElement performs validation checks to ensure the element is valid
151 func (s DatePickerBlockElement) ValidateElement() bool {
152 return true
150 // validateType enforces block objects for block parameters
151 func (s DatePickerBlockElement) blockType() MessageElementType {
152 return s.Type
153153 }
154154
155155 // NewDatePickerBlockElement returns an instance of a date picker element
156156 func NewDatePickerBlockElement(actionID string) *DatePickerBlockElement {
157157 return &DatePickerBlockElement{
158 Type: "datepicker",
158 Type: metDatepicker,
159159 ActionID: actionID,
160160 }
161161 }
99
1010 imageElement := NewImageBlockObject("https://api.slack.com/img/blocks/bkb_template_images/tripAgentLocationMarker.png", "Location Pin Icon")
1111
12 assert.Equal(t, imageElement.Type, "image")
12 assert.Equal(t, string(imageElement.Type), "image")
1313 assert.Contains(t, imageElement.ImageURL, "tripAgentLocationMarker")
1414 assert.Equal(t, imageElement.AltText, "Location Pin Icon")
1515
2020 btnTxt := NewTextBlockObject("plain_text", "Next 2 Results", false, false)
2121 btnElement := NewButtonBlockElement("test", "click_me_123", btnTxt)
2222
23 assert.Equal(t, btnElement.Type, "button")
23 assert.Equal(t, string(btnElement.Type), "button")
2424 assert.Equal(t, btnElement.ActionID, "test")
2525 assert.Equal(t, btnElement.Value, "click_me_123")
2626 assert.Equal(t, btnElement.Text.Text, "Next 2 Results")
4848
4949 optGroup := NewOptionsGroupSelectBlockElement("static_select", nil, "test", testGroupOption)
5050
51 assert.Equal(t, optGroup.Type, "static_select")
51 assert.Equal(t, string(optGroup.Type), "static_select")
5252 assert.Equal(t, optGroup.ActionID, "test")
5353 assert.Equal(t, len(optGroup.OptionGroups), 1)
5454
6969 // Build overflow section
7070 overflowElement := NewOverflowBlockElement("test", overflowOptionOne, overflowOptionTwo, overflowOptionThree)
7171
72 assert.Equal(t, overflowElement.Type, "overflow")
72 assert.Equal(t, string(overflowElement.Type), "overflow")
7373 assert.Equal(t, overflowElement.ActionID, "test")
7474 assert.Equal(t, len(overflowElement.Options), 3)
7575
7979
8080 datepickerElement := NewDatePickerBlockElement("test")
8181
82 assert.Equal(t, datepickerElement.Type, "datepicker")
82 assert.Equal(t, string(datepickerElement.Type), "datepicker")
8383 assert.Equal(t, datepickerElement.ActionID, "test")
8484
8585 }
00 package slack
1
2 import "strings"
31
42 // ImageBlock defines data required to display an image as a block element
53 //
64 // More Information: https://api.slack.com/reference/messaging/blocks#image
75 type ImageBlock struct {
8 Type string `json:"type"`
6 Type MessageBlockType `json:"type"`
97 ImageURL string `json:"image_url"`
108 AltText string `json:"alt_text"`
119 BlockID string `json:"block_id,omitempty"`
1210 Title *TextBlockObject `json:"title"`
1311 }
1412
15 // ValidateBlock ensures that the type set to the block is found in the list of
16 // valid slack block.
17 func (s *ImageBlock) ValidateBlock() bool {
18 return isStringInSlice(validBlockList, strings.ToLower(s.Type))
19
13 // blockType returns the type of the block
14 func (s ImageBlock) blockType() MessageBlockType {
15 return s.Type
2016 }
2117
2218 // NewImageBlock returns an instance of a new Image Block type
2319 func NewImageBlock(imageURL, altText, blockID string, title *TextBlockObject) *ImageBlock {
2420 return &ImageBlock{
25 Type: "image",
21 Type: mbtImage,
2622 ImageURL: imageURL,
2723 AltText: altText,
2824 BlockID: blockID,
1010 imageText := NewTextBlockObject("plain_text", "Location", false, false)
1111 imageBlock := NewImageBlock("https://api.slack.com/img/blocks/bkb_template_images/tripAgentLocationMarker.png", "Marker", "test", imageText)
1212
13 assert.Equal(t, imageBlock.Type, "image")
13 assert.Equal(t, string(imageBlock.Type), "image")
1414 assert.Equal(t, imageBlock.Title.Type, "plain_text")
1515 assert.Equal(t, imageBlock.BlockID, "test")
1616 assert.Contains(t, imageBlock.Title.Text, "Location")
66 // BlockObject defines an interface that all block object types should
77 // implement.
88 // @TODO: Is this interface needed?
9 type BlockObject interface {
10 ValidateObject() bool
9 type blockObject interface {
10 validateType() MessageObjectType
1111 }
1212
1313 // ImageBlockObject An element to insert an image - this element can be used
1616 //
1717 // More Information: https://api.slack.com/reference/messaging/block-elements#image
1818 type ImageBlockObject struct {
19 Type string `json:"type"`
20 ImageURL string `json:"image_url"`
21 AltText string `json:"alt_text"`
19 Type MessageObjectType `json:"type"`
20 ImageURL string `json:"image_url"`
21 AltText string `json:"alt_text"`
2222 }
2323
24 // ValidateObject performs validation checks to ensure the element is valid
25 func (s ImageBlockObject) ValidateObject() bool {
26 return true
24 // validateType enforces block objects for element and block parameters
25 func (s ImageBlockObject) validateType() MessageObjectType {
26 return s.Type
2727 }
2828
2929 // NewImageBlockObject returns a new instance of an image block element
3030 func NewImageBlockObject(imageURL, altText string) *ImageBlockObject {
3131 return &ImageBlockObject{
32 Type: "image",
32 Type: motImage,
3333 ImageURL: imageURL,
3434 AltText: altText,
3535 }
4545 Verbatim bool `json:"verbatim,omitempty"`
4646 }
4747
48 // ValidateObject performs validation checks to ensure the element is valid
49 func (s *TextBlockObject) ValidateObject() bool {
50 return true
48 // validateType enforces block objects for element and block parameters
49 func (s TextBlockObject) validateType() MessageObjectType {
50 return MessageObjectType(s.Type)
5151 }
5252
5353 // NewTextBlockObject returns an instance of a new Text Block Object
7272 Deny *TextBlockObject `json:"deny"`
7373 }
7474
75 // ValidateObject performs validation checks to ensure the element is valid
76 func (s *ConfirmationBlockObject) ValidateObject() bool {
77 return true
75 // validateType enforces block objects for element and block parameters
76 func (s ConfirmationBlockObject) validateType() MessageObjectType {
77 return motConfirmation
7878 }
7979
8080 // NewConfirmationBlockObject returns an instance of a new Confirmation Block Object
9595 Value string `json:"value"`
9696 }
9797
98 // ValidateObject performs validation checks to ensure the element is valid
99 func (s *OptionBlockObject) ValidateObject() bool {
100 return true
101 }
102
10398 // NewOptionBlockObject returns an instance of a new Option Block Element
10499 func NewOptionBlockObject(value string, text *TextBlockObject) *OptionBlockObject {
105100 return &OptionBlockObject{
106101 Text: text,
107102 Value: value,
108103 }
104 }
105
106 // validateType enforces block objects for element and block parameters
107 func (s OptionBlockObject) validateType() MessageObjectType {
108 return motOption
109109 }
110110
111111 // OptionGroupBlockObject Provides a way to group options in a select menu.
116116 Options []*OptionBlockObject `json:"options"`
117117 }
118118
119 // ValidateObject performs validation checks to ensure the element is valid
120 func (s *OptionGroupBlockObject) ValidateObject() bool {
121 return true
119 // validateType enforces block objects for element and block parameters
120 func (s OptionGroupBlockObject) validateType() MessageObjectType {
121 return motOptionGroup
122122 }
123123
124124 // NewOptionGroupBlockElement returns an instance of a new option group block element
99
1010 imageObject := NewImageBlockObject("https://api.slack.com/img/blocks/bkb_template_images/beagle.png", "Beagle")
1111
12 assert.Equal(t, imageObject.Type, "image")
12 assert.Equal(t, string(imageObject.Type), "image")
1313 assert.Equal(t, imageObject.AltText, "Beagle")
1414 assert.Contains(t, imageObject.ImageURL, "beagle.png")
1515
00 package slack
1
2 import "strings"
31
42 // SectionBlock defines a new block of type section
53 //
64 // More Information: https://api.slack.com/reference/messaging/blocks#section
75 type SectionBlock struct {
8 Type string `json:"type"`
6 Type MessageBlockType `json:"type"`
97 Text *TextBlockObject `json:"text,omitempty"`
108 BlockID string `json:"block_id,omitempty"`
119 Fields []*TextBlockObject `json:"fields,omitempty"`
12 Accessory BlockElement `json:"accessory,omitempty"`
10 Accessory blockElement `json:"accessory,omitempty"`
1311 }
1412
15 // ValidateBlock ensures that the type set to the block is found in the list of
16 // valid slack block.
17 func (s *SectionBlock) ValidateBlock() bool {
18 return isStringInSlice(validBlockList, strings.ToLower(s.Type))
19
13 // blockType returns the type of the block
14 func (s SectionBlock) blockType() MessageBlockType {
15 return s.Type
2016 }
2117
2218 // NewSectionBlock returns a new instance of a section block to be rendered
23 func NewSectionBlock(textObj *TextBlockObject, fields []*TextBlockObject, accessory BlockElement) *SectionBlock {
19 func NewSectionBlock(textObj *TextBlockObject, fields []*TextBlockObject, accessory blockElement) *SectionBlock {
2420 return &SectionBlock{
25 Type: "section",
21 Type: mbtSection,
2622 Text: textObj,
2723 Fields: fields,
2824 Accessory: accessory,
1010 textInfo := NewTextBlockObject("mrkdwn", "*<fakeLink.toHotelPage.com|The Ritz-Carlton New Orleans>*\n★★★★★\n$340 per night\nRated: 9.1 - Excellent", false, false)
1111
1212 sectionBlock := NewSectionBlock(textInfo, nil, nil)
13 assert.Equal(t, sectionBlock.Type, "section")
13 assert.Equal(t, string(sectionBlock.Type), "section")
1414 assert.Equal(t, len(sectionBlock.Fields), 0)
1515 assert.Nil(t, sectionBlock.Accessory)
1616 assert.Equal(t, sectionBlock.Text.Type, "mrkdwn")
9393 DeleteOriginal bool `json:"delete_original"`
9494
9595 // Block type Message
96 Blocks []Block `json:"blocks,omitempty"`
96 Blocks []block `json:"blocks,omitempty"`
9797 }
9898
9999 // Icon is used for bot messages