flottbot icon indicating copy to clipboard operation
flottbot copied to clipboard

Add option to allow for larger content to be posted

Open wass3r opened this issue 5 years ago • 2 comments

Slack has a 4,000 character limit. Per https://api.slack.com/methods/chat.postMessage under "Formatting messages", allow the user to toggle whether messages known to contain high character count should fall back to uploading as a file/snippet instead (see https://api.slack.com/methods/files.upload). Probably a flag at the rule level?

wass3r avatar Jan 06 '21 23:01 wass3r

here is my patch I did for file upload at commit: eb455f2cfe2ab218f6bcc4e6934e0a11118fe951

(the patch also included to allow direct specify of directory)

diff --git a/cmd/flottbot/main.go b/cmd/flottbot/main.go
index 3a01165..acdef00 100644
--- a/cmd/flottbot/main.go
+++ b/cmd/flottbot/main.go
@@ -17,6 +17,7 @@ import (
 func newBot() *models.Bot {
        bot := viper.New()
        bot.AddConfigPath("./config")
+       bot.AddConfigPath(os.Args[1])
        bot.AddConfigPath(".")
        bot.SetConfigName("bot")
        err := bot.ReadInConfig()
diff --git a/core/matcher.go b/core/matcher.go
index acc049a..2470413 100644
--- a/core/matcher.go
+++ b/core/matcher.go
@@ -313,6 +313,9 @@ func doRuleActions(message models.Message, outputMsgs chan<- models.Message, rul

        // Populate message output to users
        message.OutputToUsers = rule.OutputToUsers
+       message.UploadFile = rule.UploadFile
+       message.FileName = rule.FileName
+       message.FileType = rule.FileType

        // Start a thread if the message is not already part of a thread and
        // start_message_thread was set for the Rule
diff --git a/core/rules.go b/core/rules.go
index 37c1890..a6c7976 100644
--- a/core/rules.go
+++ b/core/rules.go
@@ -20,7 +20,7 @@ import (
 func Rules(rules *map[string]models.Rule, bot *models.Bot) {
        // Check if the rules directory even exists
        bot.Log.Debug().Msg("looking for rules directory...")
-       searchDir, err := utils.PathExists(path.Join("config", "rules"))
+       searchDir, err := utils.PathExists(path.Join(os.Args[1], "rules"))
        if err != nil {
                bot.Log.Error().Msgf("could not parse rules: %v", err)
        }
diff --git a/models/message.go b/models/message.go
index 1a9b1d9..a0bb624 100644
--- a/models/message.go
+++ b/models/message.go
@@ -15,6 +15,7 @@ type Message struct {
        ChannelName       string
        Input             string
        Output            string
+       FullOutput        string
        Error             string
        Timestamp         string
        ThreadTimestamp   string
@@ -28,6 +29,9 @@ type Message struct {
        Vars              map[string]string
        OutputToRooms     []string
        OutputToUsers     []string
+       UploadFile        bool
+       FileName          string
+       FileType          string
        Remotes           Remotes
        SourceLink        string
 }
diff --git a/models/rule.go b/models/rule.go
index 6757950..34a5c8f 100644
--- a/models/rule.go
+++ b/models/rule.go
@@ -18,6 +18,9 @@ type Rule struct {
        StartMessageThread bool     `mapstructure:"start_message_thread" binding:"omitempty"`
        IgnoreThreads      bool     `mapstructure:"ignore_threads" binding:"omitempty"`
        FormatOutput       string   `mapstructure:"format_output"`
+       UploadFile         bool     `mapstructure:"upload_file"`
+       FileName           string   `mapstructure:"filename"`
+       FileType           string   `mapstructure:"filetype"`
        HelpText           string   `mapstructure:"help_text"`
        IncludeInHelp      bool     `mapstructure:"include_in_help" binding:"required"`
        Active             bool     `mapstructure:"active" binding:"required"`
diff --git a/remote/slack/helper.go b/remote/slack/helper.go
index ee61233..2d06a53 100644
--- a/remote/slack/helper.go
+++ b/remote/slack/helper.go
@@ -398,7 +398,17 @@ func handleDirectMessage(api *slack.Client, message models.Message, bot *models.
                        " please set 'direct_message_only' to 'false'")
        }
        // Respond back to user via direct message
-       return sendDirectMessage(api, message.Vars["_user.id"], message)
+       if message.UploadFile {
+               err := fileUpload(api, message.Vars["_user.id"], message)
+               if err != nil {
+                 return err
+               }
+       } else {
+               err := sendDirectMessage(api, message.Vars["_user.id"], message)
+               if err != nil {
+                 return err
+               }
+       }
 }

 // handleNonDirectMessage - handle sending logic for non direct messages
@@ -408,9 +418,16 @@ func handleNonDirectMessage(api *slack.Client, users []slack.User, message model
        // Is output to rooms set?
        if len(message.OutputToRooms) > 0 {
                for _, roomID := range message.OutputToRooms {
-                       err := sendChannelMessage(api, roomID, message)
-                       if err != nil {
-                               return err
+                       if message.UploadFile {
+                               err := fileUpload(api, roomID, message)
+                               if err != nil {
+                                       return err
+                               }
+                       } else {
+                               err := sendChannelMessage(api, roomID, message)
+                               if err != nil {
+                                       return err
+                               }
                        }
                }
        }
@@ -425,9 +442,16 @@ func handleNonDirectMessage(api *slack.Client, users []slack.User, message model
                                        bot.Log.Warn().Msg("you have specified 'direct_message_only' as 'false' but listed yourself in 'output_to_users'")
                                }
                                // Respond back to these users via direct message
-                               err := sendDirectMessage(api, userID, message)
-                               if err != nil {
-                                       return err
+                               if message.UploadFile {
+                                       err := fileUpload(api, userID, message)
+                                       if err != nil {
+                                               return err
+                                       }
+                               } else {
+                                       err := sendDirectMessage(api, userID, message)
+                                       if err != nil {
+                                               return err
+                                       }
                                }
                        }
                }
@@ -435,9 +459,16 @@ func handleNonDirectMessage(api *slack.Client, users []slack.User, message model
        // Was there no specified output set?
        // Send message back to original channel
        if len(message.OutputToRooms) == 0 && len(message.OutputToUsers) == 0 {
-               err := sendBackToOriginMessage(api, message)
-               if err != nil {
-                       return err
+               if message.UploadFile {
+                       err := fileUpload(api, message.ChannelID, message)
+                       if err != nil {
+                               return err
+                       }
+               } else {
+                       err := sendBackToOriginMessage(api, message)
+                       if err != nil {
+                               return err
+                       }
                }
        }
        return nil
@@ -800,3 +831,15 @@ func sendMessage(api *slack.Client, ephemeral bool, channel, userID, text, threa

        return err
 }
+
+func fileUpload(api *slack.Client, channel string, message models.Message) error {
+       params := slack.FileUploadParameters{
+               Filename: message.FileName, Content: message.FullOutput,
+               Filetype: message.FileType,
+               Channels: []string{channel},
+       }
+
+       _, err := api.UploadFile(params)
+
+       return err
+}
diff --git a/remote/slack/remote.go b/remote/slack/remote.go
index 035fadf..c249e1f 100644
--- a/remote/slack/remote.go
+++ b/remote/slack/remote.go
@@ -116,6 +116,8 @@ func (c *Client) Send(message models.Message, bot *models.Bot) {

        // check message size and trim if necessary because
        // slack messages have a hard limit of 4000 characters
+
+       message.FullOutput = message.Output
        if len(message.Output) > slack.MaxMessageTextLength {
                contents := message.Output
                message.Output = contents[:(slack.MaxMessageTextLength-3)] + "..."
diff --git a/utils/path.go b/utils/path.go
index 24888f9..24e2c3b 100644
--- a/utils/path.go
+++ b/utils/path.go
@@ -15,14 +15,7 @@ var (

 // PathExists helps determine whether a path exists
 func PathExists(p string) (string, error) {
-       ex, err := os.Executable()
-
-       if err != nil {
-               return "", errCurrPath
-       }
-
-       exPath := filepath.Dir(ex)
-       fullPath := filepath.Join(exPath, p)
+       fullPath := filepath.Dir(p)

        if _, err := os.Stat(fullPath); err != nil {
                if os.IsNotExist(err) {

juliosueiras avatar Jun 06 '23 15:06 juliosueiras

example flags are

upload_file: true
filename: snippet
filetype: text

juliosueiras avatar Jun 06 '23 15:06 juliosueiras