Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ run:
# This file contains only configs which differ from defaults.
# All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
linters-settings:
goconst:
min-occurrences: 5

cyclop:
# The maximal code complexity to report.
# Default: 10
Expand Down
117 changes: 75 additions & 42 deletions internal/moderation/buttons.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,67 +27,70 @@ func InfoButtons(s *discordgo.Session, i *discordgo.InteractionCreate) {

// Get the action
var action = customIDSplit[0]

// Get the userID
var userID = customIDSplit[1]
// Get user from the user ID
discordUser, err := s.User(userID)
if err != nil {
shared.SimpleEphemeralInteractionResponse("Failed to get discord user", s, i.Interaction)
log.Error().Err(err).Msg("Failed to get discord user")
return
}

// Get the embedID
var embedID = customIDSplit[2]
// Get the channelID
var channelID = customIDSplit[3]

// TODO: Handle if a user has never been seen before
userObj, err := shared.DBClient.User.FindUnique(
db.User.UserID.Equals(userID),
).Exec(context.Background())
userObj, err := shared.GetUserIfExists(&discordgo.User{
ID: userID,
Username: discordUser.Username,
})
if err != nil {
shared.SimpleEphemeralInteractionResponse("Failed to get or create user", s, i.Interaction)
log.Error().Err(err).Msg("Failed to get user")
return
}

reportCount := getUserReportCount(userObj.ID)

// Get discord user
discordUser, err := s.User(userID)
if err != nil {
log.Error().Err(err).Msg("Failed to get user")
return
}

log.Debug().Msg("Got user info button event")

var embed discordgo.MessageEmbed
var embed = discordgo.MessageEmbed{
Title: "Infractions",
Color: shared.DarkBlue,
Fields: []*discordgo.MessageEmbedField{
{
Name: "User (Tag)",
Value: "",
Inline: true,
},
{
Name: "Points",
Value: strconv.Itoa(userObj.Points),
Inline: true,
},
{
Name: "Reports",
Value: strconv.Itoa(reportCount),
Inline: true,
},
},
// Set the image as the users avatar
Thumbnail: &discordgo.MessageEmbedThumbnail{
URL: discordUser.AvatarURL("256x256"),
},
}

switch action {
case "overview":
embed = GenerateOverviewEmbed(*userObj, userID, reportCount, discordUser.AvatarURL("256x256"))
case "infractions":
embed = discordgo.MessageEmbed{
Title: "Infractions",
Color: shared.DarkBlue,
Fields: []*discordgo.MessageEmbedField{
{
Name: "User (Tag)",
Value: "",
Inline: true,
},
{
Name: "Points",
Value: strconv.Itoa(userObj.Points),
Inline: true,
},
{
Name: "Reports",
Value: strconv.Itoa(reportCount),
Inline: true,
},
{
Name: "__Infractions__",
Value: "",
},
},
// Set the image as the users avatar
Thumbnail: &discordgo.MessageEmbedThumbnail{
URL: discordUser.AvatarURL("256x256"),
},
}
embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
Name: "__Infractions__",
Value: "",
})

// Get all infractions
infractions, infractionErr := shared.DBClient.Infraction.FindMany(
Expand All @@ -96,6 +99,7 @@ func InfoButtons(s *discordgo.Session, i *discordgo.InteractionCreate) {
db.Infraction.CreatedAt.Order(db.SortOrderDesc),
).Exec(context.Background())
if infractionErr != nil {
shared.SimpleEphemeralInteractionResponse("Failed to get infractions", s, i.Interaction)
log.Error().Err(err).Msg("Failed to get infractions")
return
}
Expand All @@ -112,7 +116,33 @@ func InfoButtons(s *discordgo.Session, i *discordgo.InteractionCreate) {
})
}
case "notes":
// Show the notes
embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
Name: "__Notes__",
Value: "",
})

// Get all notes
notes, noteErr := shared.DBClient.Note.FindMany(
db.Note.UserID.Equals(userObj.ID),
).OrderBy(
db.Note.CreatedAt.Order(db.SortOrderDesc),
).Exec(context.Background())
if noteErr != nil {
shared.SimpleEphemeralInteractionResponse("Failed to get notes", s, i.Interaction)
log.Error().Err(err).Msg("Failed to get notes")
return
}

for _, note := range notes {
dateWithoutTime := strings.Split(note.CreatedAt, "T")[0]

embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
Name: "ID:: " + strconv.Itoa(note.ID) + " :: Staff ::" + note.ModeratorUsername,
Value: "Date: **" + dateWithoutTime + "** (" + shared.StringTimeToDiscordTimestamp(note.CreatedAt) + ")\n" +
"Note: " + note.Content,
Inline: false,
})
}
case "messages":
// Show the messages
case "leaves":
Expand All @@ -127,7 +157,9 @@ func InfoButtons(s *discordgo.Session, i *discordgo.InteractionCreate) {
Embeds: &[]*discordgo.MessageEmbed{&embed},
})
if err != nil {
shared.SimpleEphemeralInteractionResponse("Failed to edit message", s, i.Interaction)
log.Error().Err(err).Msg("Failed to edit message")
return
}

// Respond to the interaction
Expand All @@ -136,5 +168,6 @@ func InfoButtons(s *discordgo.Session, i *discordgo.InteractionCreate) {
})
if err != nil {
log.Error().Err(err).Msg("Failed to respond to interaction")
return
}
}
20 changes: 20 additions & 0 deletions internal/moderation/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ import (
)

var Commands = []*discordgo.ApplicationCommand{ //nolint:gochecknoglobals // This is a list of commands for Discord
{
Name: "note",
Description: "Add a note to a user",
DefaultMemberPermissions: shared.Int64Ptr(discordgo.PermissionKickMembers),
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionUser,
Name: "user",
Description: "The user to add a note to",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionString,
Name: "text",
Description: "The text of the note",
Required: true,
},
},
},
{
Name: "warn",
Description: "Warn the user",
Expand Down Expand Up @@ -115,6 +134,7 @@ var CommandHandlers = map[string]func( //nolint:gochecknoglobals // This is a ma
s *discordgo.Session,
i *discordgo.InteractionCreate,
){
"note": NoteCommand,
"warn": WarnCommand,
"strike": StrikeCommand,
"info": InfoCommand,
Expand Down
55 changes: 17 additions & 38 deletions internal/moderation/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ func GenerateInfoButtons(channelID string, embedID string, userID string) []disc
Name: "⚠️",
},
},
// discordgo.Button{
// Label: "Notes",
// Style: discordgo.PrimaryButton,
// CustomID: "notes" + suffix,
// Emoji: &discordgo.ComponentEmoji{
// Name: "📝",
// },
// },
discordgo.Button{
Label: "Notes",
Style: discordgo.PrimaryButton,
CustomID: "notes" + suffix,
Emoji: &discordgo.ComponentEmoji{
Name: "📝",
},
},
// discordgo.Button{
// Label: "Messages",
// Style: discordgo.PrimaryButton,
Expand Down Expand Up @@ -175,17 +175,12 @@ func InfoCommand(s *discordgo.Session, i *discordgo.InteractionCreate) {
db.User.UserID.Equals(user.ID),
).Exec(context.Background())
if err != nil {
log.Error().Err(err).Msg("Failed to get user")
err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "Failed to get user info",
Flags: discordgo.MessageFlagsEphemeral,
},
})
if err != nil {
log.Error().Err(err).Msg("Failed to send fail interaction response for info")
if errors.Is(err, db.ErrNotFound) {
shared.SimpleEphemeralInteractionResponse("User not found", s, i.Interaction)
return
}
shared.SimpleEphemeralInteractionResponse("Failed to get user", s, i.Interaction)
log.Error().Err(err).Msg("Failed to get user")
return
}

Expand All @@ -202,17 +197,8 @@ func InfoCommand(s *discordgo.Session, i *discordgo.InteractionCreate) {
Embed: &embed,
})
if err != nil {
shared.SimpleEphemeralInteractionResponse("Failed to send info message", s, i.Interaction)
log.Error().Err(err).Msg("Failed to send info message")
err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "Failed to get user info",
Flags: discordgo.MessageFlagsEphemeral,
},
})
if err != nil {
log.Error().Err(err).Msg("Failed to send fail interaction response for info")
}
return
}

Expand All @@ -223,17 +209,10 @@ func InfoCommand(s *discordgo.Session, i *discordgo.InteractionCreate) {
Components: &buttons,
})
if err != nil {
shared.SimpleEphemeralInteractionResponse("Failed to add buttons to info message", s, i.Interaction)
log.Error().Err(err).Msg("Failed to add buttons to info message")
return
}

err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "User information available below",
Flags: 64,
},
})
if err != nil {
log.Error().Err(err).Msg("Failed to send interaction response for info")
}
shared.SimpleEphemeralInteractionResponse("User info generated below", s, i.Interaction)
}
52 changes: 52 additions & 0 deletions internal/moderation/note.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package moderation

import (
"context"
"errors"
"math280h/wisp/db"
"math280h/wisp/internal/shared"

"github.com/bwmarrin/discordgo"
"github.com/rs/zerolog/log"
)

func NoteCommand(s *discordgo.Session, i *discordgo.InteractionCreate) {
userID := i.ApplicationCommandData().Options[0].UserValue(s).ID
text := i.ApplicationCommandData().Options[1].StringValue()

// Get user from the user ID
user, err := s.User(userID)
if err != nil {
shared.SimpleEphemeralInteractionResponse("Failed to get discord user", s, i.Interaction)
log.Error().Err(err).Msg("Failed to get discord user")
return
}

userObj, userErr := shared.GetUserIfExists(user)
if userErr != nil {
if errors.Is(userErr, db.ErrNotFound) {
shared.SimpleEphemeralInteractionResponse("User not found", s, i.Interaction)
return
}
shared.SimpleEphemeralInteractionResponse("Failed to get or create user", s, i.Interaction)
log.Error().Err(userErr).Msg("Failed to get or create user")
return
}

_, noteErr := shared.DBClient.Note.CreateOne(
db.Note.User.Link(
db.User.UserID.Equals(userObj.UserID),
),
db.Note.Content.Set(text),
db.Note.ModeratorID.Set(i.Member.User.ID),
db.Note.ModeratorUsername.Set(i.Member.User.Username),
).Exec(context.Background())
if noteErr != nil {
shared.SimpleEphemeralInteractionResponse("Failed to create note", s, i.Interaction)
log.Error().Err(noteErr).Msg("Failed to create note")
return
}

// Respond to the command
shared.SimpleEphemeralInteractionResponse("Note added to user", s, i.Interaction)
}
18 changes: 18 additions & 0 deletions internal/shared/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"strconv"
"time"

"github.com/bwmarrin/discordgo"
"github.com/rs/zerolog/log"
)

Expand Down Expand Up @@ -32,3 +33,20 @@ func StringWithTzToDiscordTimestamp(t string) string {
unixTimestamp := parsedTime.Unix()
return "<t:" + strconv.FormatInt(unixTimestamp, 10) + ":R>"
}

func SimpleEphemeralInteractionResponse(
content string,
session *discordgo.Session,
interaction *discordgo.Interaction,
) {
err := session.InteractionRespond(interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: content,
Flags: 64,
},
})
if err != nil {
log.Error().Err(err).Msg("Failed to respond to interaction")
}
}
Loading
Loading