func main() { iniflags.Parse() api := slack.New(*token) //var channel_id string channel_id := getChannelId(*channel, api) var include, exclude *regexp.Regexp var err error if *includes != "" { include, err = regexp.Compile(*includes) if err != nil { fmt.Println("ERROR: Failed to compile `line_includes` regex.") fmt.Println(err) api.PostMessage(channel_id, "==> slackd failed to compile `line_includes` regex.", slack.NewPostMessageParameters()) api.PostMessage(channel_id, err.Error(), slack.NewPostMessageParameters()) os.Exit(2) } } if *excludes != "" { exclude, err = regexp.Compile(*excludes) if err != nil { fmt.Println("ERROR: Failed to compile `line_excludes` regex.") fmt.Println(err) api.PostMessage(channel_id, "==> slackd failed to compile `line_excludes` regex.", slack.NewPostMessageParameters()) api.PostMessage(channel_id, err.Error(), slack.NewPostMessageParameters()) os.Exit(2) } } log, err := tail.TailFile(*file, tail.Config{Follow: true, ReOpen: *reopen, Poll: true}) if err != nil { fmt.Println("ERROR: Could not tail the specified log.") fmt.Println(err) api.PostMessage(channel_id, "==> slackd could not tail the specified log.", slack.NewPostMessageParameters()) api.PostMessage(channel_id, err.Error(), slack.NewPostMessageParameters()) os.Exit(2) } for line := range log.Lines { if (include != nil && include.MatchString(line.Text)) || (exclude != nil && !exclude.MatchString(line.Text)) { api.PostMessage( channel_id, fmt.Sprintf("```%s```", line.Text), slack.NewPostMessageParameters()) } } }
func postToSlack(username string, channel string, message string, attachments string) { param := slack.NewPostMessageParameters() param.Username = username dec := json.NewDecoder(strings.NewReader(attachments)) _ = dec.Decode(¶m.Attachments) fmt.Printf("%v\n", param.Attachments) _, _, err := ctx.slack.PostMessage(channel, message, param) if err != nil { log.WithFields(log.Fields{ "username": username, "channel": channel, "message": message, "attachments": attachments, }).Error(err.Error()) return } log.WithFields(log.Fields{ "username": username, "channel": channel, "message": message, "attachments": attachments, }).Info("posted") }
func (rt ReconTask) performTask(task ActionItemConfig, stringContext map[string]interface{}) { rt.log.Debug("Task Config - %v", task.Config) switch task.Type { case "sendToSlack": message := EvaluateTemplate(task.Config["message"].(string), stringContext) slackClient := slack.New(task.Config["slackKey"].(string)) slackClient.PostMessage(task.Config["slackTo"].(string), message, slack.NewPostMessageParameters()) case "executeMysql": query := EvaluateTemplate(task.Config["query"].(string), stringContext) params := task.Config["params"].([]interface{}) paramValues := make([]interface{}, 0) for _, param := range params { paramValue := EvaluateTemplate(param.(string), stringContext) paramValues = append(paramValues, paramValue) } endPoint, err := NewMysqlDataProvider(task.Config["mysqlConfig"].(map[string]interface{})) if err != nil { rt.log.Error("Failed to connect to mysql - %v", err) } stmt, err := endPoint.db.Prepare(query) if err != nil { rt.log.Error("Failed to prepare statement- %v", err) } defer stmt.Close() rt.log.Info("Executing [%s] with params [%v]", query, paramValues) result, err := stmt.Exec(paramValues...) if err != nil { rt.log.Error("Failed to Execute query - %v", err) } count, _ := result.RowsAffected() if count < 1 { rt.log.Info("0 rows affected, might want to check - %v", stringContext) } } }
// Publish Publishes messages to slack func (x Slack) Publish(publishMsgs <-chan models.Message, connector models.Connector) { api := slack.New(connector.Key) for { message := <-publishMsgs msg := "" params := slack.NewPostMessageParameters() params.Username = connector.BotName params.IconEmoji = connector.Image if message.Out.Detail != "" { color := slackColorMe(message.Out.Status) attachment := slack.Attachment{ Title: message.Out.Text, TitleLink: message.Out.Link, Text: message.Out.Detail, Color: color, MarkdownIn: []string{"text"}, } params.Attachments = []slack.Attachment{attachment} } else { msg = message.Out.Text } for _, target := range strings.Split(message.Out.Target, ",") { if target == "*" { target = message.In.Target } if target != "" && target != "*" { api.PostMessage(target, msg, params) } } } }
// expect some byte and write to slack func (s *Slack) Write(o []byte) (n int, err error) { outBuf := bytes.Buffer{} outBuf.Write(o) //s.rtm.SendMessage( //s.rtm.NewOutgoingMessage( //outBuf.String(), //s.channel, //), //) params := slack.NewPostMessageParameters() params.Username = "******" params.AsUser = true params.Attachments = []slack.Attachment{ { //AuthorName: authorName, //AuthorIcon: authorIcon, Text: fmt.Sprintf("%s\n\u2014\n", outBuf.String()), // \u200B for space //ThumbURL: thumbURL, //Fields: []AttachmentField{ //AttachmentField{ //Title: "", //Value: fmt.Sprintf("*<%s|%s>*\n%s", post.ShortUrl, post.Title, description), //Short: false, //}, //}, MarkdownIn: []string{"text"}, }} s.api.PostMessage(s.channel, "", params) return len(o), nil }
func sendMessage(sendWg *sync.WaitGroup, config *model.Config, api *slack.Client, msg *model.ChatMessage) { params := slack.NewPostMessageParameters() params.Attachments = msg.Attachments params.Username = config.SlackUser params.IconURL = config.SlackIcon params.LinkNames = 1 params.AsUser = false channel := msg.Channel if channel == "" { // For now just print everything to the main channel. When we have RTM // support up and running we might also want the ability to write back // to a user DM channel. channel = config.SlackDefaultChannel } logOut.Debugf("Posting to channel %s %s %+v", channel, msg.Text, params) _, _, err := api.PostMessage(channel, msg.Text, params) if err != nil { logOut.Errorf("Error writing chat message: %s\n", err.Error()) } sendWg.Done() }
// DefaultMessageParameters returns a default PostMessageParameters for vropsbot func DefaultMessageParameters() (params slack.PostMessageParameters) { params = slack.NewPostMessageParameters() params.AsUser = true params.EscapeText = false return }
func (c *HelpCommand) Run(m *slack.MessageEvent, args ...string) { params := slack.NewPostMessageParameters() params.Attachments = []slack.Attachment{slack.Attachment{ Color: "good", Fields: []slack.AttachmentField{}, }} service := c.Service.(*SlackService) if len(args) == 0 { for name := range service.Commands { params.Attachments[0].Fields = append(params.Attachments[0].Fields, slack.AttachmentField{ Title: service.Commands[name].GetName(), Value: service.Commands[name].GetDescription(), }) } } else if command, ok := service.Commands[args[0]]; ok { params.Attachments[0].Fields = append(params.Attachments[0].Fields, slack.AttachmentField{ Title: command.GetName(), Value: command.GetDescription(), }) } else { c.SendMessagef(m.Channel, "Команда %s не найдена", args[0]) return } c.SendPostMessage(m.Channel, "Мои команды", params) }
func (s Slack) newPostMessageParams() slack.PostMessageParameters { params := slack.NewPostMessageParameters() if s.userName != "" { params.Username = s.userName } if s.iconURL != "" { params.IconURL = s.iconURL } return params }
func main() { if cli.file != "" { log.Printf("Loading config from %s\n", cli.file) f, err := os.Open(cli.file) if err != nil { log.Fatal(err) } defer f.Close() err = json.NewDecoder(f).Decode(&settings) if err != nil { log.Fatal(err) } } else { log.Fatal("You need to pass a json file to -config") } // override whats in the settings with whats on the cli if cli.token != "" { log.Printf("Slack token passed via CLI: %s\n", cli.token) settings.Token = cli.token } if settings.Botname == "" || cli.botname != "" { settings.Botname = cli.botname } if settings.Token == "" { log.Fatal("You need to give me an API token!") } collins := c.New(settings.Collins.Username, settings.Collins.Password, settings.Collins.Host) // set up posting params postParams = slack.NewPostMessageParameters() //postParams.Username = settings.Botname //postParams.LinkNames = 1 // we will perform proper formatting per https://api.slack.com/docs/formatting, do make the server do no processing postParams.Parse = "none" api := slack.New(settings.Token) api.SetDebug(cli.debug) authresp, err := api.AuthTest() if err != nil { log.Fatal(err) } log.Printf("Authed with Slack successfully as %s (%s)\n", authresp.User, authresp.UserId) log.Printf("Creating new handler context with message handlers:\n") for _, v := range messagehandlers { log.Printf(" %s\n", v) } handlerContext = handlers.New(collins, authresp, api, messagehandlers) log.Printf("Starting up message handler") handlerContext.Run() }
func statusToSlack(api *slack.Client, my_name string, channel string, msg string) { params := slack.NewPostMessageParameters() params.Username = my_name params.IconEmoji = ":exclamation:" attachment := slack.Attachment{} attachment.Color = "#ffaa00" attachment.Title = "Alarm Status Update" attachment.Text = msg params.Attachments = []slack.Attachment{attachment} api.PostMessage(channel, "", params) }
func logToSlack(api *slack.Client, my_name string, channel string, msg string, fields []slack.AttachmentField) { params := slack.NewPostMessageParameters() params.Username = my_name params.IconEmoji = ":page_with_curl:" attachment := slack.Attachment{} attachment.Color = "#ffaa00" attachment.Title = "Log Entry" attachment.Text = msg attachment.Fields = fields params.Attachments = []slack.Attachment{attachment} api.PostMessage(channel, "", params) }
func motionToSlack(api *slack.Client, my_name string, channel string, image string, count int) { _, err := http.Get(image) chk(err) params := slack.NewPostMessageParameters() params.Username = my_name params.IconEmoji = ":rotating_light:" attachment := slack.Attachment{} attachment.Color = "#ff0000" attachment.Title = "Motion detected" attachment.Text = fmt.Sprintf("Motion events detected: %d", count) attachment.ImageURL = image params.Attachments = []slack.Attachment{attachment} api.PostMessage(channel, "", params) }
func lightsToSlack(api *slack.Client, my_name string, channel string, image string, level int) { _, err := http.Get(image) chk(err) params := slack.NewPostMessageParameters() params.Username = my_name params.IconEmoji = ":bulb:" attachment := slack.Attachment{} attachment.Color = "#00ff00" attachment.Title = "Lights detected" attachment.Text = fmt.Sprintf("Light level detected: %d", level) attachment.ImageURL = image params.Attachments = []slack.Attachment{attachment} api.PostMessage(channel, "", params) }
func (b *Bslack) Send(msg config.Message) error { flog.Debugf("Receiving %#v", msg) if msg.Account == b.Account { return nil } nick := msg.Username message := msg.Text channel := msg.Channel if b.Config.PrefixMessagesWithNick { message = nick + " " + message } if !b.Config.UseAPI { matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL} matterMessage.Channel = channel matterMessage.UserName = nick matterMessage.Type = "" matterMessage.Text = message err := b.mh.Send(matterMessage) if err != nil { flog.Info(err) return err } return nil } schannel, err := b.getChannelByName(channel) if err != nil { return err } np := slack.NewPostMessageParameters() if b.Config.PrefixMessagesWithNick == true { np.AsUser = true } np.Username = nick np.IconURL = config.GetIconURL(&msg, b.Config) if msg.Avatar != "" { np.IconURL = msg.Avatar } b.sc.PostMessage(schannel.ID, message, np) /* newmsg := b.rtm.NewOutgoingMessage(message, schannel.ID) b.rtm.SendMessage(newmsg) */ return nil }
func (n *slackNotifier) Notify(text string) error { channel, err := n.findChannel(n.channelName) if err != nil { return err } message := slack.NewPostMessageParameters() message.Text = text message.Username = n.name n.client.PostMessage(channel.Id, message.Text, message) if err != nil { return err } return nil }
func (w *workerImpl) Work() { channel, err := w.findChannel(w.channelName) if err != nil { workers.Log(w, err) return } message := slack.NewPostMessageParameters() message.Text = "test" message.Username = w.name w.client.PostMessage(channel.Id, message.Text, message) if err != nil { workers.Log(w, err) return } }
func Help(c *Context, m *slack.MessageEvent) (bool, error) { if c.isBotMention(m) && strings.Contains(m.Msg.Text, "help") { log.Printf("Got help message\n") p := slack.NewPostMessageParameters() //TODO sort this nonsense, cause the help output ordering keeps changing... helpfallbackslice := make([]string, len(helpinfo)) actionFields := make([]string, len(helpinfo)) descriptionFields := make([]string, len(helpinfo)) i := 0 for k, v := range helpinfo { helpfallbackslice[i] = fmt.Sprintf("%s - %s", k, v) actionFields[i] = k descriptionFields[i] = v i = i + 1 } /* this looks lame helpattachmentfields := []slack.AttachmentField{ slack.AttachmentField{ Title: "Action", Value: strings.Join(actionFields, "\n"), Short: true, }, slack.AttachmentField{ Title: "Description", Value: strings.Join(descriptionFields, "\n"), Short: true, }, } */ p.Attachments = []slack.Attachment{ slack.Attachment{ Title: fmt.Sprintf("%s help", c.Self.User), Fallback: strings.Join(helpfallbackslice, "\n"), Text: strings.Join(helpfallbackslice, "\n"), Color: "warning", //Fields: helpattachmentfields, }, } _, _, err := c.Slack.PostMessage(m.ChannelId, "", p) return true, err } else { return false, nil } }
func (s *SlackLink) sendSlackMessages() { defer s.wg.Done() for msg := range s.slackOut { params := slack.NewPostMessageParameters() params.Markdown = !msg.DisableMarkdown if msg.As != nil { params.AsUser = false params.Username = msg.As.Name params.IconURL = "https://minotar.net/avatar/" + url.QueryEscape(strings.ToLower(msg.As.Name)) + "/48.png" } else { params.AsUser = true } s.slack.PostMessage(msg.To, msg.Message, params) } }
func AssetTag(c *Context, m *slack.MessageEvent) (bool, error) { // dont process if this came from a bot (like ourselves). avoids looping if isBotMessage(m) { return false, nil } // handle messages with any asset tags present - we will turn them into collins links tags := extractAssetTags(m.Msg.Text) if len(tags) > 0 { assets := c.lookupAssetsFromTags(tags) // send a message back to that channel with the links to the assets p := slack.NewPostMessageParameters() p.Attachments = make([]slack.Attachment, len(assets)) for i, asset := range assets { p.Attachments[i] = c.slackAssetAttachment(asset) } _, _, err := c.Slack.PostMessage(m.ChannelId, "", p) return true, err } return false, nil }
func AssetHostname(c *Context, m *slack.MessageEvent) (bool, error) { // handle messages with any hostnames present - if assets, link them if isBotMessage(m) { return false, nil } hosts := extractHostnames(m.Msg.Text) if len(hosts) > 0 { assets := []collins.Asset{} for _, host := range hosts { //TODO! log.Printf("Found host %s in message: %s\n", host, m.Msg.Text) a, err := c.Collins.Find(map[string]string{}, map[string]string{"hostname": host}) if err != nil || a == nil { log.Printf("Error trying to find host %s: %s\n", host, err.Error()) continue } if len(a) > 1 { log.Printf("Multiple assets found matching hostname %s: %+v\n", a) } else if len(a) == 0 { log.Printf("Nothing found for hostname %s\n", host) } else { assets = append(assets, a[0]) } } if len(assets) > 0 { log.Printf("Found assets: %+v\n", assets) p := slack.NewPostMessageParameters() //old style list assets //p.Attachments = []slack.Attachment{*slackAssetsAttachment(assets)} p.Attachments = make([]slack.Attachment, len(assets)) for i, asset := range assets { p.Attachments[i] = c.slackAssetAttachment(asset) } _, _, err := c.Slack.PostMessage(m.ChannelId, "", p) return true, err } } return false, nil }
func doYoutubeMessage(liveStreamItem youtubeLiveStreamsResponseItem) { messageParams := slack.NewPostMessageParameters() messageParams.AsUser = true messageParams.Parse = "full" messageParams.LinkNames = 1 messageParams.UnfurlMedia = true messageParams.UnfurlLinks = true messageParams.EscapeText = false var channelTitle = liveStreamItem.Snippet.ChannelTitle if channelTitle == "" { channelTitle = youtubeStreamDetails[liveStreamItem.Snippet.ChannelID].Snippet.Title } if channelTitle == "" { channelTitle = "Someone Forgot To Set A Channel Title" } messageParams.Attachments = append(messageParams.Attachments, slack.Attachment{ Title: fmt.Sprintf( "Watch %s play %s", channelTitle, liveStreamItem.Snippet.Title, ), TitleLink: fmt.Sprintf(youtubeLinkURL, liveStreamItem.ID.VideoId), ThumbURL: liveStreamItem.Snippet.Thumbnails.Default.URL, }) _, _, err := slackClient.PostMessage( slackCFG.Channel, fmt.Sprintf( "*%s* has begun streaming *%s*\n\n%s", channelTitle, liveStreamItem.Snippet.Title, liveStreamItem.Snippet.Description, ), messageParams, ) if err != nil { log.Printf("[yt] error sending message to channel: %s", err.Error()) } }
func (s *SlackBot) HandleJoin(e Event) { time.Sleep(600 * time.Millisecond) phrases := []string{ "Wynwood-Tech", "the best internet group since sliced bread", "the dark abyss", "Jamrock", "the interwebz", "the beginning of the rest of your life", } msgParams := slack.NewPostMessageParameters() msgParams.AsUser = true msgParams.LinkNames = 1 msgString := fmt.Sprintf( "Hey @%v, welcome to %s! Make sure you update your avatar.", e.User.Name, phrases[rand.Intn(len(phrases))], ) s.RTM.PostMessage("#general", msgString, msgParams) msgString = "I am Evil Bot here to serve and entertain. My commands are largely Easter-eggs... but you can always ask for !top5." s.RTM.PostMessage("#general", msgString, msgParams) }
func main() { log.SetPrefix("TWEELACK ") viper.SetConfigName("config") viper.AddConfigPath(".") viper.AddConfigPath("$HOME/.tweelack") err := viper.ReadInConfig() if err != nil { log.Fatalln(err) } twitterConsumerKey := viper.GetString("twitter.consumer.key") if len(twitterConsumerKey) == 0 { log.Fatalln("Twitter consumer key required") } twitterConsumerSecret := viper.GetString("twitter.consumer.secret") if len(twitterConsumerSecret) == 0 { log.Fatalln("Twitter consumer secret required") } twitterTokenValue := viper.GetString("twitter.token.value") if len(twitterTokenValue) == 0 { log.Fatalln("Twitter token value required") } twitterTokenSecret := viper.GetString("twitter.token.secret") if len(twitterTokenSecret) == 0 { log.Fatalln("Twitter token secret required") } if TwitterHandle = viper.GetString("twitter.handle"); len(TwitterHandle) == 0 { log.Fatalln("Twitter handle required") } if TweetCount = viper.GetInt("twitter.count"); TweetCount == 0 { TweetCount = 1 } if TwitterTimeout = viper.GetDuration("twitter.timeout"); TwitterTimeout == 0 { TwitterTimeout = 1 } TwitterHashtag = viper.GetString("twitter.hashtag") slackToken := viper.GetString("slack.token") if len(slackToken) == 0 { log.Fatalln("Slack token required") } if SlackChannel = viper.GetString("slack.channel"); len(SlackChannel) == 0 { SlackChannel = "general" } if Purpose = viper.GetString("slack.purpose"); len(Purpose) == 0 { Purpose = "post" } SlackMessageParameters = slack.NewPostMessageParameters() SlackMessageParameters.AsUser = viper.GetBool("slack.parameters.as_user") SlackMessageParameters.Username = viper.GetString("slack.parameters.username") SlackMessageParameters.IconURL = viper.GetString("slack.parameters.icon.url") SlackMessageParameters.IconEmoji = viper.GetString("slack.parameters.icon.emoji") anaconda.SetConsumerKey(twitterConsumerKey) anaconda.SetConsumerSecret(twitterConsumerSecret) TwitterApi = anaconda.NewTwitterApi(twitterTokenValue, twitterTokenSecret) SlackApi = slack.New(slackToken) UrlValues = url.Values{} UrlValues.Set("screen_name", TwitterHandle) UrlValues.Set("exclude_replies", "true") UrlValues.Set("include_rts", "false") if channels, err := SlackApi.GetChannels(true); err == nil { for _, channel := range channels { if channel.Name == SlackChannel { SlackChannel = channel.ID break } } } PostToSlack(FetchTweets()) }
func (r *Response) MParams() slack.PostMessageParameters { msgParams := slack.NewPostMessageParameters() msgParams.AsUser = true msgParams.LinkNames = 1 return msgParams }
func (c *LogCommand) Run(m *sl.MessageEvent, args ...string) { loggers := system.LoggerHookInstance.GetRecords() if len(args) == 0 { params := sl.NewPostMessageParameters() params.Attachments = []sl.Attachment{sl.Attachment{ Color: "good", Fields: []sl.AttachmentField{}, }} for name := range loggers { params.Attachments[0].Fields = append(params.Attachments[0].Fields, sl.AttachmentField{ Title: name, }) } c.SendPostMessage(m.Channel, "Available components", params) return } showItemsCount := system.MaxItems if len(args) == 2 { var err error if showItemsCount, err = strconv.Atoi(args[1]); err != nil { c.SendMessage(m.Channel, "Specified number of records to display is not a number") return } } component, ok := loggers[args[0]] if !ok { c.SendMessagef(m.Channel, "Component *%s* does't exists", args[0]) return } if len(component) == 0 { c.SendMessagef(m.Channel, "Log empty for *%s* component", args[0]) return } skip := -1 if showItemsCount < len(component) { skip = len(component) - showItemsCount } else { showItemsCount = len(component) } var ( color string index int64 attachment sl.Attachment ) params := sl.NewPostMessageParameters() params.Attachments = make([]sl.Attachment, showItemsCount) for i, c := range component { if i < skip { continue } switch c.Level { case logrus.DebugLevel: color = "#999999" case logrus.InfoLevel: color = "#5bc0de" case logrus.WarnLevel: color = "warning" case logrus.ErrorLevel: color = "danger" case logrus.FatalLevel: color = "danger" case logrus.PanicLevel: color = "danger" default: color = "good" } attachment = sl.Attachment{ Color: color, Title: c.Time.Format(time.RFC1123Z), Text: c.Message, Fields: []sl.AttachmentField{}, } for field, value := range component[i].Data { if field == "component" { continue } attachment.Fields = append(attachment.Fields, sl.AttachmentField{ Title: field, Value: fmt.Sprintf("%v", value), Short: true, }) } params.Attachments[index] = attachment index = index + 1 } c.SendPostMessage(m.Channel, fmt.Sprintf("Show last *%d* entries for *%s* component", showItemsCount, args[0]), params) }
func (s *SlackSession) handleMessage(User string, Channel string, msg *slack.Msg) { tx, err := s.Db.Begin() if err != nil { goto fail } defer tx.Rollback() // Check user type; ignore bots { if msg.SubType == "bot_message" { return } var is_bot bool if err = tx.QueryRow("select user_is_bot from users where user_id = $1 and team_id = $2", User, s.TeamID).Scan(&is_bot); err != nil { s.log.WithError(err).Warn("Failed to read row") goto fail } if is_bot { s.log.Debug("Ignoring message; from bot") return } } if match := rxProposal.FindStringSubmatch(msg.Text); match != nil { s.log.WithField("matchgroups", fmt.Sprintf("%#v", match)).Info("Saw proposal") topic := match[1] comment := match[2] _, err = tx.Exec( "INSERT INTO topics (team_id, topic_channel, topic_name, topic_comment) "+ "VALUES ($1, $2, $3, nullif($4,''))", s.TeamID, Channel, topic, comment) if err != nil { // TODO: report error in channel s.log.WithError(err).Info("Failed to insert proposal") goto fail } pmp := slack.NewPostMessageParameters() pmp.AsUser = true //pmp.Username = s.rtm.GetInfo().User.Name _, _, err = s.rtm.PostMessage(Channel, fmt.Sprintf("Voting is now open on %s", topic), pmp) if err != nil { log.WithError(err).Info("Failed to post voting open message") } } else if match := rxVote.FindStringSubmatch(msg.Text); match != nil { var value decimal.Decimal topic := match[2] log := s.log.WithFields(log.Fields{ "topic": topic, "user": User, "channel": msg.Channel, "user_msg": msg.Text, }) if value, err = decimal.NewFromString(match[1]); err != nil { log.WithError(err).Info("Failed to parse vote value") return } comment := match[3] _, err = tx.Exec( "INSERT INTO votes (team_id, topic_name, user_id, vote_value, vote_comment) "+ "VALUES ($1, $2, $3, $4, nullif($5, '')) "+ "ON CONFLICT (topic_name, team_id, user_id) "+ "DO UPDATE SET (vote_value, vote_comment) = ($4, nullif($5, ''))", s.TeamID, topic, User, value, comment) if err != nil { log.WithError(err).Info("Failed to insert vote") } log.WithField("matchgroups", fmt.Sprintf("%#v", match)).Info("Saw vote") } else if match := s.rxAtMessage.FindStringSubmatch(msg.Text); match != nil { args, err := shlex.Split(match[1], true) pmp := slack.NewPostMessageParameters() pmp.AsUser = true pmp.EscapeText = false user_pfx := fmt.Sprintf("<@%s>: ", msg.User) if err != nil || len(args) < 1 { s.rtm.PostMessage(Channel, user_pfx+" Syntax error: %s"+err.Error(), pmp) return } switch strings.ToLower(args[0]) { case "howdy": s.rtm.PostMessage(Channel, user_pfx+" Howdy neighbor!", pmp) case "status": if len(args) < 2 { topics := []map[string]interface{}{} rows, err := tx.Query( "SELECT topic_name, COALESCE(topic_comment, ''), COUNT(user_id), SUM(vote_value) "+ "FROM topics NATURAL LEFT JOIN (votes NATURAL JOIN users) "+ "WHERE topic_open AND team_id = $1 AND topic_channel = $2 "+ "GROUP BY topic_name, topic_channel, team_id, topic_comment", s.TeamID, Channel) if err != nil { log.WithError(err).Error("Failed to query topics") return } for rows.Next() { var ( name, comment string count int sum decimal.Decimal ) rows.Scan(&name, &comment, &count, &sum) topics = append(topics, map[string]interface{}{ "name": name, "comment": comment, "nvotes": count, "total": sum, }) } buffer := &bytes.Buffer{} topicSummary.Execute(buffer, topics) s.rtm.PostMessage(Channel, buffer.String(), pmp) } default: s.rtm.PostMessage(Channel, fmt.Sprintf("%s You seem confused; you said `%#v`", user_pfx, args), pmp) } } tx.Commit() return fail: } /* Sample message var foo = &slack.MessageEvent{Msg: slack.Msg{ Type: "message", Channel: "C0KGNAP7A", User: "******", Text: "More testage", Timestamp: "1454444512.000011", IsStarred: false, PinnedTo: []string(nil), Attachments: []slack.Attachment(nil), Edited: (*slack.Edited)(nil), SubType: "", Hidden: false, DeletedTimestamp: "", EventTimestamp: "", BotID: "", Username: "", Icons: (*slack.Icon)(nil), Inviter: "", Topic: "", Purpose: "", Name: "", OldName: "", Members: []string(nil), File: (*slack.File)(nil), Upload: false, Comment: (*slack.Comment)(nil), ItemType: "", ReplyTo: 0, Team: "T06RWKEF3"}} */ func (s *SlackSession) updateUser(user slack.User) { tx, err := s.Db.Begin() if err != nil { goto fail } defer tx.Rollback() if _, err = tx.Exec( "INSERT INTO users (team_id, user_id, user_name, user_is_bot) VALUES ($3, $2, $1, $4) "+ "ON CONFLICT (team_id, user_id) DO UPDATE SET (user_name, user_is_bot) = ($1, $4)", user.Name, user.ID, s.TeamID, user.IsBot); err != nil { goto fail } if err = tx.Commit(); err != nil { goto fail } return fail: if err != nil { s.log.WithError(err).WithField("user", user.ID).Error("Failed to refresh user in db") } } func (s *SlackSession) updateTeam(team *slack.Team) { tx, err := s.Db.Begin() if err != nil { goto fail } defer tx.Rollback() if _, err = tx.Exec("UPDATE teams SET (team_name) = ($1) WHERE team_id = $2", team.Name, team.ID); err != nil { goto fail } if err = tx.Commit(); err != nil { goto fail } return fail: if err != nil { s.log.WithError(err).Error("Failed to refresh team in db") } }
func mindTwitch() { log.Println("[tw] Starting up") if buf, err := ioutil.ReadFile(twitchConfigFile); err != nil { log.Fatal(err) } else { if err := json.Unmarshal(buf, &twitchCFG); err != nil { log.Fatal(err) } } client, err := twch.NewClient(twitchCFG.Key, nil) if err != nil { log.Fatal(err) } var active = map[string]int{} var lastActive = map[string]time.Time{} var twitchTicker = time.Tick(time.Second) for { streamers := map[string]bool{} nextRun := time.Now().Add(1 * time.Minute) for _, c := range twitchCFG.Channels { <-twitchTicker found := false if s, _, err := client.Streams.GetStream(c); err == nil { if s.ID != nil { details, _ := json.MarshalIndent(s, "\t", "\t") detailsString := string(details) streamers[c] = true sid := *s.ID if oid, ok := active[c]; ok { if oid != sid { found = true log.Printf( "[tw] Found changed stream for %s id: %d -> %d\n%s", c, oid, *s.ID, detailsString, ) } else { lastActive[c] = time.Now() log.Printf( "[tw] Continued twitch stream for %s id: %d\n", c, *s.ID, ) } } else { found = true log.Printf( "[tw] Found twitch stream for %s id: %d\n%s", c, *s.ID, detailsString, ) } if found { active[c] = sid lastSeen := time.Now().Add(0 - (24 * time.Hour)) if ls, ok := lastActive[c]; ok { lastSeen = ls } lastActive[c] = time.Now() if time.Now().Sub(lastSeen) < (15 * time.Minute) { log.Printf( "[tw] Skipping twitch %s because of recent activity %s ago", c, time.Now().Sub(lastSeen).String(), ) continue } displayName := c if s.Channel.DisplayName != nil { displayName = *s.Channel.DisplayName } game := "something" if s.Game != nil { game = *s.Game } messageParams := slack.NewPostMessageParameters() messageParams.AsUser = true messageParams.Parse = "full" messageParams.LinkNames = 1 messageParams.UnfurlMedia = true messageParams.UnfurlLinks = true messageParams.EscapeText = false messageParams.Attachments = append(messageParams.Attachments, slack.Attachment{ Title: fmt.Sprintf("Watch %s play %s", displayName, game), TitleLink: *s.Channel.URL, ThumbURL: *s.Preview.Small, }) _, _, err := slackClient.PostMessage( slackCFG.Channel, fmt.Sprintf("*%s* has begun streaming *%s* at %s", *s.Channel.Name, game, *s.Channel.URL), messageParams, ) if err != nil { log.Printf("[tw] Error sending slack message: %s", err.Error()) } } } else { log.Printf("[tw] Found no twitch stream for %s", c) } } else { log.Printf("[tw] Error checking twitch stream: %s", err.Error()) } } for k := range active { if _, ok := streamers[k]; !ok { log.Printf("[tw] Removing twitch stream: %s", k) delete(active, k) } } for k := range lastActive { if time.Now().Sub(lastActive[k]) > (30 * time.Minute) { log.Printf("[tw] Removing last activity marker for twitch stream: %s", k) delete(lastActive, k) } } sleepFor := nextRun.Sub(time.Now()) if sleepFor < (15 * time.Second) { sleepFor = 15 * time.Second } time.Sleep(sleepFor) } }
func main() { var info slack.Info quothPattern := regexp.MustCompile(`^(?i:quoth(?:\s+(\S+))?)`) deletePattern := regexp.MustCompile(`^(?i:forget ([A-Za-z0-9]{24}))`) bracketRemovalPattern := regexp.MustCompile(`<(.*?)>`) rand.Seed(time.Now().UnixNano()) // Read config.toml config, err := toml.LoadFile("config.toml") if err != nil { fmt.Fprintln(os.Stderr, "Error opening config file. Did you remember to `cp config.toml.example config.toml`?\n", err.Error()) os.Exit(1) } apiToken := config.Get("slack-quoter.api_token").(string) channelKey := config.Get("slack-quoter.channel_key").(string) mongoDBServer := config.Get("slack-quoter.mongodb_server").(string) session, err := mgo.Dial(mongoDBServer) if err != nil { panic(err) } defer session.Close() col := session.DB("slack").C("quotes") api := slack.New(apiToken) api.SetDebug(true) postMessageParams := slack.NewPostMessageParameters() postMessageParams.AsUser = true postMessageParams.UnfurlLinks = true rtm := api.NewRTM() go rtm.ManageConnection() Loop: for { select { case msg := <-rtm.IncomingEvents: fmt.Print("Event Received: ") switch ev := msg.Data.(type) { case *slack.HelloEvent: // Ignore hello case *slack.ConnectedEvent: info = *(ev.Info) fmt.Println("Connection counter:", ev.ConnectionCount) // Replace #general with your Channel ID case *slack.MessageEvent: var quote MessageWithID if ev.Channel != channelKey { continue } if matches := quothPattern.FindStringSubmatch(ev.Text); matches != nil { // Ignore bot users and ourselves. requester := info.GetUserByID(ev.User) if requester != nil && (requester.IsBot || info.User.ID == ev.User) { continue } var user *slack.User if matches[1] != "" { user = getUserForName(matches[1], info) } var query *mgo.Query if user != nil { query = col.Find(bson.M{"user": user.ID}) } else { query = col.Find(nil) } count, err := query.Count() if err != nil { fmt.Println("Error gettings count: ", err) continue } if count == 0 { rtm.SendMessage(rtm.NewOutgoingMessage("No quotes. Consider better posting.", channelKey)) continue } query.Skip(rand.Intn(count)).One("e) // We have a random quote now. Print to the channel. if user == nil { user = info.GetUserByID(quote.User) } var name string if user != nil { name = user.Name } else { name = "UNKNOWN" } quoteText := bracketRemovalPattern.ReplaceAllString(quote.Text, "$1") api.PostMessage(channelKey, fmt.Sprintf("Quoth %s:\t\t\t\t\t\t(%s)\n%s", name, quote.ID.Hex(), quoteText), postMessageParams) } else if matches := deletePattern.FindStringSubmatch(ev.Text); matches != nil { err := col.RemoveId(bson.ObjectIdHex(matches[1])) if err == mgo.ErrNotFound { rtm.SendMessage(rtm.NewOutgoingMessage(fmt.Sprintf("What %s? No %ss here.", matches[1], matches[1]), channelKey)) } else { rtm.SendMessage(rtm.NewOutgoingMessage("Beleted "+matches[1]+".", channelKey)) } } case *slack.PresenceChangeEvent: fmt.Printf("Presence Change: %v\n", ev) case *slack.LatencyReport: fmt.Printf("Current latency: %v\n", ev.Value) case *slack.RTMError: fmt.Printf("Error: %s\n", ev.Error()) case *slack.InvalidAuthEvent: fmt.Printf("Invalid credentials") break Loop case *slack.StarAddedEvent: if ev.Item.Type != "message" { continue } col.Upsert(ev.Item.Message.Msg, ev.Item.Message.Msg) default: // Ignore other events.. // fmt.Printf("Unexpected: %v\n", msg.Data) } } } }