Skip to content
Snippets Groups Projects
Commit d0404bd4 authored by Levatax's avatar Levatax
Browse files

fix guild ID handling, optional user information to ticket setup, persisting...

fix guild ID handling, optional user information to ticket setup, persisting of ticket state on disk
parent ade07457
Branches main
No related tags found
No related merge requests found
...@@ -3,5 +3,6 @@ ...@@ -3,5 +3,6 @@
*.test *.test
*.out *.out
/.idea/ /.idea/
/store/
ticket-bot ticket-bot
ticket.conf ticket.conf
\ No newline at end of file
...@@ -2,12 +2,13 @@ package main ...@@ -2,12 +2,13 @@ package main
import ( import (
log "git.randomchars.net/FreeNitori/Log" log "git.randomchars.net/FreeNitori/Log"
"os"
) )
func cleanup() { func cleanup() {
dumpPath := config.Store + "/state"
if err := session.Close(); err != nil { if err := session.Close(); err != nil {
log.Fatalf("Error while closing session, %s", err) log.Warnf("Error while closing session, %s", err)
os.Exit(1)
} }
log.Infof("Dumping ticket state to %s.", dumpPath)
dumpTicketState(dumpPath)
} }
...@@ -14,6 +14,7 @@ var defaultConfig = configPayload{ ...@@ -14,6 +14,7 @@ var defaultConfig = configPayload{
MessageID: []string{}, MessageID: []string{},
GuildID: "GUILD_ID", GuildID: "GUILD_ID",
Prefix: "!", Prefix: "!",
Store: "./store",
} }
type configPayload struct { type configPayload struct {
...@@ -21,6 +22,7 @@ type configPayload struct { ...@@ -21,6 +22,7 @@ type configPayload struct {
MessageID []string MessageID []string
GuildID string GuildID string
Prefix string Prefix string
Store string
} }
func init() { func init() {
......
...@@ -19,7 +19,7 @@ func handleReaction(context *multiplexer.Context) { ...@@ -19,7 +19,7 @@ func handleReaction(context *multiplexer.Context) {
return return
} }
if reactionAdd.GuildID != config.GuildID { if reactionAdd.GuildID == "" {
return return
} }
if reactionAdd.UserID == session.State.User.ID { if reactionAdd.UserID == session.State.User.ID {
...@@ -31,13 +31,13 @@ func handleReaction(context *multiplexer.Context) { ...@@ -31,13 +31,13 @@ func handleReaction(context *multiplexer.Context) {
switch reactionAdd.Emoji.Name { switch reactionAdd.Emoji.Name {
case "1️⃣": case "1️⃣":
setupTicket(reactionAdd.GuildID, reactionAdd.UserID, 0) setupTicket(config.GuildID, reactionAdd.UserID, 0, context.User)
case "2️⃣": case "2️⃣":
setupTicket(reactionAdd.GuildID, reactionAdd.UserID, 1) setupTicket(config.GuildID, reactionAdd.UserID, 1, context.User)
case "3️⃣": case "3️⃣":
setupTicket(reactionAdd.GuildID, reactionAdd.UserID, 2) setupTicket(config.GuildID, reactionAdd.UserID, 2, context.User)
case "4️⃣": case "4️⃣":
setupTicket(reactionAdd.GuildID, reactionAdd.UserID, 3) setupTicket(config.GuildID, reactionAdd.UserID, 3, context.User)
default: default:
return return
} }
...@@ -60,6 +60,9 @@ func handleMessages(context *multiplexer.Context) { ...@@ -60,6 +60,9 @@ func handleMessages(context *multiplexer.Context) {
case true: case true:
sendMessage(instance.ChannelID, context.Message.Content) sendMessage(instance.ChannelID, context.Message.Content)
case false: case false:
if context.Message.Content == context.Prefix() + "close" {
return
}
sendMessage(instance.UserChannelID, context.Message.Content) sendMessage(instance.UserChannelID, context.Message.Content)
} }
} }
......
...@@ -20,6 +20,19 @@ func main() { ...@@ -20,6 +20,19 @@ func main() {
flag.Parse() flag.Parse()
parse() parse()
// Ensure store directory
if _, err := os.ReadDir(config.Store); err != nil {
if os.IsNotExist(err) {
log.Warnf("Creating store directory on %s.", config.Store)
if err = os.MkdirAll(config.Store, 0700); err != nil {
log.Fatalf("Error creating store directory on %s, %s", config.Store, err)
os.Exit(1)
}
} else {
log.Fatalf("Store directory inaccessible, %s.", err)
}
}
// Set discordgo log handler // Set discordgo log handler
discordgo.Logger = func(msgL, _ int, format string, a ...interface{}) { discordgo.Logger = func(msgL, _ int, format string, a ...interface{}) {
var level logrus.Level var level logrus.Level
...@@ -53,6 +66,12 @@ func main() { ...@@ -53,6 +66,12 @@ func main() {
session.ShouldReconnectOnError = true session.ShouldReconnectOnError = true
session.Identify.Intents = discordgo.IntentsAllWithoutPrivileged session.Identify.Intents = discordgo.IntentsAllWithoutPrivileged
if state, ok := readTicketState(config.Store + "/state"); ok == true {
ticketInstancesUser = state.TicketInstancesUser
ticketInstancesChannel = state.TicketInstancesChannel
log.Infof("Read %v ticket states from %s.", len(ticketInstancesChannel), config.Store + "/state")
}
// Open session // Open session
if err := session.Open(); err != nil { if err := session.Open(); err != nil {
log.Fatalf("Error while opening session, %s", err) log.Fatalf("Error while opening session, %s", err)
......
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
log "git.randomchars.net/FreeNitori/Log" log "git.randomchars.net/FreeNitori/Log"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"os"
"sync"
"time" "time"
) )
var ticketLock = sync.RWMutex{}
var ticketInstancesChannel = make(map[string]*ticket) var ticketInstancesChannel = make(map[string]*ticket)
var ticketInstancesUser = make(map[string]*ticket) var ticketInstancesUser = make(map[string]*ticket)
...@@ -17,7 +21,15 @@ type ticket struct { ...@@ -17,7 +21,15 @@ type ticket struct {
CreationDate time.Time `json:"creation_date"` CreationDate time.Time `json:"creation_date"`
} }
type ticketState struct {
TicketInstancesChannel map[string]*ticket `json:"ticket_instances_channel"`
TicketInstancesUser map[string]*ticket `json:"ticket_instances_user"`
}
func (t *ticket) delete() { func (t *ticket) delete() {
ticketLock.RLock()
defer ticketLock.RUnlock()
delete(ticketInstancesUser, t.UserID) delete(ticketInstancesUser, t.UserID)
delete(ticketInstancesChannel, t.ChannelID) delete(ticketInstancesChannel, t.ChannelID)
if _, err := session.ChannelDelete(t.ChannelID); err != nil { if _, err := session.ChannelDelete(t.ChannelID); err != nil {
...@@ -50,7 +62,9 @@ func createTicket(channelID, userID string) *ticket { ...@@ -50,7 +62,9 @@ func createTicket(channelID, userID string) *ticket {
return instance return instance
} }
func setupTicket(guildID, userID string, subject int) bool { func setupTicket(guildID, userID string, subject int, user *discordgo.User) bool {
ticketLock.RLock()
defer ticketLock.RUnlock()
if channel, err := session.GuildChannelCreate(guildID, "ticket-"+userID, discordgo.ChannelTypeGuildText); err != nil { if channel, err := session.GuildChannelCreate(guildID, "ticket-"+userID, discordgo.ChannelTypeGuildText); err != nil {
log.Warnf("Error creating ticket channel for user %s, %s", userID, err) log.Warnf("Error creating ticket channel for user %s, %s", userID, err)
return false return false
...@@ -64,6 +78,52 @@ func setupTicket(guildID, userID string, subject int) bool { ...@@ -64,6 +78,52 @@ func setupTicket(guildID, userID string, subject int) bool {
return false return false
} }
} }
if user != nil {
return sendMessage(channel.ID, fmt.Sprintf("Ticket created by user %s#%s (%s) with subject %v.",
user.Username, user.Discriminator, user.ID, subject))
} else {
return sendMessage(channel.ID, fmt.Sprintf("Ticket created with subject %v.", subject)) return sendMessage(channel.ID, fmt.Sprintf("Ticket created with subject %v.", subject))
} }
} }
}
func makeActiveTicketsPayload() []byte {
if payload, err := json.Marshal(ticketState{
TicketInstancesChannel: ticketInstancesChannel,
TicketInstancesUser: ticketInstancesUser,
}); err != nil {
log.Fatalf("Error saving ticket state, %s, all ticket changes since previous start will be lost.")
os.Exit(1)
} else {
return payload
}
return nil
}
func dumpTicketState(path string) {
// Permanently lock ticket state until program exit
ticketLock.Lock()
if err := os.WriteFile(path, makeActiveTicketsPayload(), 0600); err != nil {
log.Errorf("Error dumping ticket state, %s, all ticket changes since previous start will be lost.")
}
}
func readTicketState(path string) (ticketState, bool) {
var state ticketState
if payload, err := os.ReadFile(path); err != nil {
if os.IsNotExist(err) {
return state, false
}
log.Fatalf("Error reading state file, %s", err)
os.Exit(1)
} else {
if err = json.Unmarshal(payload, &state); err != nil {
log.Fatalf("Error parsing state file, %s", err)
os.Exit(1)
} else {
return state, true
}
}
return state, false
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment