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

Sync disabled #41

Merged
merged 15 commits into from
Sep 19, 2019
2 changes: 2 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ coverage:
patch:
default:
target: 50%
ignore:
- "**/mock*.go"
11 changes: 11 additions & 0 deletions cmd/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"encoding/json"
"fmt"
"os"
"strings"

"github.com/evandroflores/pong/model"
Expand All @@ -22,6 +23,16 @@ func Register(usage, description string, handler func(request slacker.Request, r
slack.Client.Command(usage, &slacker.CommandDefinition{Description: description, Handler: handler})
}

// RegisterAdmin adds a command using an Admin authorization function
func RegisterAdmin(usage, description string, handler func(request slacker.Request, response slacker.ResponseWriter)) {
log.Infof("Registering Admin %s - %s", usage, description)
slack.Client.Command(usage, &slacker.CommandDefinition{Description: description, Handler: handler, AuthorizationFunc: isAdmin})
}

func isAdmin(request slacker.Request) bool {
return strings.Contains(os.Getenv("PONG_ADMINS"), request.Event().User)
}

func cleanID(userID string) string {
return replacer.Replace(userID)
}
Expand Down
74 changes: 68 additions & 6 deletions cmd/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ package cmd
import (
"fmt"
"math/rand"
"os"
"reflect"
"runtime"
"strings"
"testing"
"time"

"github.com/bouk/monkey"
"bou.ke/monkey"
"github.com/evandroflores/pong/model"
sl "github.com/evandroflores/pong/slack"
"github.com/nlopes/slack"
"github.com/shomali11/proper"
"github.com/shomali11/slacker"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
)

Expand All @@ -27,11 +31,15 @@ func init() {
}

func makeTestEvent() *slack.MessageEvent {
return makeTestEventWith(teamID, channelID, userID)
}

func makeTestEventWith(teamID, channelID, slackID string) *slack.MessageEvent {
return &slack.MessageEvent{
Msg: slack.Msg{
Team: "TTTTTTTTT",
Channel: "CCCCCCCCC",
User: "UUUUUUUUU",
Team: teamID,
Channel: channelID,
User: slackID,
}}
}

Expand All @@ -40,12 +48,16 @@ func makeTestPlayer() model.Player {
name := fmt.Sprintf("Fake User - %08d", randomInt)
slackID := fmt.Sprintf("U%08d", randomInt)

return makeTestPlayerWith(teamID, channelID, slackID, name)
}

func makeTestPlayerWith(teamID, channelID, slackID, name string) model.Player {
mockIngest := func(player *model.Player) {
fmt.Printf("Ingesting called for %s\n", player.ToStr())
}
player := model.Player{
TeamID: "TTTTTTTTT",
ChannelID: "CCCCCCCCC",
TeamID: teamID,
ChannelID: channelID,
SlackID: slackID,
Name: name,
Image: "https://www.thispersondoesnotexist.com/image",
Expand Down Expand Up @@ -90,6 +102,32 @@ func TestSayWhat(t *testing.T) {
assert.Empty(t, response.GetErrors())
}

func TestLoadCommands(t *testing.T) {

expectedMsg := fmt.Sprintf("[%d] commands loaded", len(sl.Client.BotCommands()))

called := false
mockDefaultCommand := func(s *slacker.Slacker, handler func(slacker.Request, slacker.ResponseWriter)) {
fmt.Printf("DefaultCommand called")
assert.Equal(t, runtime.FuncForPC(reflect.ValueOf(sayWhat).Pointer()).Name(),
runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name())
called = true
}

monkey.PatchInstanceMethod(reflect.TypeOf(sl.Client), "DefaultCommand", mockDefaultCommand)

mockLogInfof := func(format string, args ...interface{}) {
assert.Equal(t, expectedMsg, fmt.Sprintf(format, args))
}

patchLog := monkey.Patch(log.Infof, mockLogInfof)

LoadCommands()

assert.True(t, called)
patchLog.Unpatch()
}

func TestInvalidWinner(t *testing.T) {
var props = proper.NewProperties(
map[string]string{
Expand Down Expand Up @@ -159,3 +197,27 @@ func TestTrend(t *testing.T) {
assert.Equal(t, getPosDiff(5), " ↑ 5 ")
assert.Equal(t, getPosDiff(-5), " ↓ 5 ")
}

func TestIsAdmin(t *testing.T) {
props := proper.NewProperties(map[string]string{})
evt := makeTestEvent()

currentAdminEnv := os.Getenv("PONG_ADMINS")
os.Setenv("PONG_ADMINS", evt.User)
defer func() { os.Setenv("PONG_ADMINS", currentAdminEnv) }()

request := &fakeRequest{event: evt, properties: props}
assert.True(t, isAdmin(request))
}

func TestNotAdmin(t *testing.T) {
props := proper.NewProperties(map[string]string{})
evt := makeTestEvent()

currentAdminEnv := os.Getenv("PONG_ADMINS")
os.Setenv("PONG_ADMINS", "")
defer func() { os.Setenv("PONG_ADMINS", currentAdminEnv) }()

request := &fakeRequest{event: evt, properties: props}
assert.False(t, isAdmin(request))
}
40 changes: 40 additions & 0 deletions cmd/delete_disabled.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package cmd

import (
"bytes"
"fmt"

"github.com/evandroflores/pong/model"
"github.com/evandroflores/pong/slack"
"github.com/shomali11/slacker"
)

func init() {
RegisterAdmin("delete-disabled", "Delete disabled Slack users from Pong", deleteDisabled)
}

func deleteDisabled(request slacker.Request, response slacker.ResponseWriter) {
response.Typing()

teamID := cleanID(request.Event().Team)
channelID := cleanID(request.Event().Channel)

players := model.GetAllPlayers(teamID, channelID)

var message bytes.Buffer

removed := 0
for _, player := range players {
slackUser, _ := slack.Client.GetUserInfo(player.SlackID)
if slackUser.Deleted {
player.Delete()
message.WriteString(fmt.Sprintf("*%s* - Removed\n", player.Name))
removed++
}
}
if removed == 0 {
message.WriteString("No users removed.")
}

response.Reply(message.String())
}
101 changes: 101 additions & 0 deletions cmd/delete_disabled_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package cmd

import (
"fmt"
"reflect"
"strings"
"testing"

"bou.ke/monkey"

"github.com/evandroflores/pong/database"
"github.com/evandroflores/pong/model"
"github.com/evandroflores/pong/slack"
ns "github.com/nlopes/slack"
"github.com/shomali11/proper"
"github.com/shomali11/slacker"
"github.com/stretchr/testify/suite"
)

type DeleteDisabledTestSuite struct {
suite.Suite
teamID string
channelID string
adminID string
nonAdminID string
players []model.Player
deactivated map[string]model.Player
}

func (s *DeleteDisabledTestSuite) SetupSuite() {
s.teamID = "TDELETE"
s.channelID = "CTESTDEL"
s.adminID = "UIS0ADMIN"
s.nonAdminID = "UNOTADMIN"
s.players = []model.Player{}
s.deactivated = map[string]model.Player{}

for i := 1; i <= 20; i++ {
player := makeTestPlayerWith(s.teamID, s.channelID, fmt.Sprintf("U%08d", i), fmt.Sprintf("Fake User %08d", i))
player.Points = 1000 - float64(i)
if i%2 == 0 {
s.deactivated[player.SlackID] = player
}
s.players = append(s.players, player)

database.Connection.Create(&player)
}

mockGetUserInfo := func(sl *slacker.Slacker, id string) (*ns.User, error) {
isDeactivated := false
if (s.deactivated[id] != model.Player{}) {
isDeactivated = true
}

return &ns.User{
ID: id,
Deleted: isDeactivated,
}, nil
}

monkey.PatchInstanceMethod(reflect.TypeOf(slack.Client), "GetUserInfo", mockGetUserInfo)
}

func (s *DeleteDisabledTestSuite) TearDownSuite() {
for i := 0; i < len(s.players); i++ {
database.Connection.Where(&s.players[i]).Delete(&model.Player{})
}
database.Connection.Unscoped().Where("deleted_at is not null").Delete(&model.Player{})
}

func TestDeleteDisabledTestSuite(t *testing.T) {
suite.Run(t, new(DeleteDisabledTestSuite))
}

func (s *DeleteDisabledTestSuite) TestAdminRemoving() {
var props = proper.NewProperties(map[string]string{})

evt := makeTestEventWith(s.teamID, s.channelID, s.adminID)

request := &fakeRequest{event: evt, properties: props}
response := &fakeResponse{}

deleteDisabled(request, response)
s.Len(response.GetMessages(), 1)
s.Equal(strings.Count(response.GetMessages()[0], "Removed"), len(s.deactivated))
s.Empty(response.GetErrors())
}

func (s *DeleteDisabledTestSuite) TestNoUsersRemoved() {
var props = proper.NewProperties(map[string]string{})

evt := makeTestEventWith(s.teamID, s.channelID, s.adminID)

request := &fakeRequest{event: evt, properties: props}
response := &fakeResponse{}

deleteDisabled(request, response)
s.Len(response.GetMessages(), 1)
s.Equal(response.GetMessages()[0], "No users removed.")
s.Empty(response.GetErrors())
}
2 changes: 1 addition & 1 deletion cmd/rank_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type RankTestSuite struct {
}

func (s *RankTestSuite) SetupSuite() {
s.rankChannelID = "CCCCCCCCC"
s.rankChannelID = "C12345678"
evandroflores marked this conversation as resolved.
Show resolved Hide resolved
s.noRankChannelID = "CAAAAAAAA"
s.expectedRank = fmt.Sprintf("\n*Rank for * <#%s>\n\n", s.rankChannelID)

Expand Down
2 changes: 1 addition & 1 deletion cmd/top_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type TopTestSuite struct {
}

func (s *TopTestSuite) SetupSuite() {
s.rankChannelID = "CCCCCCCCC"
s.rankChannelID = "C12345678"
s.noRankChannelID = "CAAAAAAAA"
s.rankHeader = fmt.Sprintf("*Rank for * <#%s>", s.rankChannelID)

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/evandroflores/pong
go 1.12

require (
bou.ke/monkey v1.0.1 // indirect
bou.ke/monkey v1.0.1
github.com/bouk/monkey v1.0.1
github.com/jinzhu/gorm v1.9.10
github.com/nlopes/slack v0.5.1-0.20190605211732-a05dfd3f167d
Expand Down
5 changes: 5 additions & 0 deletions model/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ func (player *Player) Update() (int, error) {
return (previousPosition - dbPlayer.GetPosition()), nil
}

// Delete removes locally the user from the DB.
func (player *Player) Delete() {
database.Connection.Delete(&player)
}

// IngestData calls Slack API to get Users data
func (player *Player) IngestData() {
slackUser, err := slack.Client.GetUserInfo(player.SlackID)
Expand Down