-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from Crazybus/moon_lettuce
First commit for moonsla
- Loading branch information
Showing
6 changed files
with
441 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
moonsla |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
language: go | ||
|
||
go: | ||
- "1.10" | ||
|
||
services: | ||
- docker | ||
|
||
script: | ||
- go test -v -race -coverprofile=coverage.txt -covermode=atomic | ||
- wget https://github.com/Crazybus/lope/releases/download/0.2.0/lope-linux_amd64 -O lope && chmod +x lope | ||
- ./lope -workDir /go/src/github.com/Crazybus/moonsla -blacklist GO golang:1.10 '/usr/local/go/bin/go get -v ./... && /usr/local/go/bin/go run build/build.go' | ||
|
||
after_success: | ||
- bash <(curl -s https://codecov.io/bash) | ||
|
||
deploy: | ||
provider: releases | ||
api_key: | ||
secure: hT+TBmMhj8yFvGfTOGPhoVuiINprm600JijpT//kgO2PBiiQ/Tcc+ShEiXGXNoXb+mngMj+w4NsPbNjFR6K1TIxsyFDrmN2RvKi01SJZMKgpbJH5+VmkMPHJX0AxMcHjYTBkz9inM6PLzFsSHrDO296gjGpM4xMvh4wuOYz/4JH9dLcsn6BdchhrA1ipKrHwsDU6DaK9YvZwjRpB3eO4s5woUuYfHgr9OkAPLCUuh6u+HCRhtxH8F9aNtNVlHm43u9lLcwJ41YVycpfRNEhHp30Nrghn4PciPoqISJVyRSSva96HSlR9+T55aCGY0ch762k9P6CeP3OQfK/2s8v5Fcq40ScUm+GLntRv49O1eJuqBkI7HImnHzrb1w329MgJTijFVxf3W7jEj4mjyttuyScMzd9b7/ERRGUzhqqQx488ICw3tU9+fnfguhEaNt3DanyijT6ZYqVA6TQTanc/z+w+uQTy7w92mRocNNYPJA17yL8BOS7EJb5vu0+ifVyXco+5McTBcJUSm+zqFzLm2Ey3VGs4eVbCY3r4XvOSr3P3MjR1iB8u+fBeVqL6TPi+p0eRPtSHjoRRPjsmoupv9fpmRIDA7hXi3GoT9HZB8fSfFtKoEgfi7lz67UPwQXADhIEnTD5SKptt897lvq1DOj4lDDETakdkBkBKIBWdh4w= | ||
file_glob: true | ||
file: build/moonsla* | ||
skip_cleanup: true | ||
on: | ||
tags: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,40 @@ | ||
# moonsla | ||
View all the slack messages! | ||
# Moonsla | ||
|
||
[![Build Status](https://travis-ci.org/Crazybus/moonsla.svg?branch=master)](https://travis-ci.org/Crazybus/moonsla) | ||
|
||
Moonsla is a small tool to display a stream of slack messages in a single view. | ||
|
||
It looks something like this | ||
|
||
``` | ||
10:42:37 - general - Michael Russell: Weird I never knew that slack threads were just normal messages | ||
10:42:55 - random - Someone Else: Sweet Potato! | ||
10:43:37 - general - John Smith: Can people please stop using threads for everything! | ||
``` | ||
|
||
# Usage | ||
|
||
If you don't have one already you will need to generate a [slack API token](https://api.slack.com/custom-integrations/legacy-tokens) | ||
|
||
You need to set this to your `SLACK_TOKEN` environment variable | ||
``` | ||
export SLACK_TOKEN='xoxp-1231231231232323-123123123123-123123123123123-c91238917239123' | ||
moonsla | ||
``` | ||
|
||
You can also set `SLACK_CHANNELS` to a comma separated list of channels to filter for | ||
``` | ||
export SLACK_CHANNELS='general,random' | ||
``` | ||
|
||
# Why? | ||
|
||
I'm not a fan of notifications because they are very intrusive. Instead I used to keep slack always open with the slackbot channel active (so I don't accidentally type shell commands into #general). Whenever I had a spare moment I would then check each slack channel to see if there was anything that needed my attention. This took a bit too long and quite often the message would be bot telling me I had just submitted a pull request | ||
|
||
# Future | ||
|
||
* Fix channel naming for slackbot and private channels | ||
* Improve formatting of messages so that sub-teams, urls and everything else is formatted as expected | ||
* Automatically link to the slack message so it is easy to open up the message from moonsla in slack | ||
* Support multiple slack workspaces | ||
* Add an optional web interface to make things look pretty and allow displaying of images |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package main | ||
|
||
import ( | ||
"crypto/sha256" | ||
"fmt" | ||
"io" | ||
"log" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
) | ||
|
||
var buildDir = filepath.FromSlash("build/") | ||
|
||
var operatingSystems = [...]string{ | ||
"darwin", | ||
"linux", | ||
"windows", | ||
} | ||
|
||
var archs = [...]string{ | ||
"386", | ||
"amd64", | ||
} | ||
|
||
func checksum(goos string, goarch string) error { | ||
file := buildDir + "moonsla-" + goos + "_" + goarch | ||
f, err := os.Open(file) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
|
||
h := sha256.New() | ||
if _, err := io.Copy(h, f); err != nil { | ||
return err | ||
} | ||
sumFile := file + ".sha256" | ||
hash := fmt.Sprintf("%x", h.Sum(nil)) | ||
fmt.Println(hash, file) | ||
|
||
hashFile, err := os.Create(sumFile) | ||
if err != nil { | ||
return err | ||
} | ||
defer hashFile.Close() | ||
|
||
_, err = hashFile.WriteString(hash) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func build(goos string, goarch string) error { | ||
os.Setenv("GOOS", goos) | ||
os.Setenv("GOARCH", goarch) | ||
|
||
cmd := exec.Command( | ||
"/usr/local/go/bin/go", | ||
"build", | ||
"-v", | ||
"-o", | ||
buildDir+"moonsla-"+goos+"_"+goarch, | ||
) | ||
return cmd.Run() | ||
} | ||
|
||
func main() { | ||
for _, goos := range operatingSystems { | ||
for _, goarch := range archs { | ||
err := build(goos, goarch) | ||
if err != nil { | ||
log.Printf("Failed to build %s/%s with error: %v", goos, goarch, err) | ||
os.Exit(1) | ||
} | ||
err = checksum(goos, goarch) | ||
if err != nil { | ||
log.Printf("Failed to generate checksums for %s/%s with error: %v", goos, goarch, err) | ||
os.Exit(1) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/nlopes/slack" | ||
) | ||
|
||
func getChannels(api *slack.Client) (channels map[string]string) { | ||
channels = make(map[string]string) | ||
chans, _ := api.GetChannels(true) | ||
for _, c := range chans { | ||
channels[c.ID] = c.Name | ||
} | ||
return channels | ||
} | ||
|
||
func getUsers(api *slack.Client) (users map[string]string) { | ||
users = make(map[string]string) | ||
allUsers, _ := api.GetUsers() | ||
for _, u := range allUsers { | ||
users[u.ID] = u.RealName | ||
} | ||
return users | ||
} | ||
|
||
func getTimeStamp(ts string) (timeStamp time.Time) { | ||
i, err := strconv.ParseInt(strings.Split(ts, ".")[0], 10, 64) | ||
if err != nil { | ||
panic(err) | ||
} | ||
timeStamp = time.Unix(i, 0) | ||
return timeStamp | ||
} | ||
|
||
func formatMentions(msg string, users map[string]string) string { | ||
re := regexp.MustCompile("<@U.*?>") | ||
matches := re.FindAllString(msg, -1) | ||
for _, m := range matches { | ||
userID := m[2:(len(m) - 1)] | ||
username, ok := users[userID] | ||
if ok { | ||
username = "@" + username | ||
msg = strings.Replace(msg, m, username, -1) | ||
} | ||
} | ||
return msg | ||
} | ||
|
||
func filterChannel(name string, channels map[string]string, whitelist []string) (whitelisted bool, cName string) { | ||
whitelisted = false | ||
|
||
cName, ok := channels[name] | ||
if ok { | ||
for _, w := range whitelist { | ||
if cName == w { | ||
whitelisted = true | ||
} | ||
} | ||
} else { | ||
whitelisted = true | ||
cName = name | ||
} | ||
|
||
if len(whitelist) == 0 { | ||
whitelisted = true | ||
} | ||
|
||
return whitelisted, cName | ||
} | ||
|
||
func main() { | ||
|
||
slackToken, ok := os.LookupEnv("SLACK_TOKEN") | ||
if !ok { | ||
fmt.Println("Please set your SLACK_TOKEN") | ||
} | ||
api := slack.New(slackToken) | ||
|
||
logger := log.New(os.Stdout, "slack-bot: ", log.Lshortfile|log.LstdFlags) | ||
slack.SetLogger(logger) | ||
api.SetDebug(false) | ||
|
||
channels := getChannels(api) | ||
fmt.Printf("Found %v channels\n", len(channels)) | ||
|
||
users := getUsers(api) | ||
fmt.Printf("Found %v users\n", len(users)) | ||
|
||
rtm := api.NewRTM() | ||
go rtm.ManageConnection() | ||
|
||
whitelist := strings.Split(os.Getenv("SLACK_CHANNELS"), ",") | ||
fmt.Printf("Channel whitelist: %v\n", whitelist) | ||
|
||
for msg := range rtm.IncomingEvents { | ||
|
||
switch ev := msg.Data.(type) { | ||
|
||
case *slack.MessageEvent: | ||
|
||
// Skip empty messages | ||
if ev.Text == "" { | ||
continue | ||
} | ||
|
||
whitelisted, cName := filterChannel(ev.Channel, channels, whitelist) | ||
if !whitelisted { | ||
continue | ||
} | ||
|
||
// Map the users ID to a username if it exists | ||
uName, ok := users[ev.User] | ||
if !ok { | ||
uName = ev.User | ||
} | ||
|
||
t := getTimeStamp(ev.EventTimestamp) | ||
timeStamp := fmt.Sprintf("%02d:%02d:%02d", t.Hour(), t.Minute(), t.Second()) | ||
|
||
msg := formatMentions(ev.Text, users) | ||
|
||
fmt.Printf("%v - %v - %v: %v\n", timeStamp, cName, uName, msg) | ||
|
||
case *slack.RTMError: | ||
fmt.Printf("Error: %s\n", ev.Error()) | ||
|
||
case *slack.InvalidAuthEvent: | ||
fmt.Printf("Invalid credentials") | ||
return | ||
|
||
default: | ||
// Ignore other events.. | ||
// fmt.Printf("Unexpected: %v\n", msg.Data) | ||
} | ||
} | ||
} |
Oops, something went wrong.