Repository: slack-go/slack (go)

Issue:
Support rich text input 
### Description

Support [rich text input](https://app.slack.com/block-kit-builder/T06FNKK2N#%7B%22title%22:%7B%22type%22:%22plain_text%22,%22text%22:%22My%20App%22,%22emoji%22:true%7D,%22submit%22:%7B%22type%22:%22plain_text%22,%22text%22:%22Submit%22,%22emoji%22:true%7D,%22type%22:%22modal%22,%22close%22:%7B%22type%22:%22plain_text%22,%22text%22:%22Cancel%22,%22emoji%22:true%7D,%22blocks%22:%5B%7B%22type%22:%22input%22,%22element%22:%7B%22type%22:%22rich_text_input%22,%22action_id%22:%22rich_text_input-action%22%7D,%22label%22:%7B%22type%22:%22plain_text%22,%22text%22:%22Label%22,%22emoji%22:true%7D%7D%5D%7D) 

```
	"blocks": [
		{
			"type": "input",
			"element": {
				"type": "rich_text_input",
				"action_id": "rich_text_input-action"
			},
			"label": {
				"type": "plain_text",
				"text": "Label",
				"emoji": true
			}
		}
	]
```

### (Optional) Slack's documentation
[rich text input](https://api.slack.com/reference/block-kit/block-elements#rich_text_input) 


Pull request:
Add support for Rich Text Input
closes #1239 

Patch:
diff --git a/block.go b/block.go
index c28377a..18222bd 100644
--- a/block.go
+++ b/block.go
@@ -18,7 +18,6 @@ const (
 	MBTInput    MessageBlockType = "input"
 	MBTHeader   MessageBlockType = "header"
 	MBTRichText MessageBlockType = "rich_text"
-	MBTVideo    MessageBlockType = "video"
 )
 
 // Block defines an interface all block types should implement
diff --git a/block_conv.go b/block_conv.go
index d017c66..48a9d0e 100644
--- a/block_conv.go
+++ b/block_conv.go
@@ -66,10 +66,10 @@ func (b *Blocks) UnmarshalJSON(data []byte) error {
 			block = &InputBlock{}
 		case "rich_text":
 			block = &RichTextBlock{}
+		case "rich_text_input":
+			block = &RichTextBlock{}
 		case "section":
 			block = &SectionBlock{}
-		case "video":
-			block = &VideoBlock{}
 		default:
 			block = &UnknownBlock{}
 		}
@@ -116,6 +116,8 @@ func (b *InputBlock) UnmarshalJSON(data []byte) error {
 		e = &DateTimePickerBlockElement{}
 	case "plain_text_input":
 		e = &PlainTextInputBlockElement{}
+	case "rich_text_input":
+		e = &RichTextInputBlockElement{}
 	case "email_text_input":
 		e = &EmailTextInputBlockElement{}
 	case "url_text_input":
@@ -198,6 +200,8 @@ func (b *BlockElements) UnmarshalJSON(data []byte) error {
 			blockElement = &DateTimePickerBlockElement{}
 		case "plain_text_input":
 			blockElement = &PlainTextInputBlockElement{}
+		case "rich_text_input":
+			blockElement = &RichTextInputBlockElement{}
 		case "email_text_input":
 			blockElement = &EmailTextInputBlockElement{}
 		case "url_text_input":
@@ -300,6 +304,12 @@ func (a *Accessory) UnmarshalJSON(data []byte) error {
 			return err
 		}
 		a.PlainTextInputElement = element.(*PlainTextInputBlockElement)
+	case "rich_text_input":
+		element, err := unmarshalBlockElement(r, &RichTextInputBlockElement{})
+		if err != nil {
+			return err
+		}
+		a.RichTextInputElement = element.(*RichTextInputBlockElement)
 	case "radio_buttons":
 		element, err := unmarshalBlockElement(r, &RadioButtonsBlockElement{})
 		if err != nil {
diff --git a/block_element.go b/block_element.go
index a70d8f2..49232d5 100644
--- a/block_element.go
+++ b/block_element.go
@@ -12,6 +12,7 @@ const (
 	METDatetimepicker MessageElementType = "datetimepicker"
 	METPlainTextInput MessageElementType = "plain_text_input"
 	METRadioButtons   MessageElementType = "radio_buttons"
+	METRichTextInput  MessageElementType = "rich_text_input"
 	METEmailTextInput MessageElementType = "email_text_input"
 	METURLTextInput   MessageElementType = "url_text_input"
 	METNumber         MessageElementType = "number_input"
@@ -51,6 +52,7 @@ type Accessory struct {
 	DatePickerElement          *DatePickerBlockElement
 	TimePickerElement          *TimePickerBlockElement
 	PlainTextInputElement      *PlainTextInputBlockElement
+	RichTextInputElement       *RichTextInputBlockElement
 	RadioButtonsElement        *RadioButtonsBlockElement
 	SelectElement              *SelectBlockElement
 	MultiSelectElement         *MultiSelectBlockElement
@@ -73,6 +75,8 @@ func NewAccessory(element BlockElement) *Accessory {
 		return &Accessory{TimePickerElement: element.(*TimePickerBlockElement)}
 	case *PlainTextInputBlockElement:
 		return &Accessory{PlainTextInputElement: element.(*PlainTextInputBlockElement)}
+	case *RichTextInputBlockElement:
+		return &Accessory{RichTextInputElement: element.(*RichTextInputBlockElement)}
 	case *RadioButtonsBlockElement:
 		return &Accessory{RadioButtonsElement: element.(*RadioButtonsBlockElement)}
 	case *SelectBlockElement:
@@ -509,6 +513,32 @@ func NewPlainTextInputBlockElement(placeholder *TextBlockObject, actionID string
 	}
 }
 
+// RichTextInputBlockElement creates a field where allows users to enter formatted text
+// in a WYSIWYG composer, offering the same messaging writing experience as in Slack
+// More Information: https://api.slack.com/reference/block-kit/block-elements#rich_text_input
+type RichTextInputBlockElement struct {
+	Type                 MessageElementType    `json:"type"`
+	ActionID             string                `json:"action_id,omitempty"`
+	Placeholder          *TextBlockObject      `json:"placeholder,omitempty"`
+	InitialValue         string                `json:"initial_value,omitempty"`
+	DispatchActionConfig *DispatchActionConfig `json:"dispatch_action_config,omitempty"`
+	FocusOnLoad          bool                  `json:"focus_on_load,omitempty"`
+}
+
+// ElementType returns the type of the Element
+func (s RichTextInputBlockElement) ElementType() MessageElementType {
+	return s.Type
+}
+
+// NewRichTextInputBlockElement returns an instance of a rich-text input element
+func NewRichTextInputBlockElement(placeholder *TextBlockObject, actionID string) *RichTextInputBlockElement {
+	return &RichTextInputBlockElement{
+		Type:        METRichTextInput,
+		ActionID:    actionID,
+		Placeholder: placeholder,
+	}
+}
+
 // CheckboxGroupsBlockElement defines an element which allows users to choose
 // one or more items from a list of possible options.
 //
diff --git a/block_rich_text.go b/block_rich_text.go
index aea1597..01e5cdb 100644
--- a/block_rich_text.go
+++ b/block_rich_text.go
@@ -40,9 +40,6 @@ func (e *RichTextBlock) UnmarshalJSON(b []byte) error {
 		switch s.Type {
 		case RTESection:
 			elem = &RichTextSection{}
-		case RTEList:
-			elem = &RichTextList{}
-
 		default:
 			elems = append(elems, &RichTextUnknown{
 				Type: s.Type,
@@ -95,88 +92,12 @@ func (u RichTextUnknown) RichTextElementType() RichTextElementType {
 	return u.Type
 }
 
-type RichTextListElementType string
-
-const (
-	RTEListOrdered RichTextListElementType = "ordered"
-	RTEListBullet  RichTextListElementType = "bullet"
-)
-
-type RichTextList struct {
-	Type     RichTextElementType     `json:"type"`
-	Elements []RichTextElement       `json:"elements"`
-	Style    RichTextListElementType `json:"style"`
-	Indent   int                     `json:"indent"`
-}
-
-// NewRichTextList returns a new rich text list element.
-func NewRichTextList(style RichTextListElementType, indent int, elements ...RichTextElement) *RichTextList {
-	return &RichTextList{
-		Type:     RTEList,
-		Elements: elements,
-		Style:    style,
-		Indent:   indent,
-	}
-}
-
-// ElementType returns the type of the Element
-func (s RichTextList) RichTextElementType() RichTextElementType {
-	return s.Type
-}
-
-func (e *RichTextList) UnmarshalJSON(b []byte) error {
-	var raw struct {
-		RawElements []json.RawMessage       `json:"elements"`
-		Style       RichTextListElementType `json:"style"`
-		Indent      int                     `json:"indent"`
-	}
-	if string(b) == "{}" {
-		return nil
-	}
-	if err := json.Unmarshal(b, &raw); err != nil {
-		return err
-	}
-	elems := make([]RichTextElement, 0, len(raw.RawElements))
-	for _, r := range raw.RawElements {
-		var s struct {
-			Type RichTextElementType `json:"type"`
-		}
-		if err := json.Unmarshal(r, &s); err != nil {
-			return err
-		}
-		var elem RichTextElement
-		switch s.Type {
-		case RTESection:
-			elem = &RichTextSection{}
-		case RTEList:
-			elem = &RichTextList{}
-		default:
-			elems = append(elems, &RichTextUnknown{
-				Type: s.Type,
-				Raw:  string(r),
-			})
-			continue
-		}
-		if err := json.Unmarshal(r, elem); err != nil {
-			return err
-		}
-		elems = append(elems, elem)
-	}
-	*e = RichTextList{
-		Type:     RTEList,
-		Elements: elems,
-		Style:    raw.Style,
-		Indent:   raw.Indent,
-	}
-	return nil
-}
-
 type RichTextSection struct {
 	Type     RichTextElementType      `json:"type"`
 	Elements []RichTextSectionElement `json:"elements"`
 }
 
-// RichTextElementType returns the type of the Element
+// ElementType returns the type of the Element
 func (s RichTextSection) RichTextElementType() RichTextElementType {
 	return s.Type
 }
diff --git a/block_video.go b/block_video.go
deleted file mode 100644
index 322c614..0000000
--- a/block_video.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package slack
-
-// VideoBlock defines data required to display a video as a block element
-//
-// More Information: https://api.slack.com/reference/block-kit/blocks#video
-type VideoBlock struct {
-	Type            MessageBlockType `json:"type"`
-	VideoURL        string           `json:"video_url"`
-	ThumbnailURL    string           `json:"thumbnail_url"`
-	AltText         string           `json:"alt_text"`
-	Title           *TextBlockObject `json:"title"`
-	BlockID         string           `json:"block_id,omitempty"`
-	TitleURL        string           `json:"title_url,omitempty"`
-	AuthorName      string           `json:"author_name,omitempty"`
-	ProviderName    string           `json:"provider_name,omitempty"`
-	ProviderIconURL string           `json:"provider_icon_url,omitempty"`
-	Description     *TextBlockObject `json:"description,omitempty"`
-}
-
-// BlockType returns the type of the block
-func (s VideoBlock) BlockType() MessageBlockType {
-	return s.Type
-}
-
-// NewVideoBlock returns an instance of a new Video Block type
-func NewVideoBlock(videoURL, thumbnailURL, altText, blockID string, title *TextBlockObject) *VideoBlock {
-	return &VideoBlock{
-		Type:         MBTVideo,
-		VideoURL:     videoURL,
-		ThumbnailURL: thumbnailURL,
-		AltText:      altText,
-		BlockID:      blockID,
-		Title:        title,
-	}
-}
-
-// WithAuthorName sets the author name for the VideoBlock
-func (s *VideoBlock) WithAuthorName(authorName string) *VideoBlock {
-	s.AuthorName = authorName
-	return s
-}
-
-// WithTitleURL sets the title URL for the VideoBlock
-func (s *VideoBlock) WithTitleURL(titleURL string) *VideoBlock {
-	s.TitleURL = titleURL
-	return s
-}
-
-// WithDescription sets the description for the VideoBlock
-func (s *VideoBlock) WithDescription(description *TextBlockObject) *VideoBlock {
-	s.Description = description
-	return s
-}
-
-// WithProviderIconURL sets the provider icon URL for the VideoBlock
-func (s *VideoBlock) WithProviderIconURL(providerIconURL string) *VideoBlock {
-	s.ProviderIconURL = providerIconURL
-	return s
-}
-
-// WithProviderName sets the provider name for the VideoBlock
-func (s *VideoBlock) WithProviderName(providerName string) *VideoBlock {
-	s.ProviderName = providerName
-	return s
-}
diff --git a/conversation.go b/conversation.go
index 787a961..1a63c53 100644
--- a/conversation.go
+++ b/conversation.go
@@ -22,7 +22,6 @@ type Conversation struct {
 	IsIM               bool     `json:"is_im"`
 	IsExtShared        bool     `json:"is_ext_shared"`
 	IsOrgShared        bool     `json:"is_org_shared"`
-	IsGlobalShared     bool     `json:"is_global_shared"`
 	IsPendingExtShared bool     `json:"is_pending_ext_shared"`
 	IsPrivate          bool     `json:"is_private"`
 	IsMpIM             bool     `json:"is_mpim"`
@@ -31,9 +30,6 @@ type Conversation struct {
 	NumMembers         int      `json:"num_members"`
 	Priority           float64  `json:"priority"`
 	User               string   `json:"user"`
-	ConnectedTeamIDs   []string `json:"connected_team_ids,omitempty"`
-	SharedTeamIDs      []string `json:"shared_team_ids,omitempty"`
-	InternalTeamIDs    []string `json:"internal_team_ids,omitempty"`
 
 	// TODO support pending_shared
 	// TODO support previous_names
diff --git a/slackevents/inner_events.go b/slackevents/inner_events.go
index 6be8b92..fb1ab13 100644
--- a/slackevents/inner_events.go
+++ b/slackevents/inner_events.go
@@ -267,7 +267,6 @@ type MessageEvent struct {
 	Upload bool   `json:"upload"`
 	Files  []File `json:"files"`
 
-	Blocks      slack.Blocks       `json:"blocks,omitempty"`
 	Attachments []slack.Attachment `json:"attachments,omitempty"`
 
 	// Root is the message that was broadcast to the channel when the SubType is


Test patch:
diff --git a/block_element_test.go b/block_element_test.go
index 0c47aff..19a0c96 100644
--- a/block_element_test.go
+++ b/block_element_test.go
@@ -148,6 +148,12 @@ func TestNewPlainTextInputBlockElement(t *testing.T) {
 
 }
 
+func TestNewRichTextInputBlockElement(t *testing.T) {
+	richTextInputElement := NewRichTextInputBlockElement(nil, "test")
+	assert.Equal(t, string(richTextInputElement.Type), "rich_text_input")
+	assert.Equal(t, richTextInputElement.ActionID, "test")
+}
+
 func TestNewEmailTextInputBlockElement(t *testing.T) {
 	emailTextInputElement := NewEmailTextInputBlockElement(nil, "example@example.com")
 
diff --git a/block_rich_text_test.go b/block_rich_text_test.go
index 2788c97..270dde9 100644
--- a/block_rich_text_test.go
+++ b/block_rich_text_test.go
@@ -36,12 +36,11 @@ func TestRichTextBlock_UnmarshalJSON(t *testing.T) {
 		err      error
 	}{
 		{
-			[]byte(`{"elements":[{"type":"rich_text_unknown"},{"type":"rich_text_section"},{"type":"rich_text_list"}]}`),
+			[]byte(`{"elements":[{"type":"rich_text_unknown"},{"type":"rich_text_section"}]}`),
 			RichTextBlock{
 				Elements: []RichTextElement{
 					&RichTextUnknown{Type: RTEUnknown, Raw: `{"type":"rich_text_unknown"}`},
 					&RichTextSection{Type: RTESection, Elements: []RichTextSectionElement{}},
-					&RichTextList{Type: RTEList, Elements: []RichTextElement{}},
 				},
 			},
 			nil,
@@ -118,84 +117,3 @@ func TestRichTextSection_UnmarshalJSON(t *testing.T) {
 		}
 	}
 }
-
-func TestRichTextList_UnmarshalJSON(t *testing.T) {
-	cases := []struct {
-		raw      []byte
-		expected RichTextList
-		err      error
-	}{
-		{
-			[]byte(`{"style":"ordered","elements":[{"type":"rich_text_unknown","value":10},{"type":"rich_text_section","elements":[{"type":"text","text":"hi"}]}]}`),
-			RichTextList{
-				Type:  RTEList,
-				Style: RTEListOrdered,
-				Elements: []RichTextElement{
-					&RichTextUnknown{Type: RTEUnknown, Raw: `{"type":"rich_text_unknown","value":10}`},
-					&RichTextSection{
-						Type: RTESection,
-						Elements: []RichTextSectionElement{
-							&RichTextSectionTextElement{Type: RTSEText, Text: "hi"},
-						},
-					},
-				},
-			},
-			nil,
-		},
-		{
-			[]byte(`{"style":"ordered","elements":[{"type":"rich_text_list","style":"bullet","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"hi"}]}]}]}`),
-			RichTextList{
-				Type:  RTEList,
-				Style: RTEListOrdered,
-				Elements: []RichTextElement{
-					&RichTextList{
-						Type:  RTEList,
-						Style: RTEListBullet,
-						Elements: []RichTextElement{
-							&RichTextSection{
-								Type: RTESection,
-								Elements: []RichTextSectionElement{
-									&RichTextSectionTextElement{Type: RTSEText, Text: "hi"},
-								},
-							},
-						},
-					},
-				},
-			},
-			nil,
-		},
-		{
-			[]byte(`{"type": "rich_text_list","elements":[]}`),
-			RichTextList{
-				Type:     RTEList,
-				Elements: []RichTextElement{},
-			},
-			nil,
-		},
-		{
-			[]byte(`{"type": "rich_text_list","elements":[],"indent":2}`),
-			RichTextList{
-				Type:     RTEList,
-				Indent:   2,
-				Elements: []RichTextElement{},
-			},
-			nil,
-		},
-	}
-	for _, tc := range cases {
-		var actual RichTextList
-		err := json.Unmarshal(tc.raw, &actual)
-		if err != nil {
-			if tc.err == nil {
-				t.Errorf("unexpected error: %s", err)
-			}
-			t.Errorf("expected error is %s, but got %s", tc.err, err)
-		}
-		if tc.err != nil {
-			t.Errorf("expected to raise an error %s", tc.err)
-		}
-		if diff := deep.Equal(actual, tc.expected); diff != nil {
-			t.Errorf("actual value does not match expected one\n%s", diff)
-		}
-	}
-}
diff --git a/block_video_test.go b/block_video_test.go
deleted file mode 100644
index d4b791f..0000000
--- a/block_video_test.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package slack
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestNewVideoBlock(t *testing.T) {
-
-	videoTitle := NewTextBlockObject("plain_text", "VideoTitle", false, false)
-	videoBlock := NewVideoBlock(
-		"https://example.com/example.mp4",
-		"https://example.com/thumbnail.png",
-		"alternative text", "blockID", videoTitle)
-
-	assert.Equal(t, string(videoBlock.Type), "video")
-	assert.Equal(t, videoBlock.Title.Type, "plain_text")
-	assert.Equal(t, videoBlock.BlockID, "blockID")
-	assert.Contains(t, videoBlock.Title.Text, "VideoTitle")
-	assert.Contains(t, videoBlock.VideoURL, "example.mp4")
-
-}