Skip to content

Commit

Permalink
Willnilges/refactor (#49)
Browse files Browse the repository at this point in the history
* Add stub of age checking to pinned reminder func

* go fmt

* Ah man circular dependencies.

Might be better to do global variables, else do a big "cspService" or
something. IDK man. Go sucks.

* Revert "Ah man circular dependencies."

This reverts commit 4257b55.

* Add dedicated event handler object

* Move BlockKit response to util file

Makes the logic more readable.

* Beeeeeg refactor

* God this app is such a mess

* Make CSP take care of cron

* Remove cron from Dockerfile
  • Loading branch information
WillNilges authored Dec 4, 2023
1 parent fe66e5f commit 13e155c
Show file tree
Hide file tree
Showing 12 changed files with 657 additions and 574 deletions.
3 changes: 3 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ CSP_CURRENT_EMOJI=trophy
CSP_NOMINAL_MESSAGE=All systems operational
CSP_NOMINAL_SENT_BY=Your Support Team <3
CSP_HELP_LINK=Having problems? Send a message to <a href="https://nycmesh.slack.com/archives/C679UKBUK">#support on Slack</a>, or head to the <a href="https://nycmesh.net/support">Support Page</a>.

CSP_REMINDER_SCHEDULE=* 17 * * *

6 changes: 1 addition & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,7 @@ COPY --from=builder /build/cursed-status-page ./
COPY static/. ./static/
COPY templates/. ./templates/

# Set up cron to send pin reminders daily
COPY crontab /etc/cron.d/send-reminders
RUN chmod 0644 /etc/cron.d/send-reminders; crontab /etc/cron.d/send-reminders; touch /var/log/cron.log

RUN apk add --no-cache tzdata

ENTRYPOINT crond && ./cursed-status-page
ENTRYPOINT ./cursed-status-page

1 change: 0 additions & 1 deletion crontab

This file was deleted.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/robfig/cron/v3 v3.0.0 // indirect
github.com/slack-go/slack v0.12.3 // indirect
github.com/tidwall/gjson v1.17.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/slack-go/slack v0.12.3 h1:92/dfFU8Q5XP6Wp5rr5/T5JHLM5c5Smtn53fhToAP88=
github.com/slack-go/slack v0.12.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
94 changes: 39 additions & 55 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,21 @@ import (

"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
"github.com/slack-go/slack"
"github.com/slack-go/slack/socketmode"
"github.com/robfig/cron/v3"
)

type Config struct {
OrgName string
LogoURL string
FaviconURL string

SlackTeamID string
SlackAccessToken string
SlackAppToken string
SlackStatusChannelID string
SlackTeamID string
SlackAccessToken string
SlackAppToken string
SlackStatusChannelID string
SlackForwardChannelID string
SlackBotID string
SlackTruncation string
SlackBotID string
SlackTruncation string

StatusNeutralColor string
StatusOKColor string
Expand All @@ -35,26 +34,13 @@ type Config struct {
NominalMessage string
NominalSentBy string
HelpMessage string
}

type StatusUpdate struct {
Text string
SentBy string
TimeStamp string
BackgroundClass string
IconFilename string
ReminderSchedule string
}

// Useful global variables
var config Config

var globalChannelHistory []slack.Message

var globalUpdates []StatusUpdate
var globalPinnedUpdates []StatusUpdate

var slackAPI *slack.Client
var slackSocket *socketmode.Client

func init() {
// Load environment variables one way or another
err := godotenv.Load()
Expand Down Expand Up @@ -85,48 +71,46 @@ func init() {
config.NominalSentBy = os.Getenv("CSP_NOMINAL_SENT_BY")
config.HelpMessage = os.Getenv("CSP_HELP_LINK")

pinReminders := flag.Bool("send-reminders", false, "Check for pinned items and send a reminder if it's been longer than a day.")
config.ReminderSchedule = os.Getenv("CSP_REMINDER_SCHEDULE")
}

func main() {
useSlack := flag.Bool("slack", true, "Launch an instance of CSP to connect to Slack")

pinReminders := flag.Bool("send-reminders", false, "Check for pinned items and send a reminder if it's been longer than a day.")
flag.Parse()

slackAPI := slack.New(config.SlackAccessToken, slack.OptionAppLevelToken(config.SlackAppToken))
slackSocket = socketmode.New(slackAPI,
socketmode.OptionLog(log.New(os.Stdout, "socketmode: ", log.Lshortfile|log.LstdFlags)),
)
var csp CSPService

// Get the channel history
globalChannelHistory, err = getChannelHistory()
if err != nil {
log.Fatal(err)
if *useSlack {
cspSlack, err := NewCSPSlack()
csp = &cspSlack
if err != nil {
log.Fatalf("Could not set up new CSPSlack service. %s", err)
}
}


// Get some deets we'll need from the slack API
authTestResponse, err := slackAPI.AuthTest()
config.SlackBotID = authTestResponse.UserID

// Send out reminders about pinned messages.
if *pinReminders {
sendReminders()
os.Exit(0)
}

// Initialize the actual data we need for the status page
globalUpdates, globalPinnedUpdates, err = buildStatusPage()
if err != nil {
log.Fatal(err)
log.Printf("Setting up reminders. Schedule is %s\n", config.ReminderSchedule)
c := cron.New()
c.AddFunc(config.ReminderSchedule, func() {
log.Println("CHOM")
err := csp.SendReminders()
if err != nil {
log.Printf("Cronjob returned error: %s\n", err)
}
})
c.Start()
}
}

func main() {
go runSocket() // Start the Slack Socket
go csp.Run()

app := gin.Default()
app.LoadHTMLGlob("templates/*")
app.Static("/static", "./static")
web := gin.Default()
web.LoadHTMLGlob("templates/*")
web.Static("/static", "./static")

app.GET("/", statusPage)
app.GET("/health", health)
web.GET("/", csp.StatusPage)
web.GET("/health", health)

_ = app.Run()
_ = web.Run()
}
69 changes: 13 additions & 56 deletions page.go
Original file line number Diff line number Diff line change
@@ -1,76 +1,33 @@
package main

import (
"fmt"
"html/template"
"log"
"net/http"
"strings"

"github.com/gin-gonic/gin"
)

func buildStatusPage() (updates []StatusUpdate, pinnedUpdates []StatusUpdate, err error) {
log.Println("Building Status Page...")
for _, message := range globalChannelHistory {
botID := fmt.Sprintf("<@%s>", config.SlackBotID)
// Ignore messages that don't mention us. Also, ignore messages that
// mention us but are empty!
if !strings.Contains(message.Text, botID) || message.Text == botID {
continue
}

msgUser, err := slackSocket.GetUserInfo(message.User)
if err != nil {
log.Println(err)
return updates, pinnedUpdates, err
}
realName := msgUser.RealName
var update StatusUpdate
update.Text = strings.Replace(message.Text, botID, "", -1)
update.SentBy = realName
update.TimeStamp = slackTSToHumanTime(message.Timestamp)
update.BackgroundClass = ""
update.IconFilename = ""

for _, reaction := range message.Reactions {
// Only take action on our reactions
if botReaction := stringInSlice(reaction.Users, config.SlackBotID); !botReaction {
continue
}

// Use the first reaction sent by the bot that we find
switch reaction.Name {
case config.StatusOKEmoji:
update.BackgroundClass = "list-group-item-success"
update.IconFilename = "checkmark.svg"
case config.StatusWarnEmoji:
update.BackgroundClass = "list-group-item-warning"
update.IconFilename = "warning.svg"
case config.StatusErrorEmoji:
update.BackgroundClass = "list-group-item-danger"
update.IconFilename = "error.svg"
}

}
if len(message.PinnedTo) > 0 {
pinnedUpdates = append(pinnedUpdates, update)
} else {
updates = append(updates, update)
}
}
type StatusUpdate struct {
Text string
SentBy string
TimeStamp string
BackgroundClass string
IconFilename string
}

return updates, pinnedUpdates, nil
type CSPPage struct {
updates []StatusUpdate
pinnedUpdates []StatusUpdate
}

func statusPage(c *gin.Context) {
func (page *CSPPage) statusPage(c *gin.Context) {
c.HTML(
http.StatusOK,
"index.html",
gin.H{
"HelpMessage": template.HTML(config.HelpMessage),
"PinnedStatuses": globalPinnedUpdates,
"StatusUpdates": globalUpdates,
"PinnedStatuses": page.pinnedUpdates,
"StatusUpdates": page.updates,
"Org": config.OrgName,
"Logo": config.LogoURL,
"Favicon": config.FaviconURL,
Expand Down
Loading

0 comments on commit 13e155c

Please sign in to comment.