Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slack link bookmarks #230

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 46 additions & 20 deletions adapter/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ var (

// Adapter represents a connection to a chat provider.
type Adapter interface {
// BookmarkLink bookmarks a link in the specified chanel, if the adapter
// supports this.
BookmarkLink(ctx context.Context, channelID, title, link string) error
theothertomelliott marked this conversation as resolved.
Show resolved Hide resolved

// GetChannelInfo provides info on a specific provider channel accessible
// to the adapter.
GetChannelInfo(channelID string) (*io.ChannelInfo, error)
Expand Down Expand Up @@ -276,7 +280,7 @@ func SendEnvelope(ctx context.Context, a Adapter, channelID string, envelope dat
ctx, sp := tr.Start(ctx, "adapter.SendEnvelope")
defer sp.End()

handleAdvancedOutput(ctx, envelope.Response.Advanced) // TODO: handle error
handleAdvancedOutput(ctx, a, envelope.Response.Advanced) // TODO: handle error

e := adapterLogEntry(ctx, log.WithContext(ctx), a).WithField("message.type", tt)

Expand Down Expand Up @@ -327,38 +331,60 @@ func SendEnvelope(ctx context.Context, a Adapter, channelID string, envelope dat

// handleAdvancedOutput executes a slice of adapter actions specified as
// io.AdvancedInput.
func handleAdvancedOutput(ctx context.Context, output []io.AdvancedOutput) error {
func handleAdvancedOutput(ctx context.Context, adapter Adapter, output []io.AdvancedOutput) error {
e := adapterLogEntry(ctx, log.WithContext(ctx))
for _, o := range output {
var a = adapter
e1 := e.WithField("output.action", o.Action).WithField("output.messageref", o.MessageRef)
var msgRef MessageRef
err := json.NewDecoder(strings.NewReader(o.MessageRef)).Decode(&msgRef)
if err != nil {
e1.WithError(err).Errorf("Badly formatted MessageRef")
}
// An alternate way to get the adapter will be necessary for actions
// that don't involve existing messages.
a, err := GetAdapter(msgRef.Adapter)
var msgRef = new(MessageRef)
err := json.NewDecoder(strings.NewReader(o.MessageRef)).Decode(msgRef)
if err != nil {
e.WithError(err).Error("Couldn't find specified adapter")
return nil
msgRef = nil
if o.Adapter != "" {
a1, err := GetAdapter(o.Adapter)
if err != nil {
a = a1
}
}
} else {
e1 = e1.WithField("adapter.name", a.GetName())
a, err = GetAdapter(msgRef.Adapter)
if err != nil {
e.WithError(err).Error("Couldn't find specified adapter from MessageRef")
return nil
}
}

e1 = e1.WithField("adapter.name", a.GetName())

switch o.Action {
case io.ActionReply:
err = a.Reply(ctx, msgRef, o.Content)
if err != nil {
e1.WithError(err).Errorf("Failed to create reply")
if msgRef != nil {
err = a.Reply(ctx, *msgRef, o.Content)
if err != nil {
e1.WithError(err).Errorf("Failed to create reply")
} else {
e1.Debug("Replied!")
}
} else {
e1.Debug("Replied!")
e1.WithError(err).Errorf("Badly formatted MessageRef")
}
case io.ActionReact:
err = a.React(ctx, msgRef, emoji.From(o.Content))
if msgRef != nil {
err = a.React(ctx, *msgRef, emoji.From(o.Content))
if err != nil {
e1.WithError(err).Error("Failed to react")
} else {
e1.Debug("Reacted!")
}
} else {
e1.WithError(err).Errorf("Badly formatted MessageRef")
}
case io.ActionBookmark:
err = a.BookmarkLink(ctx, o.ChannelID, o.Title, o.Content)
if err != nil {
e1.WithError(err).Error("Failed to react")
e1.WithError(err).Error("Failed to bookmark")
} else {
e1.Debug("Reacted!")
e1.Debug("Bookmarked!")
}
default:
e1.Error("Unknown action")
Expand Down
5 changes: 5 additions & 0 deletions adapter/adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ var _ Adapter = &testAdapter{}

type testAdapter struct{}

func (t *testAdapter) BookmarkLink(ctx context.Context, channelID, title, link string) error {
//TODO implement me
panic("implement me")
}

func (t *testAdapter) React(ctx context.Context, message MessageRef, emoji emoji.Emoji) error {
//TODO implement me
panic("implement me")
Expand Down
4 changes: 4 additions & 0 deletions adapter/discord/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ type Adapter struct {
events chan *adapter.ProviderEvent
}

func (s *Adapter) BookmarkLink(ctx context.Context, channelID, title, link string) error {
return fmt.Errorf("discord does not curently support bookmarking links")
}

func (s *Adapter) React(ctx context.Context, message adapter.MessageRef, emoji emoji.Emoji) error {
return s.session.MessageReactionAdd(message.ChannelID, message.ID, string(emoji.Unicode()))
}
Expand Down
10 changes: 10 additions & 0 deletions adapter/slack/classic_adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ type ClassicAdapter struct {
rtm *slack.RTM
}

func (s *ClassicAdapter) BookmarkLink(ctx context.Context, channelID, title, link string) error {
_, err := s.client.AddBookmarkContext(ctx, channelID, slack.AddBookmarkParameters{
Title: title,
Type: "link",
Link: link,
})
//TODO this could support emoji
return err
}

func (s *ClassicAdapter) React(ctx context.Context, message adapter.MessageRef, emoji emoji.Emoji) error {
return s.client.AddReactionContext(ctx, emoji.Shortname(), slack.ItemRef{
Channel: message.ChannelID,
Expand Down
10 changes: 10 additions & 0 deletions adapter/slack/socketmode_adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ type SocketModeAdapter struct {
provider data.SlackProvider
}

func (s *SocketModeAdapter) BookmarkLink(ctx context.Context, channelID, title, link string) error {
_, err := s.client.AddBookmarkContext(ctx, channelID, slack.AddBookmarkParameters{
Title: title,
Type: "link",
Link: link,
})
//TODO this could support emoji
return err
}

func (s *SocketModeAdapter) React(ctx context.Context, message adapter.MessageRef, emoji emoji.Emoji) error {
return s.client.AddReactionContext(ctx, emoji.Shortname(), slack.ItemRef{
Channel: message.ChannelID,
Expand Down
15 changes: 15 additions & 0 deletions data/io/advancedio.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ import (
const (
ActionReply = "reply"
ActionReact = "react"

// ActionBookmark is used to bookmark a link in a given chanel. This is
// currently only supported on slack. It requires a link in Content, a
// Title, a ChannelID, and optionally an Adapter.
ActionBookmark = "bookmark"
)

// CommandInfo represents a command typed in by a user. Unlike
Expand Down Expand Up @@ -123,4 +128,14 @@ type AdvancedOutput struct {
// Content is the content associated with an action, for example text for a
// reply or the emoji for a reaction.
Content string

// Title is the title of something to be created, for example a slack
// bookmark.
Title string

// Adapter is the name of a specific adapter in which to perform the action.
// This is usually optional, and will default to the adapter from which the
// command that generated this output was triggered. Actions that take
// MessageRef may use the adapter of that message.
Adapter string
}