2019-09-07 13:46:58 -07:00
|
|
|
package slack
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2022-03-12 10:41:07 -08:00
|
|
|
"errors"
|
2020-07-18 08:27:41 -07:00
|
|
|
"fmt"
|
2019-09-07 13:46:58 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
type sumtype struct {
|
|
|
|
TypeVal string `json:"type"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalJSON implements the Marshaller interface for Blocks so that any JSON
|
|
|
|
// marshalling is delegated and proper type determination can be made before marshal
|
|
|
|
func (b Blocks) MarshalJSON() ([]byte, error) {
|
|
|
|
bytes, err := json.Marshal(b.BlockSet)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON implements the Unmarshaller interface for Blocks, so that any JSON
|
|
|
|
// unmarshalling is delegated and proper type determination can be made before unmarshal
|
|
|
|
func (b *Blocks) UnmarshalJSON(data []byte) error {
|
|
|
|
var raw []json.RawMessage
|
|
|
|
|
|
|
|
if string(data) == "{}" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
err := json.Unmarshal(data, &raw)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var blocks Blocks
|
|
|
|
for _, r := range raw {
|
|
|
|
s := sumtype{}
|
|
|
|
err := json.Unmarshal(r, &s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var blockType string
|
|
|
|
if s.TypeVal != "" {
|
|
|
|
blockType = s.TypeVal
|
|
|
|
}
|
|
|
|
|
|
|
|
var block Block
|
|
|
|
switch blockType {
|
|
|
|
case "actions":
|
|
|
|
block = &ActionBlock{}
|
|
|
|
case "context":
|
|
|
|
block = &ContextBlock{}
|
|
|
|
case "divider":
|
|
|
|
block = &DividerBlock{}
|
2020-03-28 15:50:47 -07:00
|
|
|
case "file":
|
|
|
|
block = &FileBlock{}
|
2021-02-01 12:29:04 -08:00
|
|
|
case "header":
|
|
|
|
block = &HeaderBlock{}
|
2019-09-07 13:46:58 -07:00
|
|
|
case "image":
|
|
|
|
block = &ImageBlock{}
|
2020-03-01 11:59:19 -08:00
|
|
|
case "input":
|
|
|
|
block = &InputBlock{}
|
2021-12-11 15:05:15 -08:00
|
|
|
case "rich_text":
|
|
|
|
block = &RichTextBlock{}
|
2019-09-07 13:46:58 -07:00
|
|
|
case "section":
|
|
|
|
block = &SectionBlock{}
|
|
|
|
default:
|
2020-03-28 15:50:47 -07:00
|
|
|
block = &UnknownBlock{}
|
2019-09-07 13:46:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
err = json.Unmarshal(r, block)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
blocks.BlockSet = append(blocks.BlockSet, block)
|
|
|
|
}
|
|
|
|
|
|
|
|
*b = blocks
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-03-01 11:59:19 -08:00
|
|
|
// UnmarshalJSON implements the Unmarshaller interface for InputBlock, so that any JSON
|
|
|
|
// unmarshalling is delegated and proper type determination can be made before unmarshal
|
|
|
|
func (b *InputBlock) UnmarshalJSON(data []byte) error {
|
|
|
|
type alias InputBlock
|
|
|
|
a := struct {
|
|
|
|
Element json.RawMessage `json:"element"`
|
|
|
|
*alias
|
|
|
|
}{
|
|
|
|
alias: (*alias)(b),
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := json.Unmarshal(data, &a); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
s := sumtype{}
|
|
|
|
if err := json.Unmarshal(a.Element, &s); err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var e BlockElement
|
|
|
|
switch s.TypeVal {
|
|
|
|
case "datepicker":
|
|
|
|
e = &DatePickerBlockElement{}
|
2021-02-01 12:29:04 -08:00
|
|
|
case "timepicker":
|
|
|
|
e = &TimePickerBlockElement{}
|
2020-03-01 11:59:19 -08:00
|
|
|
case "plain_text_input":
|
|
|
|
e = &PlainTextInputBlockElement{}
|
2023-01-28 13:57:53 -08:00
|
|
|
case "email_text_input":
|
|
|
|
e = &EmailTextInputBlockElement{}
|
|
|
|
case "url_text_input":
|
|
|
|
e = &URLTextInputBlockElement{}
|
2020-03-01 11:59:19 -08:00
|
|
|
case "static_select", "external_select", "users_select", "conversations_select", "channels_select":
|
|
|
|
e = &SelectBlockElement{}
|
2020-05-23 15:06:21 -07:00
|
|
|
case "multi_static_select", "multi_external_select", "multi_users_select", "multi_conversations_select", "multi_channels_select":
|
|
|
|
e = &MultiSelectBlockElement{}
|
2020-09-04 14:29:13 -07:00
|
|
|
case "checkboxes":
|
|
|
|
e = &CheckboxGroupsBlockElement{}
|
|
|
|
case "overflow":
|
|
|
|
e = &OverflowBlockElement{}
|
|
|
|
case "radio_buttons":
|
|
|
|
e = &RadioButtonsBlockElement{}
|
2023-01-28 13:57:53 -08:00
|
|
|
case "number_input":
|
|
|
|
e = &NumberInputBlockElement{}
|
2020-03-01 11:59:19 -08:00
|
|
|
default:
|
|
|
|
return errors.New("unsupported block element type")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := json.Unmarshal(a.Element, e); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
b.Element = e
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-09-07 13:46:58 -07:00
|
|
|
// MarshalJSON implements the Marshaller interface for BlockElements so that any JSON
|
|
|
|
// marshalling is delegated and proper type determination can be made before marshal
|
|
|
|
func (b *BlockElements) MarshalJSON() ([]byte, error) {
|
|
|
|
bytes, err := json.Marshal(b.ElementSet)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON implements the Unmarshaller interface for BlockElements, so that any JSON
|
|
|
|
// unmarshalling is delegated and proper type determination can be made before unmarshal
|
|
|
|
func (b *BlockElements) UnmarshalJSON(data []byte) error {
|
|
|
|
var raw []json.RawMessage
|
|
|
|
|
|
|
|
if string(data) == "{}" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
err := json.Unmarshal(data, &raw)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var blockElements BlockElements
|
|
|
|
for _, r := range raw {
|
|
|
|
s := sumtype{}
|
|
|
|
err := json.Unmarshal(r, &s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var blockElementType string
|
|
|
|
if s.TypeVal != "" {
|
|
|
|
blockElementType = s.TypeVal
|
|
|
|
}
|
|
|
|
|
|
|
|
var blockElement BlockElement
|
|
|
|
switch blockElementType {
|
|
|
|
case "image":
|
|
|
|
blockElement = &ImageBlockElement{}
|
|
|
|
case "button":
|
|
|
|
blockElement = &ButtonBlockElement{}
|
|
|
|
case "overflow":
|
|
|
|
blockElement = &OverflowBlockElement{}
|
|
|
|
case "datepicker":
|
|
|
|
blockElement = &DatePickerBlockElement{}
|
2021-05-05 13:03:28 -07:00
|
|
|
case "timepicker":
|
|
|
|
blockElement = &TimePickerBlockElement{}
|
2020-03-01 11:59:19 -08:00
|
|
|
case "plain_text_input":
|
|
|
|
blockElement = &PlainTextInputBlockElement{}
|
2023-01-28 13:57:53 -08:00
|
|
|
case "email_text_input":
|
|
|
|
blockElement = &EmailTextInputBlockElement{}
|
|
|
|
case "url_text_input":
|
|
|
|
blockElement = &URLTextInputBlockElement{}
|
2020-07-18 08:27:41 -07:00
|
|
|
case "checkboxes":
|
|
|
|
blockElement = &CheckboxGroupsBlockElement{}
|
2020-09-04 14:29:13 -07:00
|
|
|
case "radio_buttons":
|
|
|
|
blockElement = &RadioButtonsBlockElement{}
|
2019-09-07 13:46:58 -07:00
|
|
|
case "static_select", "external_select", "users_select", "conversations_select", "channels_select":
|
|
|
|
blockElement = &SelectBlockElement{}
|
2023-01-28 13:57:53 -08:00
|
|
|
case "number_input":
|
|
|
|
blockElement = &NumberInputBlockElement{}
|
2019-09-07 13:46:58 -07:00
|
|
|
default:
|
2020-07-18 08:27:41 -07:00
|
|
|
return fmt.Errorf("unsupported block element type %v", blockElementType)
|
2019-09-07 13:46:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
err = json.Unmarshal(r, blockElement)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
blockElements.ElementSet = append(blockElements.ElementSet, blockElement)
|
|
|
|
}
|
|
|
|
|
|
|
|
*b = blockElements
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalJSON implements the Marshaller interface for Accessory so that any JSON
|
|
|
|
// marshalling is delegated and proper type determination can be made before marshal
|
|
|
|
func (a *Accessory) MarshalJSON() ([]byte, error) {
|
|
|
|
bytes, err := json.Marshal(toBlockElement(a))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON implements the Unmarshaller interface for Accessory, so that any JSON
|
|
|
|
// unmarshalling is delegated and proper type determination can be made before unmarshal
|
|
|
|
func (a *Accessory) UnmarshalJSON(data []byte) error {
|
|
|
|
var r json.RawMessage
|
|
|
|
|
|
|
|
if string(data) == "{\"accessory\":null}" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
err := json.Unmarshal(data, &r)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
s := sumtype{}
|
|
|
|
err = json.Unmarshal(r, &s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var blockElementType string
|
|
|
|
if s.TypeVal != "" {
|
|
|
|
blockElementType = s.TypeVal
|
|
|
|
}
|
|
|
|
|
|
|
|
switch blockElementType {
|
|
|
|
case "image":
|
|
|
|
element, err := unmarshalBlockElement(r, &ImageBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.ImageElement = element.(*ImageBlockElement)
|
|
|
|
case "button":
|
|
|
|
element, err := unmarshalBlockElement(r, &ButtonBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.ButtonElement = element.(*ButtonBlockElement)
|
|
|
|
case "overflow":
|
|
|
|
element, err := unmarshalBlockElement(r, &OverflowBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.OverflowElement = element.(*OverflowBlockElement)
|
|
|
|
case "datepicker":
|
|
|
|
element, err := unmarshalBlockElement(r, &DatePickerBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.DatePickerElement = element.(*DatePickerBlockElement)
|
2021-02-01 12:29:04 -08:00
|
|
|
case "timepicker":
|
|
|
|
element, err := unmarshalBlockElement(r, &TimePickerBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.TimePickerElement = element.(*TimePickerBlockElement)
|
2020-03-28 15:50:47 -07:00
|
|
|
case "plain_text_input":
|
|
|
|
element, err := unmarshalBlockElement(r, &PlainTextInputBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.PlainTextInputElement = element.(*PlainTextInputBlockElement)
|
|
|
|
case "radio_buttons":
|
|
|
|
element, err := unmarshalBlockElement(r, &RadioButtonsBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.RadioButtonsElement = element.(*RadioButtonsBlockElement)
|
|
|
|
case "static_select", "external_select", "users_select", "conversations_select", "channels_select":
|
2019-09-07 13:46:58 -07:00
|
|
|
element, err := unmarshalBlockElement(r, &SelectBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.SelectElement = element.(*SelectBlockElement)
|
2020-03-28 15:50:47 -07:00
|
|
|
case "multi_static_select", "multi_external_select", "multi_users_select", "multi_conversations_select", "multi_channels_select":
|
|
|
|
element, err := unmarshalBlockElement(r, &MultiSelectBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.MultiSelectElement = element.(*MultiSelectBlockElement)
|
2020-07-18 08:27:41 -07:00
|
|
|
case "checkboxes":
|
|
|
|
element, err := unmarshalBlockElement(r, &CheckboxGroupsBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.CheckboxGroupsBlockElement = element.(*CheckboxGroupsBlockElement)
|
2020-03-28 15:50:47 -07:00
|
|
|
default:
|
|
|
|
element, err := unmarshalBlockElement(r, &UnknownBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.UnknownElement = element.(*UnknownBlockElement)
|
2019-09-07 13:46:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unmarshalBlockElement(r json.RawMessage, element BlockElement) (BlockElement, error) {
|
|
|
|
err := json.Unmarshal(r, element)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return element, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func toBlockElement(element *Accessory) BlockElement {
|
|
|
|
if element.ImageElement != nil {
|
|
|
|
return element.ImageElement
|
|
|
|
}
|
|
|
|
if element.ButtonElement != nil {
|
|
|
|
return element.ButtonElement
|
|
|
|
}
|
|
|
|
if element.OverflowElement != nil {
|
|
|
|
return element.OverflowElement
|
|
|
|
}
|
|
|
|
if element.DatePickerElement != nil {
|
|
|
|
return element.DatePickerElement
|
|
|
|
}
|
2021-02-01 12:29:04 -08:00
|
|
|
if element.TimePickerElement != nil {
|
|
|
|
return element.TimePickerElement
|
|
|
|
}
|
2020-03-28 15:50:47 -07:00
|
|
|
if element.PlainTextInputElement != nil {
|
|
|
|
return element.PlainTextInputElement
|
|
|
|
}
|
|
|
|
if element.RadioButtonsElement != nil {
|
|
|
|
return element.RadioButtonsElement
|
|
|
|
}
|
2020-07-18 08:27:41 -07:00
|
|
|
if element.CheckboxGroupsBlockElement != nil {
|
|
|
|
return element.CheckboxGroupsBlockElement
|
|
|
|
}
|
2019-09-07 13:46:58 -07:00
|
|
|
if element.SelectElement != nil {
|
|
|
|
return element.SelectElement
|
|
|
|
}
|
2020-03-28 15:50:47 -07:00
|
|
|
if element.MultiSelectElement != nil {
|
|
|
|
return element.MultiSelectElement
|
|
|
|
}
|
2019-09-07 13:46:58 -07:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalJSON implements the Marshaller interface for ContextElements so that any JSON
|
|
|
|
// marshalling is delegated and proper type determination can be made before marshal
|
|
|
|
func (e *ContextElements) MarshalJSON() ([]byte, error) {
|
|
|
|
bytes, err := json.Marshal(e.Elements)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON implements the Unmarshaller interface for ContextElements, so that any JSON
|
|
|
|
// unmarshalling is delegated and proper type determination can be made before unmarshal
|
|
|
|
func (e *ContextElements) UnmarshalJSON(data []byte) error {
|
|
|
|
var raw []json.RawMessage
|
|
|
|
|
|
|
|
if string(data) == "{\"elements\":null}" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
err := json.Unmarshal(data, &raw)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, r := range raw {
|
|
|
|
s := sumtype{}
|
|
|
|
err := json.Unmarshal(r, &s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var contextElementType string
|
|
|
|
if s.TypeVal != "" {
|
|
|
|
contextElementType = s.TypeVal
|
|
|
|
}
|
|
|
|
|
|
|
|
switch contextElementType {
|
|
|
|
case PlainTextType, MarkdownType:
|
|
|
|
elem, err := unmarshalBlockObject(r, &TextBlockObject{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
e.Elements = append(e.Elements, elem.(*TextBlockObject))
|
|
|
|
case "image":
|
|
|
|
elem, err := unmarshalBlockElement(r, &ImageBlockElement{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
e.Elements = append(e.Elements, elem.(*ImageBlockElement))
|
|
|
|
default:
|
|
|
|
return errors.New("unsupported context element type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|