feature/improvements #8
1
.gitignore
vendored
1
.gitignore
vendored
@@ -26,3 +26,4 @@ go.work.sum
|
|||||||
.env
|
.env
|
||||||
|
|
||||||
/cmd/*
|
/cmd/*
|
||||||
|
/cmd
|
||||||
72
README.md
72
README.md
@@ -1,12 +1,14 @@
|
|||||||
# bolt
|
# bolt
|
||||||
|
|
||||||
look into using retries and context's
|
TODO
|
||||||
|
pre-1. Break up msg handler method its insane
|
||||||
|
1. Read through code and ensure I didn't miss anything
|
||||||
|
2. do research on intents for 'admin' jobs
|
||||||
|
3. comments and README updates, things have changed
|
||||||
|
4. determine adjustments to timeouts and contexts and const vs options for it
|
||||||
|
5. Figure out why the exiting printing is going after terminal exit
|
||||||
|
|
||||||
also add mentioned users to struct so the ban functions can use them
|
---
|
||||||
|
|
||||||
also do we move towards message handler or focus on command handling, this will dictate the structure going forward with the bans, etc.
|
|
||||||
started on msg handler but it doesn't make sense, the Adding of the handlers won't work with messages since the trigger is always blank. Might need a catch all one, but then
|
|
||||||
that blacklists a command trigger, hmmmm
|
|
||||||
|
|
||||||
The nuts-and-bolts of Discord bots. Bolt is a wrapper for [discordgo](https://github.com/bwmarrin/discordgo) that provides quick and easy bootstrapping for simple Discord bots.
|
The nuts-and-bolts of Discord bots. Bolt is a wrapper for [discordgo](https://github.com/bwmarrin/discordgo) that provides quick and easy bootstrapping for simple Discord bots.
|
||||||
|
|
||||||
@@ -62,60 +64,62 @@ The Delete method will delete the message from the text channel
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.jakeyoungdev.com/jake/bolt"
|
"code.jakeyoungdev.com/jake/bolt"
|
||||||
|
_ "github.com/joho/godotenv/autoload"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
//bolt defaults the command indicator to '.' however that can be changed with the options
|
b, err := bolt.New(bolt.WithLogLevel(bolt.LogLevelAll),
|
||||||
//Example: bolt.New(bolt.WithIndicator('!')) would support commands like !ping
|
bolt.WithMaxGoroutines(50),
|
||||||
b, err := bolt.New(bolt.WithLogLevel(bolt.LogLevelCmd))
|
bolt.WithPermissions(bolt.MessagePermissions, bolt.AdminPermissions))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.AddCommands(
|
b.AddCommands(
|
||||||
// basic ping pong command, .ping can be run at anytime by anyone and will reply "pong"
|
|
||||||
bolt.Command{
|
bolt.Command{
|
||||||
Trigger: "ping",
|
Trigger: "test",
|
||||||
Payload: func(msg bolt.Message) error {
|
Payload: func(msg *bolt.Message, admin bolt.AdminToolBox) error {
|
||||||
return msg.Respond("pong")
|
return msg.Respond("hi")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// .react will add a +1 reaction to the command message, .react can be run by anyone at any rate
|
|
||||||
bolt.Command{
|
bolt.Command{
|
||||||
Trigger: "react",
|
Trigger: "timeout",
|
||||||
Payload: func(msg bolt.Message) error {
|
Payload: func(msg *bolt.Message, tools bolt.AdminToolBox) error {
|
||||||
return msg.React(bolt.ReactionThumbsUp)
|
if len(msg.Mentions) > 0 {
|
||||||
|
err := tools.Timeout(msg.Mentions[0].ID, msg.ServerID, time.Now().Add(time.Minute*5))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return msg.Respond("done")
|
||||||
},
|
},
|
||||||
},
|
|
||||||
// .time responds with the current date/time, .time can be run once every 25 seconds by any role
|
|
||||||
bolt.Command{
|
|
||||||
Trigger: "time",
|
|
||||||
Payload: func(msg bolt.Message) error {
|
|
||||||
return msg.Respond(time.Now().String())
|
|
||||||
},
|
|
||||||
Timeout: time.Second * 25,
|
|
||||||
},
|
|
||||||
// .role command can be ran every 10 seconds by anyone with the admin role and will return the string "admin"
|
|
||||||
bolt.Command{
|
|
||||||
Trigger: "role",
|
|
||||||
Payload: func(msg bolt.Message) error {
|
|
||||||
return msg.Respond("admin")
|
|
||||||
},
|
|
||||||
Timeout: time.Second * 10,
|
|
||||||
Roles: []string{"admin"},
|
Roles: []string{"admin"},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
//start is a blocking call that handles safe-shutdown, all configuration and setup should be done before calling Start()
|
b.AddMessageHandler(func(msg *bolt.Message, tools bolt.AdminToolBox) error {
|
||||||
|
if strings.Contains(msg.Content, "swear word") {
|
||||||
|
return tools.Timeout(msg.Author.ID, msg.ServerID, time.Now().Add(time.Hour*1))
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.Content == "im a menace in VC" {
|
||||||
|
return tools.Mute(msg.Author.ID, msg.ServerID)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
err = b.Start()
|
err = b.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|||||||
57
bolt.go
57
bolt.go
@@ -9,7 +9,6 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
dg "github.com/bwmarrin/discordgo"
|
dg "github.com/bwmarrin/discordgo"
|
||||||
@@ -34,11 +33,14 @@ type bolt struct {
|
|||||||
pool chan struct{}
|
pool chan struct{}
|
||||||
maxRoutines int
|
maxRoutines int
|
||||||
msgHandlerf Payload
|
msgHandlerf Payload
|
||||||
|
admin bool
|
||||||
|
tools AdminToolBox
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bolt interface {
|
type Bolt interface {
|
||||||
Start() error
|
Start() error
|
||||||
AddCommands(cmd ...Command)
|
AddCommands(cmd ...Command)
|
||||||
|
AddMessageHandler(p Payload)
|
||||||
//filtered methods
|
//filtered methods
|
||||||
stop() error
|
stop() error
|
||||||
msgEventHandler(s *dg.Session, msg *dg.MessageCreate)
|
msgEventHandler(s *dg.Session, msg *dg.MessageCreate)
|
||||||
@@ -67,6 +69,7 @@ func New(opts ...Option) (Bolt, error) {
|
|||||||
logLvl: LogLevelAll,
|
logLvl: LogLevelAll,
|
||||||
indicator: DEFAULT_INDICATOR,
|
indicator: DEFAULT_INDICATOR,
|
||||||
wg: sync.WaitGroup{},
|
wg: sync.WaitGroup{},
|
||||||
|
admin: false,
|
||||||
maxRoutines: DEFAULT_MAX_GOROUTINES,
|
maxRoutines: DEFAULT_MAX_GOROUTINES,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,8 +78,9 @@ func New(opts ...Option) (Bolt, error) {
|
|||||||
opt(b)
|
opt(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
//options can change pool size, create post-options
|
//options can change these fields so we must create post-opts
|
||||||
b.pool = make(chan struct{}, b.maxRoutines)
|
b.pool = make(chan struct{}, b.maxRoutines)
|
||||||
|
b.tools = NewToolbox(b)
|
||||||
|
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
@@ -91,7 +95,7 @@ func (b *bolt) Start() error {
|
|||||||
log.Println("bot started")
|
log.Println("bot started")
|
||||||
|
|
||||||
sigChannel := make(chan os.Signal, 1)
|
sigChannel := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigChannel, syscall.SIGINT)
|
signal.Notify(sigChannel, os.Interrupt)
|
||||||
<-sigChannel
|
<-sigChannel
|
||||||
|
|
||||||
//move this to an option, maybe?
|
//move this to an option, maybe?
|
||||||
@@ -105,18 +109,13 @@ func (b *bolt) Start() error {
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
log.Println("shutdown timed out waiting for commands to finish, some may have been incomplete")
|
log.Println("shutdown timed out waiting for handlers to finish, some may have been incomplete")
|
||||||
case <-closeChan:
|
case <-closeChan:
|
||||||
log.Println("command routines cleaned up, exiting")
|
log.Println("handler routines cleaned")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.stop(); err != nil {
|
log.Println("exiting")
|
||||||
return err
|
return b.stop()
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("bot stopped")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bolt) stop() error {
|
func (b *bolt) stop() error {
|
||||||
@@ -130,6 +129,10 @@ func (b *bolt) AddCommands(cmd ...Command) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *bolt) AddMessageHandler(p Payload) {
|
||||||
|
b.msgHandlerf = p
|
||||||
|
}
|
||||||
|
|
||||||
func (b *bolt) msgEventHandler(s *dg.Session, msg *dg.MessageCreate) {
|
func (b *bolt) msgEventHandler(s *dg.Session, msg *dg.MessageCreate) {
|
||||||
//get server information
|
//get server information
|
||||||
server, err := s.Guild(msg.GuildID)
|
server, err := s.Guild(msg.GuildID)
|
||||||
@@ -157,16 +160,19 @@ func (b *bolt) msgEventHandler(s *dg.Session, msg *dg.MessageCreate) {
|
|||||||
log.Printf("< %s | %s | %s > %s\n", server.Name, channel.Name, msg.Author.Username, msg.Content)
|
log.Printf("< %s | %s | %s > %s\n", server.Name, channel.Name, msg.Author.Username, msg.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//this hsould be moved to a parseMessageEvent method
|
||||||
m := Message{
|
m := Message{
|
||||||
Author: msg.Author.Username,
|
Author: Author{
|
||||||
authorID: msg.Author.ID,
|
Name: msg.Author.Username,
|
||||||
authorRoles: msg.Member.Roles,
|
ID: msg.Author.ID,
|
||||||
|
Roles: msg.Member.Roles,
|
||||||
|
},
|
||||||
ID: msg.ID,
|
ID: msg.ID,
|
||||||
Content: msg.Content,
|
Content: msg.Content,
|
||||||
Channel: channel.Name,
|
Channel: channel.Name,
|
||||||
channelID: channel.ID,
|
ChannelID: channel.ID,
|
||||||
Server: server.Name,
|
Server: server.Name,
|
||||||
serverID: server.ID,
|
ServerID: server.ID,
|
||||||
sesh: b,
|
sesh: b,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +213,7 @@ func (b *bolt) msgEventHandler(s *dg.Session, msg *dg.MessageCreate) {
|
|||||||
if msg.Content[:lg] == b.indicator {
|
if msg.Content[:lg] == b.indicator {
|
||||||
if b.logLvl == LogLevelCmd {
|
if b.logLvl == LogLevelCmd {
|
||||||
//log commands
|
//log commands
|
||||||
log.Printf("< %s | %s | %s > %s\n", m.Server, m.Channel, m.authorID, m.Content)
|
log.Printf("< %s | %s | %s > %s\n", m.Server, m.Channel, m.Author.Name, m.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.pool <- struct{}{} //'aquire' a routine
|
b.pool <- struct{}{} //'aquire' a routine
|
||||||
@@ -234,7 +240,7 @@ func (b *bolt) msgEventHandler(s *dg.Session, msg *dg.MessageCreate) {
|
|||||||
|
|
||||||
func (b *bolt) handleMessage(event *Message) error {
|
func (b *bolt) handleMessage(event *Message) error {
|
||||||
if b.msgHandlerf != nil {
|
if b.msgHandlerf != nil {
|
||||||
return b.msgHandlerf(event)
|
return b.msgHandlerf(event, b.tools)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -247,7 +253,7 @@ func (b *bolt) handleCommand(msg *Message, lg int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//has command met its timeout requirements
|
//has command met its timeout requirements
|
||||||
tc, err := b.timeoutCheck(msg.ID, msg.channelID, msg.serverID, b.Session, run)
|
tc, err := b.timeoutCheck(msg.ID, msg.ChannelID, msg.ServerID, b.Session, run)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to calculate timeout for %s\n%e", run.Trigger, err)
|
return fmt.Errorf("failed to calculate timeout for %s\n%e", run.Trigger, err)
|
||||||
}
|
}
|
||||||
@@ -257,13 +263,13 @@ func (b *bolt) handleCommand(msg *Message, lg int) error {
|
|||||||
|
|
||||||
//does user have correct permissions
|
//does user have correct permissions
|
||||||
if run.Roles != nil {
|
if run.Roles != nil {
|
||||||
check, err := b.roleCheck(msg.serverID, msg.authorRoles, b.Session, run)
|
check, err := b.roleCheck(msg.ServerID, msg.Author.Roles, b.Session, run)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to perform permission checks for %s\n%e", run.Trigger, err)
|
return fmt.Errorf("failed to perform permission checks for %s\n%e", run.Trigger, err)
|
||||||
}
|
}
|
||||||
if !check {
|
if !check {
|
||||||
reply := b.createReply("you do not have permissions to run that command", msg.ID, msg.channelID, msg.serverID)
|
reply := b.createReply("you do not have permissions to run that command", msg.ID, msg.ChannelID, msg.ServerID)
|
||||||
_, err := b.Session.ChannelMessageSendComplex(msg.channelID, reply)
|
_, err := b.Session.ChannelMessageSendComplex(msg.ChannelID, reply)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -271,7 +277,7 @@ func (b *bolt) handleCommand(msg *Message, lg int) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = run.Payload(msg)
|
err = run.Payload(msg, b.tools)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("encountered an error while handling command (%s): %e", msg.Words[0], err)
|
return fmt.Errorf("encountered an error while handling command (%s): %e", msg.Words[0], err)
|
||||||
}
|
}
|
||||||
@@ -346,7 +352,8 @@ func (b *bolt) roleCheck(guild string, roles []string, s *dg.Session, run Comman
|
|||||||
|
|
||||||
func (b *bolt) timeoutCheck(msgID, channelID, guildID string, s *dg.Session, run Command) (bool, error) {
|
func (b *bolt) timeoutCheck(msgID, channelID, guildID string, s *dg.Session, run Command) (bool, error) {
|
||||||
wait := run.lastRun.Add(run.Timeout)
|
wait := run.lastRun.Add(run.Timeout)
|
||||||
if !time.Now().After(wait) {
|
now := time.Now()
|
||||||
|
if !now.After(wait) && !now.Equal(wait) {
|
||||||
reply := b.createReply(fmt.Sprintf("that command cannot be run for another %s", b.remainingTimeout(wait)), msgID, channelID, guildID)
|
reply := b.createReply(fmt.Sprintf("that command cannot be run for another %s", b.remainingTimeout(wait)), msgID, channelID, guildID)
|
||||||
_, err := s.ChannelMessageSendComplex(channelID, reply)
|
_, err := s.ChannelMessageSendComplex(channelID, reply)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
34
command.go
34
command.go
@@ -14,4 +14,36 @@ type Command struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// command payload functions, any strings returned are sent as a response to the command
|
// command payload functions, any strings returned are sent as a response to the command
|
||||||
type Payload func(msg *Message) error
|
type Payload func(msg *Message, admin AdminToolBox) error
|
||||||
|
|
||||||
|
type adminToolbox struct {
|
||||||
|
*bolt
|
||||||
|
}
|
||||||
|
type AdminToolBox interface {
|
||||||
|
Timeout(userId, serverId string, duration time.Time) error
|
||||||
|
ClearTimeout(userId, serverId string) error
|
||||||
|
Mute(userId, serverId string) error
|
||||||
|
Unmute(userId, serverId string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewToolbox(b *bolt) AdminToolBox {
|
||||||
|
return &adminToolbox{
|
||||||
|
bolt: b,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *adminToolbox) Timeout(userId, serverId string, duration time.Time) error {
|
||||||
|
return a.GuildMemberTimeout(serverId, userId, &duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *adminToolbox) ClearTimeout(userId, serverId string) error {
|
||||||
|
return a.GuildMemberTimeout(serverId, userId, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *adminToolbox) Mute(userId, serverId string) error {
|
||||||
|
return a.GuildMemberMute(serverId, userId, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *adminToolbox) Unmute(userId, serverId string) error {
|
||||||
|
return a.GuildMemberMute(serverId, userId, false)
|
||||||
|
}
|
||||||
|
|||||||
5
go.mod
5
go.mod
@@ -2,7 +2,10 @@ module code.jakeyoungdev.com/jake/bolt
|
|||||||
|
|
||||||
go 1.25.0
|
go 1.25.0
|
||||||
|
|
||||||
require github.com/bwmarrin/discordgo v0.29.0
|
require (
|
||||||
|
github.com/bwmarrin/discordgo v0.29.0
|
||||||
|
github.com/joho/godotenv v1.5.1
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gorilla/websocket v1.4.2 // indirect
|
github.com/gorilla/websocket v1.4.2 // indirect
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -2,6 +2,8 @@ github.com/bwmarrin/discordgo v0.29.0 h1:FmWeXFaKUwrcL3Cx65c20bTRW+vOb6k8AnaP+Eg
|
|||||||
github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
|||||||
68
message.go
68
message.go
@@ -2,7 +2,6 @@ package bolt
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
dg "github.com/bwmarrin/discordgo"
|
dg "github.com/bwmarrin/discordgo"
|
||||||
)
|
)
|
||||||
@@ -17,24 +16,28 @@ const (
|
|||||||
// a timeout to prevent hanging for too long, this timeout can be customized with the WithTimeout
|
// a timeout to prevent hanging for too long, this timeout can be customized with the WithTimeout
|
||||||
// option.
|
// option.
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Author string //current username of the message author
|
Author Author
|
||||||
authorID string //discord ID of message author
|
|
||||||
authorRoles []string
|
|
||||||
ID string //message ID
|
ID string //message ID
|
||||||
Words []string //message data split on whitespaces
|
Words []string //message data split on whitespaces
|
||||||
Content string //entire message data string
|
Content string //entire message data string
|
||||||
Channel string //name of channel message was sent in
|
Channel string //name of channel message was sent in
|
||||||
channelID string //ID of channel message was sent in
|
ChannelID string //ID of channel message was sent in
|
||||||
Server string //name of guild message was sent in
|
Server string //name of guild message was sent in
|
||||||
serverID string //ID of guild message was sent in
|
ServerID string //ID of guild message was sent in
|
||||||
Attachments []MessageAttachment //any attachments bound to the message
|
Attachments []MessageAttachment //any attachments bound to the message
|
||||||
Mentions []*dg.User
|
Mentions []*dg.User
|
||||||
sesh *bolt
|
sesh *bolt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Author struct {
|
||||||
|
Name string
|
||||||
|
ID string
|
||||||
|
Roles []string
|
||||||
|
}
|
||||||
|
|
||||||
// React applies reaction to the message
|
// React applies reaction to the message
|
||||||
func (m *Message) React(emoji Reaction) error {
|
func (m *Message) React(emoji Reaction) error {
|
||||||
return m.sesh.MessageReactionAdd(m.channelID, m.ID, fmt.Sprint(emoji))
|
return m.sesh.MessageReactionAdd(m.ChannelID, m.ID, fmt.Sprint(emoji))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond sends a response to the message, handling chunking if the message exceeds max length
|
// Respond sends a response to the message, handling chunking if the message exceeds max length
|
||||||
@@ -43,8 +46,8 @@ func (m *Message) Respond(res string) error {
|
|||||||
for len(res) > 0 {
|
for len(res) > 0 {
|
||||||
//send full chunk size allowed by discord
|
//send full chunk size allowed by discord
|
||||||
sc := res[:MSG_MAX_LENGTH]
|
sc := res[:MSG_MAX_LENGTH]
|
||||||
rep := m.sesh.createReply(sc, m.ID, m.channelID, m.serverID)
|
rep := m.sesh.createReply(sc, m.ID, m.ChannelID, m.ServerID)
|
||||||
_, err := m.sesh.ChannelMessageSendComplex(m.channelID, rep)
|
_, err := m.sesh.ChannelMessageSendComplex(m.ChannelID, rep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -52,8 +55,8 @@ func (m *Message) Respond(res string) error {
|
|||||||
|
|
||||||
//if we have left than a full chunk send the rest and break the loop
|
//if we have left than a full chunk send the rest and break the loop
|
||||||
if len(res) < MSG_MAX_LENGTH {
|
if len(res) < MSG_MAX_LENGTH {
|
||||||
final := m.sesh.createReply(res, m.ID, m.channelID, m.serverID)
|
final := m.sesh.createReply(res, m.ID, m.ChannelID, m.ServerID)
|
||||||
_, err := m.sesh.ChannelMessageSendComplex(m.channelID, final)
|
_, err := m.sesh.ChannelMessageSendComplex(m.ChannelID, final)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -66,44 +69,31 @@ func (m *Message) Respond(res string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//short enough message to send in one go
|
//short enough message to send in one go
|
||||||
rep := m.sesh.createReply(res, m.ID, m.channelID, m.serverID)
|
rep := m.sesh.createReply(res, m.ID, m.ChannelID, m.ServerID)
|
||||||
_, err := m.sesh.ChannelMessageSendComplex(m.channelID, rep)
|
_, err := m.sesh.ChannelMessageSendComplex(m.ChannelID, rep)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removes the message from the current channel
|
// Delete removes the message from the current channel
|
||||||
func (m *Message) Delete() error {
|
func (m *Message) Delete() error {
|
||||||
return m.sesh.ChannelMessageDelete(m.channelID, m.ID, nil)
|
return m.sesh.ChannelMessageDelete(m.ChannelID, m.ID, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timeout sets a timeout for the message author
|
// func (m *Message) Timeout(userID string, duration time.Time) error {
|
||||||
func (m *Message) Timeout(duration time.Time) error {
|
// return m.sesh.GuildMemberTimeout(m.serverID, userID, &duration)
|
||||||
return m.sesh.GuildMemberTimeout(m.serverID, m.authorID, &duration)
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
// ClearTimeout removes all timeouts for the message author
|
// func (m *Message) ClearTimeout(userID string) error {
|
||||||
func (m *Message) ClearTimeout() error {
|
// return m.sesh.GuildMemberTimeout(m.serverID, userID, nil)
|
||||||
return m.sesh.GuildMemberTimeout(m.serverID, m.authorID, nil)
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
// Ban removes a user from the server, banning them and removing all messages within the range of
|
// func (m *Message) Mute(userID string) error {
|
||||||
// the days parameter
|
// return m.sesh.GuildMemberMute(m.serverID, userID, true)
|
||||||
func (m *Message) Ban(reason string, days int) error {
|
// }
|
||||||
return m.sesh.GuildBanCreateWithReason(m.serverID, m.authorID, reason, days)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unban user
|
// func (m *Author) Unmute(userID string) error {
|
||||||
|
// return m.sesh.GuildMemberMute(m.serverID, userID, false)
|
||||||
// ClearBan deletes the ban on message Authors
|
// }
|
||||||
|
|
||||||
// lol this won't work, they're banned, same with all clear*
|
|
||||||
func (m *Message) ClearBan() error {
|
|
||||||
return m.sesh.GuildBanDelete(m.serverID, m.authorID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Message) Mute(username string) error {
|
|
||||||
return m.sesh.GuildMemberMute(m.serverID, m.authorID, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// message attachment details
|
// message attachment details
|
||||||
type MessageAttachment struct {
|
type MessageAttachment struct {
|
||||||
|
|||||||
@@ -22,10 +22,11 @@ const (
|
|||||||
dg.IntentGuildMembers |
|
dg.IntentGuildMembers |
|
||||||
dg.IntentGuildPresences |
|
dg.IntentGuildPresences |
|
||||||
dg.IntentMessageContent |
|
dg.IntentMessageContent |
|
||||||
dg.IntentsGuildMessages
|
dg.IntentsGuildMessages |
|
||||||
|
dg.IntentGuildMessageReactions
|
||||||
|
|
||||||
MessagePermissions Permission = Permission(msgPerms)
|
MessagePermissions Permission = Permission(msgPerms)
|
||||||
ReactionPermissions Permission = Permission(dg.IntentGuildMessageReactions)
|
AdminPermissions Permission = 0 //fake
|
||||||
//we also need a ModeratorPermissions for banning, kicking, etc.
|
//we also need a ModeratorPermissions for banning, kicking, etc.
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,6 +34,9 @@ func WithPermissions(perms ...Permission) Option {
|
|||||||
return func(b *bolt) {
|
return func(b *bolt) {
|
||||||
var fullPerms dg.Intent
|
var fullPerms dg.Intent
|
||||||
for _, p := range perms {
|
for _, p := range perms {
|
||||||
|
if p == AdminPermissions {
|
||||||
|
b.admin = true
|
||||||
|
}
|
||||||
fullPerms |= dg.Intent(p)
|
fullPerms |= dg.Intent(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user