diff --git a/Makefile b/Makefile index 00b29da..d951769 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ build: - go build -o bin/PixelBot . + go build -o bin/PixelBot clean: rm -f bin/bot diff --git a/go.mod b/go.mod index bff6298..3a0ab52 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( ) require ( + github.com/elliotwms/fakediscord v0.16.4 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/klauspost/compress v1.17.9 // indirect diff --git a/go.sum b/go.sum index 18a5b17..8d4d30a 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/elliotwms/fakediscord v0.16.4 h1:yHuiwdbLSbg4MbXzhcD9JxWMn9Fi2CDSheTVFT4irQo= +github.com/elliotwms/fakediscord v0.16.4/go.mod h1:uw9CFPmgeR1f2NoOdzv87gyzmQxAhPQX0WCyEFOhQKo= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= diff --git a/internal/pkg/commands/leveling.go b/internal/pkg/commands/leveling.go new file mode 100644 index 0000000..71c1fb5 --- /dev/null +++ b/internal/pkg/commands/leveling.go @@ -0,0 +1,32 @@ +package commands + +import ( + "fmt" + + "github.com/Paranoia8972/PixelBot/internal/pkg/utils" + "github.com/bwmarrin/discordgo" +) + +func LevelCommand(s *discordgo.Session, i *discordgo.InteractionCreate) { + userID := i.Member.User.ID + guildID := i.GuildID + + level, xp, err := utils.GetUserLevelAndXP(guildID, userID) + if err != nil { + s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "Error retrieving your level.", + Flags: 64, + }, + }) + return + } + + s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: fmt.Sprintf("You are level %d with %d XP!", level, xp), + }, + }) +} diff --git a/internal/pkg/commands/ticket.go b/internal/pkg/commands/ticket.go index 3380b2f..32b66e9 100644 --- a/internal/pkg/commands/ticket.go +++ b/internal/pkg/commands/ticket.go @@ -3,7 +3,10 @@ package commands import ( "encoding/json" "fmt" + "io" "log" + "net/http" + "os" "strconv" "github.com/Paranoia8972/PixelBot/internal/pkg/utils" @@ -498,7 +501,7 @@ func TicketModalSubmitHandler(s *discordgo.Session, i *discordgo.InteractionCrea }) } -func createMessageData(msg *discordgo.Message) map[string]interface{} { +func createMessageData(msg *discordgo.Message, channelName string) map[string]interface{} { messageData := map[string]interface{}{ "username": msg.Author.Username, "pfp": msg.Author.AvatarURL(""), @@ -518,6 +521,24 @@ func createMessageData(msg *discordgo.Message) map[string]interface{} { } for _, attachment := range msg.Attachments { + resp, err := http.Get(attachment.URL) + if err != nil { + continue + } + defer resp.Body.Close() + + filepath := fmt.Sprintf("attachments/%s-%s-%s", channelName, msg.ID, attachment.Filename) + out, err := os.Create(filepath) + if err != nil { + continue + } + defer out.Close() + + _, err = io.Copy(out, resp.Body) + if err != nil { + continue + } + attachmentData := map[string]interface{}{ "type": attachment.ContentType, "url": attachment.URL, @@ -558,7 +579,7 @@ func TicketCloseHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { var transcript []map[string]interface{} for _, msg := range messages { - messageData := createMessageData(msg) + messageData := createMessageData(msg, i.ChannelID) transcript = append(transcript, messageData) } diff --git a/internal/pkg/transcript/transcript.go b/internal/pkg/transcript/transcript.go index a6daeb1..562fd22 100644 --- a/internal/pkg/transcript/transcript.go +++ b/internal/pkg/transcript/transcript.go @@ -66,6 +66,7 @@ type TranscriptData struct { func StartTranscriptServer() { http.HandleFunc("/ticket", TranscriptServer) + http.Handle("/downloads/", http.StripPrefix("/downloads/", http.FileServer(http.Dir("downloads")))) color.Green("Transcript server is running on http://localhost:" + Cfg.Port + "/ticket | https://" + Cfg.TranscriptUrl + "/ticket") log.Fatal(http.ListenAndServe(":"+Cfg.Port, nil)) } @@ -132,7 +133,7 @@ func TranscriptServer(w http.ResponseWriter, r *http.Request) { } if len(msg.Attachments) > 0 { for _, attachment := range msg.Attachments { - if attachment.Type == "image/jpeg" || attachment.Type == "image/png" || attachment.Type == "image/gif" { + if strings.HasPrefix(attachment.Type, "image/") { messagesHTML += `
` diff --git a/internal/pkg/utils/leveling.go b/internal/pkg/utils/leveling.go new file mode 100644 index 0000000..705d7d7 --- /dev/null +++ b/internal/pkg/utils/leveling.go @@ -0,0 +1,61 @@ +package utils + +import ( + "errors" + "sync" +) + +type UserData struct { + XP int + Level int +} + +var ( + userData = make(map[string]map[string]*UserData) + userDataMutex = &sync.RWMutex{} +) + +func GetUserLevelAndXP(guildID, userID string) (int, int, error) { + userDataMutex.RLock() + defer userDataMutex.RUnlock() + + if guild, ok := userData[guildID]; ok { + if user, ok := guild[userID]; ok { + return user.Level, user.XP, nil + } + } + return 0, 0, errors.New("user data not found") +} + +func AddXP(guildID, userID string, xp int) error { + userDataMutex.Lock() + defer userDataMutex.Unlock() + + if _, ok := userData[guildID]; !ok { + userData[guildID] = make(map[string]*UserData) + } + + if _, ok := userData[guildID][userID]; !ok { + userData[guildID][userID] = &UserData{XP: 0, Level: 0} + } + + userData[guildID][userID].XP += xp + return nil +} + +func CheckLevelUp(guildID, userID string) (bool, int, error) { + userDataMutex.Lock() + defer userDataMutex.Unlock() + + if guild, ok := userData[guildID]; ok { + if user, ok := guild[userID]; ok { + requiredXP := (user.Level + 1) * 100 + if user.XP >= requiredXP { + user.Level++ + return true, user.Level, nil + } + return false, user.Level, nil + } + } + return false, 0, errors.New("user data not found") +}