Skip to content

Commit

Permalink
fix: Refactor infractions code
Browse files Browse the repository at this point in the history
  • Loading branch information
myrkvi committed Jul 11, 2024
1 parent 7b6fa20 commit dcab850
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 118 deletions.
261 changes: 146 additions & 115 deletions commands/infractions.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"log/slog"
"math"
"strconv"
"strings"
"time"
)

Expand Down Expand Up @@ -115,7 +116,7 @@ func WarnHandler(e *handler.CommandEvent) error {
"guild", guild.Name,
"moderator", e.User().Username)

inf, err := model.CreateInfraction(guild.ID, user.ID, e.User().ID, reason, float32(severity), silent)
inf, err := model.CreateInfraction(guild.ID, user.ID, e.User().ID, reason, severity, silent)
if err != nil {
return fmt.Errorf("failed to create infraction: %w", err)
}
Expand Down Expand Up @@ -178,7 +179,7 @@ func WarnHandler(e *handler.CommandEvent) error {
SetContent(fmt.Sprintf("Warning sent to %s.", user.Mention())).Build())
}

func severityToColor(severity float32) int {
func severityToColor(severity float64) int {
if severity >= 3.0 {
return 0xFF0000
}
Expand Down Expand Up @@ -213,33 +214,10 @@ func UserInfractionsHandler(e *handler.CommandEvent) error {
slog.Warn("No guild id found in event.", "guild", guild)
return ErrEventNoGuildID
}
infrData, err := getUserInfractions(guild.ID, user.ID, pageSize, 0)
if err != nil {
return e.CreateMessage(discord.NewMessageCreateBuilder().
SetEphemeral(true).
SetContent("Failed to retrieve infractions.").
Build())
}

if infrData.TotalCount == 0 {
return e.CreateMessage(discord.NewMessageCreateBuilder().
SetContent("You have no infractions.").
SetEphemeral(true).
Build())
}

message := discord.NewMessageCreateBuilder().
SetEphemeral(true).
SetEmbeds(infrData.Embeds...).
SetContentf("You have %d infractions. (Viewing %d-%d)\nTotal severity: %.2f",
infrData.TotalCount,
infrData.Offset+1,
infrData.Offset+infrData.CurrentCount,
infrData.TotalSeverity,
)

if infrData.Components != nil {
message.AddActionRow(infrData.Components...)
message, err := getUserInfractionsAndMakeMessage(false, &guild, &user)
if err != nil {
slog.Error("Error occurred getting infractions", "err", err)
}

return e.CreateMessage(message.Build())
Expand All @@ -258,31 +236,14 @@ func UserInfractionButtonHandler(e *handler.ComponentEvent) error {
return ErrEventNoGuildID
}

infrData, err := getUserInfractions(guild.ID, user.ID, pageSize, offset)
mcb, mub, err := getUserInfractionsAndUpdateMessage(false, offset, &guild, &user)
if err != nil {
return e.CreateMessage(discord.NewMessageCreateBuilder().
SetEphemeral(true).
SetContent("Failed to retrieve infractions.").
Build())
slog.Error("Error occurred getting infractions", "err", err)
}

if infrData.TotalCount == 0 {
return e.CreateMessage(discord.NewMessageCreateBuilder().
SetEphemeral(true).
SetContent("You have no infractions.").
SetEphemeral(true).
Build())
if mcb != nil {
return e.CreateMessage(mcb.Build())
}

return e.UpdateMessage(discord.NewMessageUpdateBuilder().
SetEmbeds(infrData.Embeds...).
AddActionRow(infrData.Components...).
SetContentf("You have %d infractions. (Viewing %d-%d)\nTotal severity: %.2f",
infrData.TotalCount,
infrData.Offset+1,
infrData.Offset+infrData.CurrentCount,
infrData.TotalSeverity).Build())

return e.UpdateMessage(mub.Build())
}

//░▀█▀░█▀█░█▀▀░█▀▄░█▀█░█▀▀░▀█▀░▀█▀░█▀█░█▀█░█▀▀░░░▄▀░░█▄█░█▀█░█▀▄░▀▄░
Expand Down Expand Up @@ -363,34 +324,9 @@ func InfractionsListHandler(e *handler.CommandEvent) error {
return ErrEventNoGuildID
}

infrData, err := getUserInfractions(guild.ID, user.ID, pageSize, 0)
message, err := getUserInfractionsAndMakeMessage(true, &guild, &user)
if err != nil {
return e.CreateMessage(discord.NewMessageCreateBuilder().
SetEphemeral(true).
SetContent("Failed to retrieve infractions.").
Build())
}

if infrData.TotalCount == 0 {
return e.CreateMessage(discord.NewMessageCreateBuilder().
SetAllowedMentions(&discord.AllowedMentions{}).
SetEphemeral(true).
SetContentf("%s has no infractions.", user.Mention()).
Build())
}

message := discord.NewMessageCreateBuilder().
SetAllowedMentions(&discord.AllowedMentions{}).
SetEmbeds(infrData.Embeds...).
SetContentf("%s has %d infractions. (Viewing %d-%d)\nTotal severity: %.2f",
user.Mention(),
infrData.TotalCount,
infrData.Offset+1,
infrData.Offset+infrData.CurrentCount,
infrData.TotalSeverity)

if infrData.Components != nil {
message.AddActionRow(infrData.Components...)
slog.Error("Error occurred getting infractions", "err", err)
}

return e.CreateMessage(message.Build())
Expand Down Expand Up @@ -451,43 +387,14 @@ func InfractionsListComponentHandler(e *handler.ComponentEvent) error {
Build())
}

infrData, err := getUserInfractions(guild.ID, userID, pageSize, offset)
mcb, mub, err := getUserInfractionsAndUpdateMessage(false, offset, &guild, user)
if err != nil {
return e.CreateMessage(discord.NewMessageCreateBuilder().
SetContent("Failed to retrieve infractions.").
SetEphemeral(true).
Build())
}

if infrData.TotalCount == 0 {
return e.CreateMessage(discord.NewMessageCreateBuilder().
SetAllowedMentions(&discord.AllowedMentions{}).
SetContentf("%s has no infractions. You shouldn't be able to navigate to this, though?", user.Mention()).
SetEphemeral(true).
Build())
slog.Error("Error occurred getting infractions", "err", err)
}

if infrData.CurrentCount == 0 {
return e.CreateMessage(discord.NewMessageCreateBuilder().
SetContent("No more infractions to show.").
SetEphemeral(true).
Build())
if mcb != nil {
return e.CreateMessage(mcb.Build())
}

message := discord.NewMessageUpdateBuilder().
SetAllowedMentions(&discord.AllowedMentions{}).
ClearEmbeds().
ClearContainerComponents().
SetEmbeds(infrData.Embeds...).
SetContentf("%s has %d infractions. (Viewing %d-%d)\nTotal severity: %.2f",
user.Mention(),
infrData.TotalCount,
infrData.Offset+1,
infrData.Offset+infrData.CurrentCount,
infrData.TotalSeverity).
AddActionRow(infrData.Components...)

return e.UpdateMessage(message.Build())
return e.UpdateMessage(mub.Build())
}

//░█░█░▀█▀░▀█▀░█░░░▀█▀░▀█▀░█░█░░░█▀▀░▀█▀░█▀▄░█░█░█▀▀░▀█▀░█▀▀░░░█░█▀▀░█░█░█▀█░█▀▀░█▀▀
Expand Down Expand Up @@ -526,10 +433,10 @@ func getUserInfractions(guildID, userID snowflake.ID, limit, offset int) (userIn
severity := 0.0
for _, inf := range allInfractions {
diff := time.Since(inf.CreatedAt)
severity += utils.CalcHalfLife(diff, guildSettings.InfractionHalfLifeDays, float64(inf.Weight))
severity += utils.CalcHalfLife(diff, guildSettings.InfractionHalfLifeDays, inf.Weight)
}

embeds := createInfractionEmbeds(infractions)
embeds := createInfractionEmbeds(infractions, guildSettings)

var components []discord.InteractiveComponent
slog.Info("Count is", "count", count)
Expand Down Expand Up @@ -567,18 +474,142 @@ func getUserInfractions(guildID, userID snowflake.ID, limit, offset int) (userIn
}, nil
}

func createInfractionEmbeds(infractions []model.Infraction) []discord.Embed {
func createInfractionEmbeds(infractions []model.Infraction, guildSettings *model.GuildSettings) []discord.Embed {
var embeds []discord.Embed

for _, inf := range infractions {
weightWithHalfLife := utils.CalcHalfLife(
time.Since(inf.CreatedAt),
utils.Iif(guildSettings == nil, 0.0, guildSettings.InfractionHalfLifeDays),
inf.Weight)

embed := discord.NewEmbedBuilder().
SetTitlef("Infraction `%s`", inf.Sqid()).
SetDescription(inf.Reason).
SetColor(severityToColor(inf.Weight)).
SetTimestamp(inf.Timestamp).
AddField("Severity", fmt.Sprintf("%.4g", inf.Weight), true)
AddField("Strikes",
fmt.Sprintf("%s (%s)\n(at warn time: %s)",
severityToDots(weightWithHalfLife),
utils.FormatFloatUpToPrec(weightWithHalfLife, 2),
utils.FormatFloatUpToPrec(inf.Weight, 2),
), true)

embeds = append(embeds, embed.Build())
}
return embeds
}

func severityToDots(severity float64) string {
severityFloor := math.Floor(severity)

dots := ""
severityInt := int(severityFloor)
dots += strings.Repeat("●", severityInt)

remaining := severity - severityFloor
if remaining >= 0.0 && remaining < 0.125 {
dots += "○"
} else if remaining >= 0.125 && remaining < 0.375 {
dots += "◔"
} else if remaining >= 0.375 && remaining < 0.625 {
dots += "◑"
} else if remaining >= 0.625 && remaining < 0.875 {
dots += "◕"
} else if remaining >= 0.875 {
dots += "●"
}

if dots == "" {
dots = "○"
}

return dots
}

func getUserInfractionsAndMakeMessage(
modView bool,
guild *discord.Guild, user *discord.User,
) (*discord.MessageCreateBuilder, error) {
infrData, err := getUserInfractions(guild.ID, user.ID, pageSize, 0)
if err != nil {
return discord.NewMessageCreateBuilder().
SetEphemeral(true).
SetContent("Failed to retrieve infractions."),
fmt.Errorf("failed to get user infractions: %w", err)
}

if infrData.TotalCount == 0 {
return discord.NewMessageCreateBuilder().
SetAllowedMentions(&discord.AllowedMentions{}).
SetEphemeral(true).
SetContentf("%s has no infractions.", user.Mention()),
nil
}

modText := fmt.Sprintf("%s has %d infractions.",
user.Mention(),
infrData.TotalCount)
userText := fmt.Sprintf("You have %d infractions.",
infrData.TotalCount)

message := discord.NewMessageCreateBuilder().
SetEphemeral(true).
SetAllowedMentions(&discord.AllowedMentions{}).
SetEmbeds(infrData.Embeds...).
SetContentf("%s (Viewing %d-%d)\nTotal strikes: %s",
utils.Iif(modView, modText, userText),
infrData.Offset+1,
infrData.Offset+infrData.CurrentCount,
fmt.Sprintf("%s (%s)",
severityToDots(infrData.TotalSeverity),
utils.FormatFloatUpToPrec(infrData.TotalSeverity, 2),
))

if infrData.Components != nil {
message.AddActionRow(infrData.Components...)
}

return message, nil
}

func getUserInfractionsAndUpdateMessage(
modView bool, offset int,
guild *discord.Guild, user *discord.User,
) (mcb *discord.MessageCreateBuilder, mub *discord.MessageUpdateBuilder, err error) {

infrData, err := getUserInfractions(guild.ID, user.ID, pageSize, offset)
if err != nil {
mcb = discord.NewMessageCreateBuilder().
SetEphemeral(true).
SetContent("Failed to retrieve infractions.")
return
}

if infrData.TotalCount == 0 {
mcb = discord.NewMessageCreateBuilder().
SetEphemeral(true).
SetContent("You have no infractions.").
SetEphemeral(true)
return
}

modText := fmt.Sprintf("%s has %d infractions.",
user.Mention(),
infrData.TotalCount)
userText := fmt.Sprintf("You have %d infractions.",
infrData.TotalCount)

mub = discord.NewMessageUpdateBuilder().
SetEmbeds(infrData.Embeds...).
AddActionRow(infrData.Components...).
SetContentf("%s (Viewing %d-%d)\nTotal strikes: %s",
utils.Iif(modView, modText, userText),
infrData.Offset+1,
infrData.Offset+infrData.CurrentCount,
fmt.Sprintf("%s (%s)",
severityToDots(infrData.TotalSeverity),
utils.FormatFloatUpToPrec(infrData.TotalSeverity, 2),
))
return
}
6 changes: 3 additions & 3 deletions model/infractions.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type Infraction struct {
UserID snowflake.ID
Moderator snowflake.ID
Reason string
Weight float32
Weight float64
Timestamp time.Time
Silent bool
}
Expand All @@ -27,7 +27,7 @@ func (i Infraction) Sqid() string {

}

func CreateInfraction(guildID, userID, moderator snowflake.ID, reason string, weight float32, silent bool) (*Infraction, error) {
func CreateInfraction(guildID, userID, moderator snowflake.ID, reason string, weight float64, silent bool) (*Infraction, error) {
inf := &Infraction{
GuildID: guildID,
UserID: userID,
Expand All @@ -47,7 +47,7 @@ func CreateInfraction(guildID, userID, moderator snowflake.ID, reason string, we

func GetUserInfractions(guildID, userID snowflake.ID, limit, offset int) ([]Infraction, int64, error) {
var infractions []Infraction
res := DB.Where("guild_id = ? AND user_id = ?", guildID, userID).
res := DB.Order("timestamp desc").Where("guild_id = ? AND user_id = ?", guildID, userID).
Offset(offset).Limit(limit).Find(&infractions)
if res.Error != nil {
return nil, 0, res.Error
Expand Down
9 changes: 9 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package utils
import (
"cmp"
"errors"
"fmt"

Check failure on line 6 in utils/utils.go

View workflow job for this annotation

GitHub Actions / GolangCi-Lint

"fmt" imported and not used) (typecheck)

Check failure on line 6 in utils/utils.go

View workflow job for this annotation

GitHub Actions / GolangCi-Lint

"fmt" imported and not used) (typecheck)

Check failure on line 6 in utils/utils.go

View workflow job for this annotation

GitHub Actions / GolangCi-Lint

"fmt" imported and not used (typecheck)
"math"
"regexp"
"strconv"
"strings"
"time"
)

Expand Down Expand Up @@ -112,3 +114,10 @@ func ParseLongDuration(s string) (time.Duration, error) {

return duration, nil
}
func FormatFloatUpToPrec(num float64, prec int) string {
str := strconv.FormatFloat(num, 'f', prec, 64)
str = strings.TrimRight(str, "0")
str = strings.TrimSuffix(str, ".")

return str
}

0 comments on commit dcab850

Please sign in to comment.