Merge pull request #5 from dustinpianalto/development

Deploy v0.0.8
development v0.0.8
DustyP 5 years ago committed by GitHub
commit d9ddfaf2cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,9 +7,9 @@ COPY ./go.sum .
RUN go mod download RUN go mod download
COPY . . COPY . .
RUN go install github.com/dustinpianalto/goff RUN go install github.com/dustinpianalto/goff/...
CMD [ "go", "run", "goff.go"] CMD [ "go", "run", "cmd/goff/main.go"]
from alpine from alpine

@ -0,0 +1,3 @@
# Goff
A discord bot for fun

Binary file not shown.

@ -0,0 +1,148 @@
package main
import (
"fmt"
"log"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/goff/internal/exts"
"github.com/dustinpianalto/goff/internal/exts/guild_management"
"github.com/dustinpianalto/goff/internal/exts/logging"
"github.com/dustinpianalto/goff/internal/exts/tasks"
"github.com/dustinpianalto/goff/internal/exts/user_management"
"github.com/dustinpianalto/goff/internal/postgres"
"github.com/dustinpianalto/goff/internal/services"
"github.com/dustinpianalto/goff/pkg/email"
//"github.com/MikeModder/anpan"
"os"
"os/signal"
"syscall"
"github.com/bwmarrin/discordgo"
)
var (
Token string
)
//func init() {
// flag.StringVar(&Token, "t", "", "Bot Token")
// flag.Parse()
//}
func main() {
Token = os.Getenv("DISCORDGO_TOKEN")
dg, err := discordgo.New("Bot " + Token)
if err != nil {
fmt.Println("There was an error when creating the Discord Session, ", err)
return
}
dg.State.MaxMessageCount = 100
dg.StateEnabled = true
dg.Identify = discordgo.Identify{
Intents: discordgo.MakeIntent(discordgo.IntentsAll),
}
postgres.ConnectDatabase(os.Getenv("DATABASE_URL"))
postgres.InitializeDatabase()
//utils.LoadTestData()
us := &postgres.UserService{DB: postgres.DB}
gs := &postgres.GuildService{DB: postgres.DB}
//prefixes := []string{
// "Go.",
//}
owners := []string{
"351794468870946827",
}
manager := disgoman.CommandManager{
Prefixes: getPrefixes,
Owners: owners,
StatusManager: disgoman.GetDefaultStatusManager(),
ErrorChannel: make(chan disgoman.CommandError, 10),
Commands: make(map[string]*disgoman.Command),
IgnoreBots: true,
CheckPermissions: false,
}
// Add Command Handlers
exts.AddCommandHandlers(&manager)
services.InitalizeServices(us, gs)
//if _, ok := handler.Commands["help"]; !ok {
// handler.AddDefaultHelpCommand()
//}
dg.AddHandler(manager.OnMessage)
dg.AddHandler(manager.StatusManager.OnReady)
dg.AddHandler(guild_management.OnMessageUpdate)
dg.AddHandler(guild_management.OnMessageDelete)
dg.AddHandler(user_management.OnGuildMemberAddLogging)
dg.AddHandler(user_management.OnGuildMemberRemoveLogging)
err = dg.Open()
if err != nil {
fmt.Println("There was an error opening the connection, ", err)
return
}
// Start the Error handler in a goroutine
go ErrorHandler(manager.ErrorChannel)
// Start the Logging handler in a goroutine
go logging.LoggingHandler(logging.LoggingChannel)
// Start the task handler in a goroutine
go tasks.ProcessTasks(dg, 1)
go email.RecieveEmail(dg)
fmt.Println("The Bot is now running.")
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
<-sc
fmt.Println("Shutting Down...")
err = dg.Close()
if err != nil {
fmt.Println(err)
}
}
func getPrefixes(guildID string) []string {
queryString := "Select prefix from prefixes p, x_guilds_prefixes xgp where xgp.guild_id = $1 and xgp.prefix_id = p.id"
rows, err := postgres.DB.Query(queryString, guildID)
if err != nil {
log.Println(err)
return []string{"Go.", "go."}
}
var prefixes []string
for rows.Next() {
var prefix string
err = rows.Scan(&prefix)
if err != nil {
log.Println(err)
return []string{"Go.", "go."}
}
prefixes = append(prefixes, prefix)
}
if len(prefixes) == 0 {
prefixes = append(prefixes, "Go.", "go.")
}
return prefixes
}
func ErrorHandler(ErrorChan chan disgoman.CommandError) {
for ce := range ErrorChan {
msg := ce.Message
if msg == "" {
msg = ce.Error.Error()
}
_, _ = ce.Context.Send(msg)
fmt.Println(ce.Error)
}
}

@ -1,32 +0,0 @@
version: "3"
services:
# goff-db:
# image: postgres
# ports:
# - "5432:5432"
# volumes:
# - "${PWD}/postgres.conf:/etc/postgresql/postgresql.conf"
# - "goff-db:/var/lib/postgresql/data:rw"
# env_file: ${PWD}/.env
goff:
build:
context: .
dockerfile: "${PWD}/Dockerfile"
env_file: ${PWD}/.env
logging:
driver: awslogs
options:
awslogs-region: us-east-1
awslogs-group: "/docker/goff/production"
# depends_on:
# - goff-db
environment:
- DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable
# links:
# - goff-db:goff.db
#volumes:
# goff-db:
# external: true

@ -1,32 +0,0 @@
version: "3"
services:
# goff-db:
# image: postgres
# ports:
# - "5432:5432"
# volumes:
# - "${PWD}/postgres.conf:/etc/postgresql/postgresql.conf"
# - "goff-db:/var/lib/postgresql/data:rw"
# env_file: ${PWD}/.env
goff:
build:
context: .
dockerfile: "${PWD}/Dockerfile"
env_file: ${PWD}/.env
# logging:
# driver: awslogs
# options:
# awslogs-region: us-east-1
# awslogs-group: "/docker/goff/production"
# depends_on:
# - goff-db
environment:
- DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable
# links:
# - goff-db:goff.db
#volumes:
# goff-db:
# external: true

@ -1,84 +0,0 @@
package exts
import (
"fmt"
"strconv"
"strings"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/rpnparse"
)
func interleave(ctx disgoman.Context, args []string) {
if len(args) == 2 {
x, err := strconv.ParseInt(args[0], 10, 64)
if err != nil {
return
}
y, err := strconv.ParseInt(args[1], 10, 64)
if err != nil {
return
}
var z = int64(0)
for i := 0; i < 64; i++ {
x_masked_i := x & (1 << i)
y_masked_i := y & (1 << i)
z |= x_masked_i << i
z |= y_masked_i << (i + 1)
}
ctx.Send(fmt.Sprintf("%v", z))
}
}
func deinterleave(ctx disgoman.Context, args []string) {
if len(args) == 1 {
z, err := strconv.ParseInt(args[0], 10, 64)
if err != nil {
return
}
var x = int64(0)
var y = int64(0)
i := 0
for z > 0 {
x |= (z & 1) << i
z >>= 1
y |= (z & 1) << i
z >>= 1
i++
}
ctx.Send(fmt.Sprintf("(%v, %v)", x, y))
}
}
func generateRPNCommand(ctx disgoman.Context, args []string) {
rpn, err := rpnparse.GenerateRPN(args)
if err != nil {
ctx.Send(err.Error())
return
}
ctx.Send(rpn)
}
func parseRPNCommand(ctx disgoman.Context, args []string) {
res, err := rpnparse.ParseRPN(args)
if err != nil {
ctx.Send(err.Error())
return
}
ctx.Send(fmt.Sprintf("The result is: %v", res))
}
func solveCommand(ctx disgoman.Context, args []string) {
rpn, err := rpnparse.GenerateRPN(args)
if err != nil {
ctx.Send(err.Error())
return
}
res, err := rpnparse.ParseRPN(strings.Split(rpn, " "))
if err != nil {
ctx.Send(err.Error())
return
}
ctx.Send(fmt.Sprintf("The result is: %v", res))
}

@ -1,376 +0,0 @@
package exts
import (
"database/sql"
"fmt"
"strings"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/goff/utils"
)
// Guild management commands
func loggingChannel(ctx disgoman.Context, args []string) {
var idString string
if len(args) > 0 {
idString = args[0]
if strings.HasPrefix(idString, "<#") && strings.HasSuffix(idString, ">") {
idString = idString[2 : len(idString)-1]
}
} else {
idString = ""
}
fmt.Println(idString)
if idString == "" {
_, err := utils.Database.Exec("UPDATE guilds SET logging_channel='' WHERE id=$1;", ctx.Guild.ID)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Logging Channel Updated.")
return
}
channel, err := ctx.Session.State.Channel(idString)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Can't find that channel.",
Error: err,
}
return
}
if channel.GuildID != ctx.Guild.ID {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "The channel passed is not in this guild.",
Error: err,
}
return
}
_, err = utils.Database.Exec("UPDATE guilds SET logging_channel=$1 WHERE id=$2;", idString, ctx.Guild.ID)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Logging Channel Updated.")
}
func getLoggingChannel(ctx disgoman.Context, _ []string) {
var channelID string
row := utils.Database.QueryRow("SELECT logging_channel FROM guilds where id=$1", ctx.Guild.ID)
err := row.Scan(&channelID)
if err != nil {
fmt.Println(err)
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error getting data from the database.",
Error: err,
}
return
}
if channelID == "" {
_, _ = ctx.Send("The logging channel is not set.")
return
}
channel, err := ctx.Session.State.GuildChannel(ctx.Guild.ID, channelID)
if err != nil {
fmt.Println(err)
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "I got the channel ID but it does not appear to be a valid channel in this guild.",
Error: err,
}
return
}
_, _ = ctx.Send(fmt.Sprintf("The logging channel is currently %s", channel.Mention()))
return
}
func welcomeChannel(ctx disgoman.Context, args []string) {
var idString string
if len(args) > 0 {
idString = args[0]
if strings.HasPrefix(idString, "<#") && strings.HasSuffix(idString, ">") {
idString = idString[2 : len(idString)-1]
}
} else {
idString = ""
}
fmt.Println(idString)
if idString == "" {
_, err := utils.Database.Exec("UPDATE guilds SET welcome_channel='' WHERE id=$1;", ctx.Guild.ID)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Welcomer Disabled.")
return
}
channel, err := ctx.Session.State.Channel(idString)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Can't find that channel.",
Error: err,
}
return
}
if channel.GuildID != ctx.Guild.ID {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "The channel passed is not in this guild.",
Error: err,
}
return
}
_, err = utils.Database.Exec("UPDATE guilds SET welcome_channel=$1 WHERE id=$2;", idString, ctx.Guild.ID)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Welcome Channel Updated.")
return
}
func getWelcomeChannel(ctx disgoman.Context, _ []string) {
var channelID string
row := utils.Database.QueryRow("SELECT welcome_channel FROM guilds where id=$1", ctx.Guild.ID)
err := row.Scan(&channelID)
if err != nil {
fmt.Println(err)
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error getting data from the database.",
Error: err,
}
return
}
if channelID == "" {
_, _ = ctx.Send("The welcomer is disabled.")
return
}
channel, err := ctx.Session.State.GuildChannel(ctx.Guild.ID, channelID)
if err != nil {
fmt.Println(err)
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "I got the channel ID but it does not appear to be a valid channel in this guild.",
Error: err,
}
return
}
_, _ = ctx.Send(fmt.Sprintf("The welcome channel is currently %s", channel.Mention()))
}
func addGuildCommand(ctx disgoman.Context, args []string) {
var guildID string
row := utils.Database.QueryRow("SELECT id FROM guilds where id=$1", ctx.Guild.ID)
err := row.Scan(&guildID)
if err == nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "This guild is already in my database",
Error: err,
}
return
}
_, err = utils.Database.Query("INSERT INTO guilds (id) VALUES ($1)", ctx.Guild.ID)
if err != nil {
fmt.Println(err)
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "There was a problem inserting this guild into the database",
Error: err,
}
return
}
_, _ = ctx.Send("This guild has been added.")
}
func puzzleChannel(ctx disgoman.Context, args []string) {
var idString string
if len(args) > 0 {
idString = args[0]
if strings.HasPrefix(idString, "<#") && strings.HasSuffix(idString, ">") {
idString = idString[2 : len(idString)-1]
}
} else {
idString = ""
}
fmt.Println(idString)
if idString == "" {
_, err := utils.Database.Exec("UPDATE guilds SET puzzle_channel='' WHERE id=$1;", ctx.Guild.ID)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Puzzle Channel Updated.")
return
}
channel, err := ctx.Session.State.Channel(idString)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Can't find that channel.",
Error: err,
}
return
}
if channel.GuildID != ctx.Guild.ID {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "The channel passed is not in this guild.",
Error: err,
}
return
}
_, err = utils.Database.Exec("UPDATE guilds SET puzzle_channel=$1 WHERE id=$2;", idString, ctx.Guild.ID)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Puzzle Channel Updated.")
}
func getPuzzleChannel(ctx disgoman.Context, _ []string) {
var channelID string
row := utils.Database.QueryRow("SELECT puzzle_channel FROM guilds where id=$1", ctx.Guild.ID)
err := row.Scan(&channelID)
if err != nil {
fmt.Println(err)
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error getting data from the database.",
Error: err,
}
return
}
if channelID == "" {
_, _ = ctx.Send("The puzzle channel is not set.")
return
}
channel, err := ctx.Session.State.GuildChannel(ctx.Guild.ID, channelID)
if err != nil {
fmt.Println(err)
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "I got the channel ID but it does not appear to be a valid channel in this guild.",
Error: err,
}
return
}
_, _ = ctx.Send(fmt.Sprintf("The puzzle channel is currently %s", channel.Mention()))
return
}
func puzzleRole(ctx disgoman.Context, args []string) {
var idString string
if len(args) > 0 {
idString = args[0]
if strings.HasPrefix(idString, "<@&") && strings.HasSuffix(idString, ">") {
idString = idString[3 : len(idString)-1]
}
} else {
idString = ""
}
fmt.Println(idString)
if idString == "" {
_, err := utils.Database.Exec("UPDATE guilds SET puzzle_role=NULL WHERE id=$1;", ctx.Guild.ID)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Puzzle Role Cleared.")
return
}
role, err := ctx.Session.State.Role(ctx.Guild.ID, idString)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Can't find that Role.",
Error: err,
}
return
}
_, err = utils.Database.Exec("INSERT INTO roles (id, guild_id) VALUES ($1, $2) ON CONFLICT DO NOTHING", role.ID, ctx.Guild.ID)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, err = utils.Database.Exec("UPDATE guilds SET puzzle_role=$1 WHERE id=$2;", role.ID, ctx.Guild.ID)
if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Puzzle Role Updated.")
}
func getPuzzleRole(ctx disgoman.Context, _ []string) {
var roleID sql.NullString
row := utils.Database.QueryRow("SELECT puzzle_role FROM guilds where id=$1", ctx.Guild.ID)
err := row.Scan(&roleID)
if err != nil {
fmt.Println(err)
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error getting data from the database.",
Error: err,
}
return
}
if !roleID.Valid {
_, _ = ctx.Send("The puzzle role is not set.")
return
}
role, err := ctx.Session.State.Role(ctx.Guild.ID, roleID.String)
if err != nil {
fmt.Println(err)
ctx.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "I got the role ID but it does not appear to be a valid role in this guild.",
Error: err,
}
return
}
_, _ = ctx.Send(fmt.Sprintf("The puzzle role is currently %s", role.Mention()))
return
}

@ -1,288 +0,0 @@
package exts
import (
"github.com/dustinpianalto/disgoman"
)
func AddCommandHandlers(h *disgoman.CommandManager) {
// Arguments:
// name - command name - string
// desc - command description - string
// owneronly - only allow owners to run - bool
// hidden - hide command from non-owners - bool
// perms - permissisions required - anpan.Permission (int)
// type - command type, sets where the command is available
// run - function to run - func(anpan.Context, []string) / CommandRunFunc
_ = h.AddCommand(&disgoman.Command{
Name: "ping",
Aliases: nil,
Description: "Check the bot's ping",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: pingCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "say",
Aliases: nil,
Description: "Repeat a message",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
SanitizeEveryone: true,
Invoke: sayCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "user",
Aliases: nil,
Description: "Get user info",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: userCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "git",
Aliases: nil,
Description: "Show my github link",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: gitCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "tag",
Aliases: nil,
Description: "Get a tag",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: tagCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "addtag",
Aliases: nil,
Description: "Add a tag",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
SanitizeEveryone: true,
Invoke: addTagCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "invite",
Aliases: nil,
Description: "Get the invite link for this bot or others",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: inviteCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "P",
Aliases: nil,
Description: "Interpret a P\" program and return the results",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: pCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "set-logging-channel",
Aliases: []string{"slc"},
Description: "Set the channel logging messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: loggingChannel,
})
_ = h.AddCommand(&disgoman.Command{
Name: "get-logging-channel",
Aliases: []string{"glc"},
Description: "Gets the channel logging messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: getLoggingChannel,
})
_ = h.AddCommand(&disgoman.Command{
Name: "set-welcome-channel",
Aliases: []string{"swc"},
Description: "Set the channel welcome messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: welcomeChannel,
})
_ = h.AddCommand(&disgoman.Command{
Name: "get-welcome-channel",
Aliases: []string{"gwc"},
Description: "Gets the channel welcome messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: getWelcomeChannel,
})
_ = h.AddCommand(&disgoman.Command{
Name: "kick",
Aliases: nil,
Description: "Kicks the given user with the given reason",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionKickMembers,
Invoke: kickUserCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "addGuild",
Aliases: nil,
Description: "Adds the current guild to the database",
OwnerOnly: true,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: addGuildCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "ban",
Aliases: []string{"ban-no-delete"},
Description: "Bans the given user with the given reason",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionBanMembers,
Invoke: banUserCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "unban",
Aliases: nil,
Description: "Unbans the given user",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionBanMembers,
Invoke: unbanUserCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "remind",
Aliases: nil,
Description: "Remind me at a later time",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: addReminderCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "encode",
Aliases: []string{"e"},
Description: "Encode 2 numbers",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: interleave,
})
_ = h.AddCommand(&disgoman.Command{
Name: "decode",
Aliases: []string{"d"},
Description: "Decode 1 number into 2",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: deinterleave,
})
_ = h.AddCommand(&disgoman.Command{
Name: "set-puzzle-channel",
Aliases: []string{"spc"},
Description: "Set the channel puzzle messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: puzzleChannel,
})
_ = h.AddCommand(&disgoman.Command{
Name: "get-puzzle-channel",
Aliases: []string{"gpc"},
Description: "Gets the channel puzzle messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: getPuzzleChannel,
})
_ = h.AddCommand(&disgoman.Command{
Name: "set-puzzle-role",
Aliases: []string{"spr"},
Description: "Set the role to be pinged when there is a new puzzle",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: puzzleRole,
})
_ = h.AddCommand(&disgoman.Command{
Name: "get-puzzle-role",
Aliases: []string{"gpr"},
Description: "Get the role that will be pinged when there is a new puzzle",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: getPuzzleRole,
})
_ = h.AddCommand(&disgoman.Command{
Name: "RPN",
Aliases: []string{"rpn"},
Description: "Convert infix to rpn",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: generateRPNCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "ParseRPN",
Aliases: []string{"PRPN", "prpn"},
Description: "Parse RPN string and return the result",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: parseRPNCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "solve",
Aliases: []string{"math", "infix"},
Description: "Solve infix equation and return the result",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: solveCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "make-role-self-assignable",
Aliases: []string{"makesar"},
Description: "Makes the passed in role self assignable by anyone",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: makeRoleSelfAssignable,
})
_ = h.AddCommand(&disgoman.Command{
Name: "remove-self-assignable-role",
Aliases: []string{"removesar"},
Description: "Makes a role that was previously self assignable not so",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: removeSelfAssignableRole,
})
_ = h.AddCommand(&disgoman.Command{
Name: "giverole",
Aliases: []string{"iwant", "givetome"},
Description: "Assigns a person the passed in role if it is self assignable",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: selfAssignRole,
})
_ = h.AddCommand(&disgoman.Command{
Name: "removerole",
Aliases: []string{"idon'twant"},
Description: "Removes a role from a person if the role is self assignable",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: unAssignRole,
})
}

@ -4,7 +4,7 @@ go 1.14
require ( require (
github.com/bwmarrin/discordgo v0.22.0 github.com/bwmarrin/discordgo v0.22.0
github.com/dustinpianalto/disgoman v0.0.12 github.com/dustinpianalto/disgoman v0.0.15
github.com/dustinpianalto/rpnparse v1.0.1 github.com/dustinpianalto/rpnparse v1.0.1
github.com/emersion/go-imap v1.0.5 github.com/emersion/go-imap v1.0.5
github.com/emersion/go-message v0.12.0 github.com/emersion/go-message v0.12.0

@ -13,6 +13,10 @@ github.com/dustinpianalto/disgoman v0.0.10 h1:UzmvMpOi4peF59tXGaNfVU+ePHs1hILa6g
github.com/dustinpianalto/disgoman v0.0.10/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g= github.com/dustinpianalto/disgoman v0.0.10/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g=
github.com/dustinpianalto/disgoman v0.0.12 h1:dLptU2ZTUZJaLBOKeE6qjuL8gqdAr6ehHSOtfHmUpL8= github.com/dustinpianalto/disgoman v0.0.12 h1:dLptU2ZTUZJaLBOKeE6qjuL8gqdAr6ehHSOtfHmUpL8=
github.com/dustinpianalto/disgoman v0.0.12/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g= github.com/dustinpianalto/disgoman v0.0.12/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g=
github.com/dustinpianalto/disgoman v0.0.14 h1:hsk56JATBE5eH5GPCDGeiTdYxok4m+edSYiYz5Uj8uo=
github.com/dustinpianalto/disgoman v0.0.14/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g=
github.com/dustinpianalto/disgoman v0.0.15 h1:kdIw6jhC82WBut7+4BarqxBw06dozU+Hu47LQzkkoGM=
github.com/dustinpianalto/disgoman v0.0.15/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g=
github.com/dustinpianalto/rpnparse v1.0.1 h1:ZvH1/RIe5hh3RGSAXOgtngEDHNPTF+DMh88XFWpQjzY= github.com/dustinpianalto/rpnparse v1.0.1 h1:ZvH1/RIe5hh3RGSAXOgtngEDHNPTF+DMh88XFWpQjzY=
github.com/dustinpianalto/rpnparse v1.0.1/go.mod h1:SzFbQb+Eed5gYCtDu/SYEXXwdPtWkDg9oaL1xQtN1BY= github.com/dustinpianalto/rpnparse v1.0.1/go.mod h1:SzFbQb+Eed5gYCtDu/SYEXXwdPtWkDg9oaL1xQtN1BY=
github.com/emersion/go-imap v1.0.5 h1:8xg/d2wo2BBP3AEP5AOaM/6i8887RGyVW2st/IVHWUw= github.com/emersion/go-imap v1.0.5 h1:8xg/d2wo2BBP3AEP5AOaM/6i8887RGyVW2st/IVHWUw=

@ -1,141 +1,9 @@
package main package goff
import ( import "github.com/dustinpianalto/disgoman"
"fmt"
"log"
"github.com/dustinpianalto/disgoman" type CommandManager struct {
"github.com/dustinpianalto/goff/events" UserService UserService
"github.com/dustinpianalto/goff/exts" GuildService GuildService
"github.com/dustinpianalto/goff/utils" disgoman.CommandManager
//"github.com/MikeModder/anpan"
"os"
"os/signal"
"syscall"
"github.com/bwmarrin/discordgo"
)
var (
Token string
)
//func init() {
// flag.StringVar(&Token, "t", "", "Bot Token")
// flag.Parse()
//}
func main() {
Token = os.Getenv("DISCORDGO_TOKEN")
dg, err := discordgo.New("Bot " + Token)
if err != nil {
fmt.Println("There was an error when creating the Discord Session, ", err)
return
}
dg.State.MaxMessageCount = 100
dg.StateEnabled = true
dg.Identify = discordgo.Identify{
Intents: discordgo.MakeIntent(discordgo.IntentsAll),
}
utils.ConnectDatabase(os.Getenv("DATABASE_URL"))
utils.InitializeDatabase()
//utils.LoadTestData()
//prefixes := []string{
// "Go.",
//}
owners := []string{
"351794468870946827",
}
// Arguments are:
// prefixes - []string
// owner ids - []string
// ignore bots - bool
// check perms - bool
handler := disgoman.CommandManager{
Prefixes: getPrefixes,
Owners: owners,
StatusManager: disgoman.GetDefaultStatusManager(),
ErrorChannel: make(chan disgoman.CommandError, 10),
Commands: make(map[string]*disgoman.Command),
IgnoreBots: true,
CheckPermissions: false,
}
// Add Command Handlers
exts.AddCommandHandlers(&handler)
//if _, ok := handler.Commands["help"]; !ok {
// handler.AddDefaultHelpCommand()
//}
dg.AddHandler(handler.OnMessage)
dg.AddHandler(handler.StatusManager.OnReady)
dg.AddHandler(events.OnMessageUpdate)
dg.AddHandler(events.OnMessageDelete)
dg.AddHandler(events.OnGuildMemberAddLogging)
dg.AddHandler(events.OnGuildMemberRemoveLogging)
err = dg.Open()
if err != nil {
fmt.Println("There was an error opening the connection, ", err)
return
}
// Start the Error handler in a goroutine
go ErrorHandler(handler.ErrorChannel)
// Start the Logging handler in a goroutine
go utils.LoggingHandler(utils.LoggingChannel)
// Start the task handler in a goroutine
go utils.ProcessTasks(dg, 1)
go utils.RecieveEmail(dg)
fmt.Println("The Bot is now running.")
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
<-sc
fmt.Println("Shutting Down...")
err = dg.Close()
if err != nil {
fmt.Println(err)
}
}
func getPrefixes(guildID string) []string {
queryString := "Select prefix from prefixes p, x_guilds_prefixes xgp where xgp.guild_id = $1 and xgp.prefix_id = p.id"
rows, err := utils.Database.Query(queryString, guildID)
if err != nil {
log.Println(err)
return []string{"Go.", "go."}
}
var prefixes []string
for rows.Next() {
var prefix string
err = rows.Scan(&prefix)
if err != nil {
log.Println(err)
return []string{"Go.", "go."}
}
prefixes = append(prefixes, prefix)
}
return prefixes
}
func ErrorHandler(ErrorChan chan disgoman.CommandError) {
for ce := range ErrorChan {
msg := ce.Message
if msg == "" {
msg = ce.Error.Error()
}
_, _ = ce.Context.Send(msg)
fmt.Println(ce.Error)
}
} }

@ -0,0 +1,22 @@
package goff
import "database/sql"
type Guild struct {
ID string
WelcomeMessage string
GoodbyeMessage string
LoggingChannel string
WelcomeChannel string
PuzzleChannel string
PuzzleRole sql.NullString
Prefixes []string
}
type GuildService interface {
Guild(id string) (*Guild, error)
CreateGuild(g *Guild) error
DeleteGuild(g *Guild) error
GuildUsers(g *Guild) ([]*User, error)
UpdateGuild(g *Guild) error
}

@ -1,4 +1,4 @@
package utils package discord_utils
import ( import (
"fmt" "fmt"

@ -1,4 +1,4 @@
package utils package discord_utils
import "time" import "time"

@ -0,0 +1,134 @@
package fun
import (
"fmt"
"strconv"
"strings"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/rpnparse"
)
var InterleaveCommand = &disgoman.Command{
Name: "encode",
Aliases: []string{"e"},
Description: "Encode 2 numbers",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: interleaveFunc,
}
func interleaveFunc(ctx disgoman.Context, args []string) {
if len(args) == 2 {
x, err := strconv.ParseInt(args[0], 10, 64)
if err != nil {
return
}
y, err := strconv.ParseInt(args[1], 10, 64)
if err != nil {
return
}
var z = int64(0)
for i := 0; i < 64; i++ {
x_masked_i := x & (1 << i)
y_masked_i := y & (1 << i)
z |= x_masked_i << i
z |= y_masked_i << (i + 1)
}
ctx.Send(fmt.Sprintf("%v", z))
}
}
var DeinterleaveCommand = &disgoman.Command{
Name: "decode",
Aliases: []string{"d"},
Description: "Decode 1 number into 2",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: deinterleaveFunc,
}
func deinterleaveFunc(ctx disgoman.Context, args []string) {
if len(args) == 1 {
z, err := strconv.ParseInt(args[0], 10, 64)
if err != nil {
return
}
var x = int64(0)
var y = int64(0)
i := 0
for z > 0 {
x |= (z & 1) << i
z >>= 1
y |= (z & 1) << i
z >>= 1
i++
}
ctx.Send(fmt.Sprintf("(%v, %v)", x, y))
}
}
var GenerateRPNCommand = &disgoman.Command{
Name: "RPN",
Aliases: []string{"rpn"},
Description: "Convert infix to rpn",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: generateRPNFunc,
}
func generateRPNFunc(ctx disgoman.Context, args []string) {
rpn, err := rpnparse.GenerateRPN(args)
if err != nil {
ctx.Send(err.Error())
return
}
ctx.Send(rpn)
}
var ParseRPNCommand = &disgoman.Command{
Name: "ParseRPN",
Aliases: []string{"PRPN", "prpn"},
Description: "Parse RPN string and return the result",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: parseRPNFunc,
}
func parseRPNFunc(ctx disgoman.Context, args []string) {
res, err := rpnparse.ParseRPN(args)
if err != nil {
ctx.Send(err.Error())
return
}
ctx.Send(fmt.Sprintf("The result is: %v", res))
}
var SolveCommand = &disgoman.Command{
Name: "solve",
Aliases: []string{"math", "infix"},
Description: "Solve infix equation and return the result",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: solveFunc,
}
func solveFunc(ctx disgoman.Context, args []string) {
rpn, err := rpnparse.GenerateRPN(args)
if err != nil {
ctx.Send(err.Error())
return
}
res, err := rpnparse.ParseRPN(strings.Split(rpn, " "))
if err != nil {
ctx.Send(err.Error())
return
}
ctx.Send(fmt.Sprintf("The result is: %v", res))
}

@ -0,0 +1,476 @@
package guild_management
import (
"database/sql"
"fmt"
"strings"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/goff/internal/postgres"
"github.com/dustinpianalto/goff/internal/services"
)
// Guild management commands
var SetLoggingChannelCommand = &disgoman.Command{
Name: "set-logging-channel",
Aliases: []string{"slc"},
Description: "Set the channel logging messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: setLoggingChannelFunc,
}
func setLoggingChannelFunc(ctx disgoman.Context, args []string) {
var idString string
if len(args) > 0 {
idString = args[0]
if strings.HasPrefix(idString, "<#") && strings.HasSuffix(idString, ">") {
idString = idString[2 : len(idString)-1]
}
} else {
idString = ""
}
guild, err := services.GuildService.Guild(ctx.Guild.ID)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
if idString == "" {
guild.LoggingChannel = idString
err = services.GuildService.UpdateGuild(guild)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Logging Channel Updated.")
return
}
channel, err := ctx.Session.State.Channel(idString)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Can't find that channel.",
Error: err,
}
return
}
if channel.GuildID != ctx.Guild.ID {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "The channel passed is not in this guild.",
Error: err,
}
return
}
guild.LoggingChannel = channel.ID
err = services.GuildService.UpdateGuild(guild)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Logging Channel Updated.")
}
var GetLoggingChannelCommand = &disgoman.Command{
Name: "get-logging-channel",
Aliases: []string{"glc"},
Description: "Gets the channel logging messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: getLoggingChannelFunc,
}
func getLoggingChannelFunc(ctx disgoman.Context, _ []string) {
var channelID string
row := postgres.DB.QueryRow("SELECT logging_channel FROM guilds where id=$1", ctx.Guild.ID)
err := row.Scan(&channelID)
if err != nil {
fmt.Println(err)
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error getting data from the database.",
Error: err,
}
return
}
if channelID == "" {
_, _ = ctx.Send("The logging channel is not set.")
return
}
channel, err := ctx.Session.State.GuildChannel(ctx.Guild.ID, channelID)
if err != nil {
fmt.Println(err)
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "I got the channel ID but it does not appear to be a valid channel in this guild.",
Error: err,
}
return
}
_, _ = ctx.Send(fmt.Sprintf("The logging channel is currently %s", channel.Mention()))
return
}
var SetWelcomeChannelCommand = &disgoman.Command{
Name: "set-welcome-channel",
Aliases: []string{"swc"},
Description: "Set the channel welcome messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: setWelcomeChannelFunc,
}
func setWelcomeChannelFunc(ctx disgoman.Context, args []string) {
var idString string
if len(args) > 0 {
idString = args[0]
if strings.HasPrefix(idString, "<#") && strings.HasSuffix(idString, ">") {
idString = idString[2 : len(idString)-1]
}
} else {
idString = ""
}
fmt.Println(idString)
if idString == "" {
_, err := postgres.DB.Exec("UPDATE guilds SET welcome_channel='' WHERE id=$1;", ctx.Guild.ID)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Welcomer Disabled.")
return
}
channel, err := ctx.Session.State.Channel(idString)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Can't find that channel.",
Error: err,
}
return
}
if channel.GuildID != ctx.Guild.ID {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "The channel passed is not in this guild.",
Error: err,
}
return
}
_, err = postgres.DB.Exec("UPDATE guilds SET welcome_channel=$1 WHERE id=$2;", idString, ctx.Guild.ID)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Welcome Channel Updated.")
return
}
var GetWelcomeChannelCommand = &disgoman.Command{
Name: "get-welcome-channel",
Aliases: []string{"gwc"},
Description: "Gets the channel welcome messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: getWelcomeChannelFunc,
}
func getWelcomeChannelFunc(ctx disgoman.Context, _ []string) {
var channelID string
row := postgres.DB.QueryRow("SELECT welcome_channel FROM guilds where id=$1", ctx.Guild.ID)
err := row.Scan(&channelID)
if err != nil {
fmt.Println(err)
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error getting data from the database.",
Error: err,
}
return
}
if channelID == "" {
_, _ = ctx.Send("The welcomer is disabled.")
return
}
channel, err := ctx.Session.State.GuildChannel(ctx.Guild.ID, channelID)
if err != nil {
fmt.Println(err)
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "I got the channel ID but it does not appear to be a valid channel in this guild.",
Error: err,
}
return
}
_, _ = ctx.Send(fmt.Sprintf("The welcome channel is currently %s", channel.Mention()))
}
var AddGuildCommand = &disgoman.Command{
Name: "addGuild",
Aliases: nil,
Description: "Adds the current guild to the database",
OwnerOnly: true,
Hidden: false,
RequiredPermissions: 0,
Invoke: addGuildCommandFunc,
}
func addGuildCommandFunc(ctx disgoman.Context, args []string) {
var guildID string
row := postgres.DB.QueryRow("SELECT id FROM guilds where id=$1", ctx.Guild.ID)
err := row.Scan(&guildID)
if err == nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "This guild is already in my database",
Error: err,
}
return
}
_, err = postgres.DB.Query("INSERT INTO guilds (id) VALUES ($1)", ctx.Guild.ID)
if err != nil {
fmt.Println(err)
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "There was a problem inserting this guild into the database",
Error: err,
}
return
}
_, _ = ctx.Send("This guild has been added.")
}
var SetPuzzleChannelCommand = &disgoman.Command{
Name: "set-puzzle-channel",
Aliases: []string{"spc"},
Description: "Set the channel puzzle messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: setPuzzleChannelFunc,
}
func setPuzzleChannelFunc(ctx disgoman.Context, args []string) {
var idString string
if len(args) > 0 {
idString = args[0]
if strings.HasPrefix(idString, "<#") && strings.HasSuffix(idString, ">") {
idString = idString[2 : len(idString)-1]
}
} else {
idString = ""
}
fmt.Println(idString)
if idString == "" {
_, err := postgres.DB.Exec("UPDATE guilds SET puzzle_channel='' WHERE id=$1;", ctx.Guild.ID)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Puzzle Channel Updated.")
return
}
channel, err := ctx.Session.State.Channel(idString)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Can't find that channel.",
Error: err,
}
return
}
if channel.GuildID != ctx.Guild.ID {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "The channel passed is not in this guild.",
Error: err,
}
return
}
_, err = postgres.DB.Exec("UPDATE guilds SET puzzle_channel=$1 WHERE id=$2;", idString, ctx.Guild.ID)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Puzzle Channel Updated.")
}
var GetPuzzleChannelCommand = &disgoman.Command{
Name: "get-puzzle-channel",
Aliases: []string{"gpc"},
Description: "Gets the channel puzzle messages will be sent to.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: getPuzzleChannelFunc,
}
func getPuzzleChannelFunc(ctx disgoman.Context, _ []string) {
var channelID string
row := postgres.DB.QueryRow("SELECT puzzle_channel FROM guilds where id=$1", ctx.Guild.ID)
err := row.Scan(&channelID)
if err != nil {
fmt.Println(err)
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error getting data from the database.",
Error: err,
}
return
}
if channelID == "" {
_, _ = ctx.Send("The puzzle channel is not set.")
return
}
channel, err := ctx.Session.State.GuildChannel(ctx.Guild.ID, channelID)
if err != nil {
fmt.Println(err)
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "I got the channel ID but it does not appear to be a valid channel in this guild.",
Error: err,
}
return
}
_, _ = ctx.Send(fmt.Sprintf("The puzzle channel is currently %s", channel.Mention()))
return
}
var SetPuzzleRoleCommand = &disgoman.Command{
Name: "set-puzzle-role",
Aliases: []string{"spr"},
Description: "Set the role to be pinged when there is a new puzzle",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: setPuzzleRoleFunc,
}
func setPuzzleRoleFunc(ctx disgoman.Context, args []string) {
var idString string
if len(args) > 0 {
idString = args[0]
if strings.HasPrefix(idString, "<@&") && strings.HasSuffix(idString, ">") {
idString = idString[3 : len(idString)-1]
}
} else {
idString = ""
}
fmt.Println(idString)
if idString == "" {
_, err := postgres.DB.Exec("UPDATE guilds SET puzzle_role=NULL WHERE id=$1;", ctx.Guild.ID)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Puzzle Role Cleared.")
return
}
role, err := ctx.Session.State.Role(ctx.Guild.ID, idString)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Can't find that Role.",
Error: err,
}
return
}
_, err = postgres.DB.Exec("INSERT INTO roles (id, guild_id) VALUES ($1, $2) ON CONFLICT DO NOTHING", role.ID, ctx.Guild.ID)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, err = postgres.DB.Exec("UPDATE guilds SET puzzle_role=$1 WHERE id=$2;", role.ID, ctx.Guild.ID)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error Updating Database",
Error: err,
}
return
}
_, _ = ctx.Send("Puzzle Role Updated.")
}
var GetPuzzleRoleCommand = &disgoman.Command{
Name: "get-puzzle-role",
Aliases: []string{"gpr"},
Description: "Get the role that will be pinged when there is a new puzzle",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: getPuzzleRoleFunc,
}
func getPuzzleRoleFunc(ctx disgoman.Context, _ []string) {
var roleID sql.NullString
row := postgres.DB.QueryRow("SELECT puzzle_role FROM guilds where id=$1", ctx.Guild.ID)
err := row.Scan(&roleID)
if err != nil {
fmt.Println(err)
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error getting data from the database.",
Error: err,
}
return
}
if !roleID.Valid {
_, _ = ctx.Send("The puzzle role is not set.")
return
}
role, err := ctx.Session.State.Role(ctx.Guild.ID, roleID.String)
if err != nil {
fmt.Println(err)
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "I got the role ID but it does not appear to be a valid role in this guild.",
Error: err,
}
return
}
_, _ = ctx.Send(fmt.Sprintf("The puzzle role is currently %s", role.Mention()))
return
}

@ -1,11 +1,11 @@
package events package guild_management
import ( import (
"fmt" "fmt"
"log" "log"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/goff/utils" "github.com/dustinpianalto/goff/internal/postgres"
) )
func OnMessageUpdate(session *discordgo.Session, m *discordgo.MessageUpdate) { func OnMessageUpdate(session *discordgo.Session, m *discordgo.MessageUpdate) {
@ -19,7 +19,7 @@ func OnMessageUpdate(session *discordgo.Session, m *discordgo.MessageUpdate) {
return return
} }
var channelID string var channelID string
row := utils.Database.QueryRow("SELECT logging_channel FROM guilds where id=$1", msg.GuildID) row := postgres.DB.QueryRow("SELECT logging_channel FROM guilds where id=$1", msg.GuildID)
err := row.Scan(&channelID) err := row.Scan(&channelID)
if err != nil || channelID == "" { if err != nil || channelID == "" {
return return
@ -56,7 +56,7 @@ func OnMessageDelete(session *discordgo.Session, m *discordgo.MessageDelete) {
return return
} }
var channelID string var channelID string
row := utils.Database.QueryRow("SELECT logging_channel FROM guilds where id=$1", msg.GuildID) row := postgres.DB.QueryRow("SELECT logging_channel FROM guilds where id=$1", msg.GuildID)
err := row.Scan(&channelID) err := row.Scan(&channelID)
if err != nil || channelID == "" { if err != nil || channelID == "" {
return return

@ -0,0 +1,56 @@
package exts
import (
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/goff/internal/exts/fun"
"github.com/dustinpianalto/goff/internal/exts/guild_management"
"github.com/dustinpianalto/goff/internal/exts/roles"
"github.com/dustinpianalto/goff/internal/exts/tags"
"github.com/dustinpianalto/goff/internal/exts/tasks"
"github.com/dustinpianalto/goff/internal/exts/user_management"
"github.com/dustinpianalto/goff/internal/exts/utils"
"github.com/dustinpianalto/goff/internal/exts/p_interpreter"
)
func AddCommandHandlers(h *disgoman.CommandManager) {
// Arguments:
// name - command name - string
// desc - command description - string
// owneronly - only allow owners to run - bool
// hidden - hide command from non-owners - bool
// perms - permissisions required - anpan.Permission (int)
// type - command type, sets where the command is available
// run - function to run - func(anpan.Context, []string) / CommandRunFunc
_ = h.AddCommand(utils.UserCommand)
_ = h.AddCommand(utils.SayCommand)
_ = h.AddCommand(utils.GitCommand)
_ = h.AddCommand(utils.InviteCommand)
_ = h.AddCommand(utils.PingCommand)
_ = h.AddCommand(tasks.AddReminderCommand)
_ = h.AddCommand(tags.AddTagCommand)
_ = h.AddCommand(tags.TagCommand)
_ = h.AddCommand(roles.MakeRoleSelfAssignableCommand)
_ = h.AddCommand(roles.RemoveSelfAssignableCommand)
_ = h.AddCommand(roles.SelfAssignRoleCommand)
_ = h.AddCommand(roles.UnAssignRoleCommand)
_ = h.AddCommand(p_interpreter.PCommand)
_ = h.AddCommand(fun.InterleaveCommand)
_ = h.AddCommand(fun.DeinterleaveCommand)
_ = h.AddCommand(fun.GenerateRPNCommand)
_ = h.AddCommand(fun.ParseRPNCommand)
_ = h.AddCommand(fun.SolveCommand)
_ = h.AddCommand(user_management.KickUserCommand)
_ = h.AddCommand(user_management.BanUserCommand)
_ = h.AddCommand(user_management.UnbanUserCommand)
_ = h.AddCommand(guild_management.SetLoggingChannelCommand)
_ = h.AddCommand(guild_management.GetLoggingChannelCommand)
_ = h.AddCommand(guild_management.SetWelcomeChannelCommand)
_ = h.AddCommand(guild_management.GetWelcomeChannelCommand)
_ = h.AddCommand(guild_management.AddGuildCommand)
_ = h.AddCommand(guild_management.SetPuzzleChannelCommand)
_ = h.AddCommand(guild_management.GetPuzzleChannelCommand)
_ = h.AddCommand(guild_management.SetPuzzleRoleCommand)
_ = h.AddCommand(guild_management.GetPuzzleRoleCommand)
}

@ -1,8 +1,10 @@
package utils package logging
import ( import (
"fmt" "fmt"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/goff/internal/postgres"
) )
var LoggingChannel = make(chan *LogEvent, 10) var LoggingChannel = make(chan *LogEvent, 10)
@ -19,7 +21,7 @@ type LogEvent struct {
func LoggingHandler(lc chan *LogEvent) { func LoggingHandler(lc chan *LogEvent) {
for event := range lc { for event := range lc {
var channelID string var channelID string
row := Database.QueryRow("SELECT logging_channel FROM guilds where id=$1", event.GuildID) row := postgres.DB.QueryRow("SELECT logging_channel FROM guilds where id=$1", event.GuildID)
err := row.Scan(&channelID) err := row.Scan(&channelID)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)

@ -1,13 +1,24 @@
package exts package p_interpreter
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/dustinpianalto/disgoman"
"strings" "strings"
"github.com/dustinpianalto/disgoman"
) )
func pCommand(ctx disgoman.Context, args []string) { var PCommand = &disgoman.Command{
Name: "P",
Aliases: nil,
Description: "Interpret a P\" program and return the results",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: pCommandFunc,
}
func pCommandFunc(ctx disgoman.Context, args []string) {
input := strings.Join(args, "") input := strings.Join(args, "")
const LENGTH = 1999 const LENGTH = 1999
var mem [LENGTH]byte var mem [LENGTH]byte
@ -57,7 +68,7 @@ func pCommand(ctx disgoman.Context, args []string) {
} }
} }
} else { } else {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: fmt.Sprintf("Invalid Character: %v", input[i]), Message: fmt.Sprintf("Invalid Character: %v", input[i]),
Error: errors.New("invalid character"), Error: errors.New("invalid character"),
@ -73,7 +84,7 @@ func pCommand(ctx disgoman.Context, args []string) {
} }
_, err := ctx.Send(string(out)) _, err := ctx.Send(string(out))
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Couldn't send results", Message: "Couldn't send results",
Error: err, Error: err,

@ -1,4 +1,4 @@
package exts package roles
import ( import (
"fmt" "fmt"
@ -7,10 +7,20 @@ import (
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/disgoman" "github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/goff/utils" "github.com/dustinpianalto/goff/internal/postgres"
) )
func makeRoleSelfAssignable(ctx disgoman.Context, args []string) { var MakeRoleSelfAssignableCommand = &disgoman.Command{
Name: "make-role-self-assignable",
Aliases: []string{"makesar"},
Description: "Makes the passed in role self assignable by anyone",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: makeRoleSelfAssignableCommandFunc,
}
func makeRoleSelfAssignableCommandFunc(ctx disgoman.Context, args []string) {
var roleString string var roleString string
var roleID string var roleID string
if len(args) > 0 { if len(args) > 0 {
@ -31,16 +41,16 @@ func makeRoleSelfAssignable(ctx disgoman.Context, args []string) {
var role *discordgo.Role var role *discordgo.Role
var err error var err error
if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil { if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Can't find that Role.", Message: "Can't find that Role.",
Error: err, Error: err,
} }
return return
} }
_, err = utils.Database.Exec("INSERT INTO roles (id, guild_id, self_assignable) VALUES ($1, $2, true) ON CONFLICT (id) DO UPDATE SET self_assignable=true", role.ID, ctx.Guild.ID) _, err = postgres.DB.Exec("INSERT INTO roles (id, guild_id, self_assignable) VALUES ($1, $2, true) ON CONFLICT (id) DO UPDATE SET self_assignable=true", role.ID, ctx.Guild.ID)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Error Updating Database", Message: "Error Updating Database",
Error: err, Error: err,
@ -50,7 +60,17 @@ func makeRoleSelfAssignable(ctx disgoman.Context, args []string) {
_, _ = ctx.Send(fmt.Sprintf("%s is now self assignable", role.Name)) _, _ = ctx.Send(fmt.Sprintf("%s is now self assignable", role.Name))
} }
func removeSelfAssignableRole(ctx disgoman.Context, args []string) { var RemoveSelfAssignableCommand = &disgoman.Command{
Name: "remove-self-assignable-role",
Aliases: []string{"removesar"},
Description: "Makes a role that was previously self assignable not so",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: removeSelfAssignableRoleCommandFunc,
}
func removeSelfAssignableRoleCommandFunc(ctx disgoman.Context, args []string) {
var roleString string var roleString string
var roleID string var roleID string
if len(args) > 0 { if len(args) > 0 {
@ -71,16 +91,16 @@ func removeSelfAssignableRole(ctx disgoman.Context, args []string) {
var err error var err error
var role *discordgo.Role var role *discordgo.Role
if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil { if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Can't find that Role.", Message: "Can't find that Role.",
Error: err, Error: err,
} }
return return
} }
_, err = utils.Database.Exec("INSERT INTO roles (id, guild_id, self_assignable) VALUES ($1, $2, false) ON CONFLICT (id) DO UPDATE SET self_assignable=false", role.ID, ctx.Guild.ID) _, err = postgres.DB.Exec("INSERT INTO roles (id, guild_id, self_assignable) VALUES ($1, $2, false) ON CONFLICT (id) DO UPDATE SET self_assignable=false", role.ID, ctx.Guild.ID)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Error Updating Database", Message: "Error Updating Database",
Error: err, Error: err,
@ -90,7 +110,17 @@ func removeSelfAssignableRole(ctx disgoman.Context, args []string) {
_, _ = ctx.Send(fmt.Sprintf("%s's self assignability has been removed.", role.Name)) _, _ = ctx.Send(fmt.Sprintf("%s's self assignability has been removed.", role.Name))
} }
func selfAssignRole(ctx disgoman.Context, args []string) { var SelfAssignRoleCommand = &disgoman.Command{
Name: "giverole",
Aliases: []string{"iwant", "givetome"},
Description: "Assigns a person the passed in role if it is self assignable",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: selfAssignRoleCommandFunc,
}
func selfAssignRoleCommandFunc(ctx disgoman.Context, args []string) {
var roleString string var roleString string
var roleID string var roleID string
if len(args) > 0 { if len(args) > 0 {
@ -111,7 +141,7 @@ func selfAssignRole(ctx disgoman.Context, args []string) {
var role *discordgo.Role var role *discordgo.Role
var err error var err error
if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil { if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Can't find that Role.", Message: "Can't find that Role.",
Error: err, Error: err,
@ -123,9 +153,9 @@ func selfAssignRole(ctx disgoman.Context, args []string) {
return return
} }
var selfAssignable bool var selfAssignable bool
err = utils.Database.QueryRow("SELECT self_assignable FROM roles where id=$1", role.ID).Scan(&selfAssignable) err = postgres.DB.QueryRow("SELECT self_assignable FROM roles where id=$1", role.ID).Scan(&selfAssignable)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Error Updating Database", Message: "Error Updating Database",
Error: err, Error: err,
@ -138,7 +168,7 @@ func selfAssignRole(ctx disgoman.Context, args []string) {
} }
err = ctx.Session.GuildMemberRoleAdd(ctx.Guild.ID, ctx.User.ID, role.ID) err = ctx.Session.GuildMemberRoleAdd(ctx.Guild.ID, ctx.User.ID, role.ID)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "There was a problem adding that role to you.", Message: "There was a problem adding that role to you.",
Error: err, Error: err,
@ -148,7 +178,17 @@ func selfAssignRole(ctx disgoman.Context, args []string) {
_, _ = ctx.Send(fmt.Sprintf("Congratulations! The %s role has been added to your... Ummm... Thing.", role.Name)) _, _ = ctx.Send(fmt.Sprintf("Congratulations! The %s role has been added to your... Ummm... Thing.", role.Name))
} }
func unAssignRole(ctx disgoman.Context, args []string) { var UnAssignRoleCommand = &disgoman.Command{
Name: "removerole",
Aliases: []string{"idon'twant"},
Description: "Removes a role from a person if the role is self assignable",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: unAssignRoleCommandFunc,
}
func unAssignRoleCommandFunc(ctx disgoman.Context, args []string) {
var roleString string var roleString string
var roleID string var roleID string
if len(args) > 0 { if len(args) > 0 {
@ -169,7 +209,7 @@ func unAssignRole(ctx disgoman.Context, args []string) {
var role *discordgo.Role var role *discordgo.Role
var err error var err error
if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil { if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Can't find that Role.", Message: "Can't find that Role.",
Error: err, Error: err,
@ -181,9 +221,9 @@ func unAssignRole(ctx disgoman.Context, args []string) {
return return
} }
var selfAssignable bool var selfAssignable bool
err = utils.Database.QueryRow("SELECT self_assignable FROM roles where id=$1", role.ID).Scan(&selfAssignable) err = postgres.DB.QueryRow("SELECT self_assignable FROM roles where id=$1", role.ID).Scan(&selfAssignable)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Error Updating Database", Message: "Error Updating Database",
Error: err, Error: err,
@ -196,7 +236,7 @@ func unAssignRole(ctx disgoman.Context, args []string) {
} }
err = ctx.Session.GuildMemberRoleRemove(ctx.Guild.ID, ctx.User.ID, role.ID) err = ctx.Session.GuildMemberRoleRemove(ctx.Guild.ID, ctx.User.ID, role.ID)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "There was a problem removing that role from you.", Message: "There was a problem removing that role from you.",
Error: err, Error: err,

@ -1,4 +1,4 @@
package exts package tags
import ( import (
"errors" "errors"
@ -7,20 +7,31 @@ import (
"strings" "strings"
"github.com/dustinpianalto/disgoman" "github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/goff/utils" "github.com/dustinpianalto/goff/internal/postgres"
) )
func addTagCommand(ctx disgoman.Context, input []string) { var AddTagCommand = &disgoman.Command{
Name: "addtag",
Aliases: nil,
Description: "Add a tag",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
SanitizeEveryone: true,
Invoke: addTagCommandFunc,
}
func addTagCommandFunc(ctx disgoman.Context, input []string) {
if len(input) >= 1 { if len(input) >= 1 {
queryString := `SELECT tags.id, tags.tag, tags.content from tags queryString := `SELECT tags.id, tags.tag, tags.content from tags
WHERE tags.guild_id = $1 WHERE tags.guild_id = $1
AND tags.tag = $2;` AND tags.tag = $2;`
row := utils.Database.QueryRow(queryString, ctx.Guild.ID, input[0]) row := postgres.DB.QueryRow(queryString, ctx.Guild.ID, input[0])
var dest string var dest string
if err := row.Scan(&dest); err != nil { if err := row.Scan(&dest); err != nil {
tag := input[0] tag := input[0]
if tag == "" { if tag == "" {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "That is not a valid tag name", Message: "That is not a valid tag name",
Error: err, Error: err,
@ -28,7 +39,7 @@ func addTagCommand(ctx disgoman.Context, input []string) {
return return
} }
if len(input) <= 1 { if len(input) <= 1 {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "I got a name but no value", Message: "I got a name but no value",
Error: err, Error: err,
@ -37,7 +48,7 @@ func addTagCommand(ctx disgoman.Context, input []string) {
} }
value := strings.Join(input[1:], " ") value := strings.Join(input[1:], " ")
if value == "" { if value == "" {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "You have to include a content for the tag", Message: "You have to include a content for the tag",
Error: err, Error: err,
@ -45,9 +56,9 @@ func addTagCommand(ctx disgoman.Context, input []string) {
return return
} }
queryString = `INSERT INTO tags (tag, content, creator, guild_id) VALUES ($1, $2, $3, $4);` queryString = `INSERT INTO tags (tag, content, creator, guild_id) VALUES ($1, $2, $3, $4);`
_, err := utils.Database.Exec(queryString, tag, value, ctx.Message.Author.ID, ctx.Guild.ID) _, err := postgres.DB.Exec(queryString, tag, value, ctx.Message.Author.ID, ctx.Guild.ID)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "", Message: "",
Error: err, Error: err,
@ -57,7 +68,7 @@ func addTagCommand(ctx disgoman.Context, input []string) {
ctx.Send(fmt.Sprintf("Tag %v added successfully.", tag)) ctx.Send(fmt.Sprintf("Tag %v added successfully.", tag))
return return
} else { } else {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "That tag already exists", Message: "That tag already exists",
Error: err, Error: err,
@ -66,7 +77,7 @@ func addTagCommand(ctx disgoman.Context, input []string) {
} }
} else { } else {
ctx.Send("You need to tell me what tag you want to add...") ctx.Send("You need to tell me what tag you want to add...")
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "You need to tell me what tag you want to add...", Message: "You need to tell me what tag you want to add...",
Error: errors.New("nothing to do"), Error: errors.New("nothing to do"),
@ -75,14 +86,24 @@ func addTagCommand(ctx disgoman.Context, input []string) {
} }
} }
func tagCommand(ctx disgoman.Context, args []string) { var TagCommand = &disgoman.Command{
Name: "tag",
Aliases: nil,
Description: "Get a tag",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: tagCommandFunc,
}
func tagCommandFunc(ctx disgoman.Context, args []string) {
if len(args) >= 1 { if len(args) >= 1 {
tagString := strings.Join(args, " ") tagString := strings.Join(args, " ")
queryString := `SELECT tags.id, tags.tag, tags.content from tags queryString := `SELECT tags.id, tags.tag, tags.content from tags
WHERE tags.guild_id = $1;` WHERE tags.guild_id = $1;`
rows, err := utils.Database.Query(queryString, ctx.Guild.ID) rows, err := postgres.DB.Query(queryString, ctx.Guild.ID)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "", Message: "",
Error: err, Error: err,
@ -96,14 +117,14 @@ func tagCommand(ctx disgoman.Context, args []string) {
content string content string
) )
if err := rows.Scan(&id, &tag, &content); err != nil { if err := rows.Scan(&id, &tag, &content); err != nil {
log.Fatal(err) log.Println(err)
} }
if tagString == tag { if tagString == tag {
ctx.Send(content) ctx.Send(content)
return return
} }
} }
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: fmt.Sprintf("Tag %v not found", args[0]), Message: fmt.Sprintf("Tag %v not found", args[0]),
Error: err, Error: err,
@ -112,7 +133,7 @@ func tagCommand(ctx disgoman.Context, args []string) {
} }
} else { } else {
ctx.Send("I need a tag to fetch...") ctx.Send("I need a tag to fetch...")
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "I need a tag to fetch...", Message: "I need a tag to fetch...",
Error: errors.New("nothing to do"), Error: errors.New("nothing to do"),

@ -1,10 +1,12 @@
package utils package tasks
import ( import (
"fmt" "fmt"
"github.com/bwmarrin/discordgo"
"log" "log"
"time" "time"
"github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/goff/internal/postgres"
) )
type Task struct { type Task struct {
@ -20,7 +22,7 @@ type Task struct {
func processTask(task *Task, s *discordgo.Session) { func processTask(task *Task, s *discordgo.Session) {
query := "SELECT completed, processing from tasks where id = $1" query := "SELECT completed, processing from tasks where id = $1"
res, err := Database.Query(query, task.ID) res, err := postgres.DB.Query(query, task.ID)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return return
@ -38,8 +40,8 @@ func processTask(task *Task, s *discordgo.Session) {
} }
closeQuery := "Update tasks set completed = true where id = $1" closeQuery := "Update tasks set completed = true where id = $1"
processQuery := "UPDATE tasks SET processing = true WHERE id = $1" processQuery := "UPDATE tasks SET processing = true WHERE id = $1"
defer Database.Exec(closeQuery, task.ID) defer postgres.DB.Exec(closeQuery, task.ID)
_, err = Database.Exec(processQuery, task.ID) _, err = postgres.DB.Exec(processQuery, task.ID)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return return
@ -85,7 +87,7 @@ func processTask(task *Task, s *discordgo.Session) {
} }
} }
processQuery = "UPDATE tasks SET processing = false WHERE id = $1" processQuery = "UPDATE tasks SET processing = false WHERE id = $1"
_, err = Database.Exec(processQuery, task.ID) _, err = postgres.DB.Exec(processQuery, task.ID)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
@ -95,7 +97,7 @@ func processTask(task *Task, s *discordgo.Session) {
func getTasksToRun() []Task { func getTasksToRun() []Task {
query := "SELECT id, type, content, guild_id, channel_id, user_id, creation_time, trigger_time " + query := "SELECT id, type, content, guild_id, channel_id, user_id, creation_time, trigger_time " +
"from tasks where completed is false and processing is false and trigger_time < $1" "from tasks where completed is false and processing is false and trigger_time < $1"
res, err := Database.Query(query, time.Now()) res, err := postgres.DB.Query(query, time.Now())
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }

@ -1,4 +1,4 @@
package exts package tasks
import ( import (
"errors" "errors"
@ -7,13 +7,23 @@ import (
"time" "time"
"github.com/dustinpianalto/disgoman" "github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/goff/utils" "github.com/dustinpianalto/goff/internal/postgres"
"github.com/olebedev/when" "github.com/olebedev/when"
"github.com/olebedev/when/rules/common" "github.com/olebedev/when/rules/common"
"github.com/olebedev/when/rules/en" "github.com/olebedev/when/rules/en"
) )
func addReminderCommand(ctx disgoman.Context, args []string) { var AddReminderCommand = &disgoman.Command{
Name: "remind",
Aliases: nil,
Description: "Remind me at a later time",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: addReminderFunc,
}
func addReminderFunc(ctx disgoman.Context, args []string) {
w := when.New(nil) w := when.New(nil)
w.Add(en.All...) w.Add(en.All...)
w.Add(common.All...) w.Add(common.All...)
@ -21,7 +31,7 @@ func addReminderCommand(ctx disgoman.Context, args []string) {
text := strings.Join(args, " ") text := strings.Join(args, " ")
r, err := w.Parse(text, time.Now()) r, err := w.Parse(text, time.Now())
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Error parsing time", Message: "Error parsing time",
Error: err, Error: err,
@ -29,7 +39,7 @@ func addReminderCommand(ctx disgoman.Context, args []string) {
return return
} }
if r == nil { if r == nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "You need to include a valid time", Message: "You need to include a valid time",
Error: errors.New("no time found"), Error: errors.New("no time found"),
@ -39,9 +49,9 @@ func addReminderCommand(ctx disgoman.Context, args []string) {
content := strings.Replace(text, r.Text+" ", "", 1) content := strings.Replace(text, r.Text+" ", "", 1)
query := "INSERT INTO tasks (type, content, guild_id, channel_id, user_id, trigger_time) " + query := "INSERT INTO tasks (type, content, guild_id, channel_id, user_id, trigger_time) " +
"VALUES ('Reminder', $1, $2, $3, $4, $5)" "VALUES ('Reminder', $1, $2, $3, $4, $5)"
_, err = utils.Database.Exec(query, content, ctx.Guild.ID, ctx.Channel.ID, ctx.User.ID, r.Time) _, err = postgres.DB.Exec(query, content, ctx.Guild.ID, ctx.Channel.ID, ctx.User.ID, r.Time)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Error adding task to database", Message: "Error adding task to database",
Error: err, Error: err,

@ -0,0 +1,73 @@
package user_management
import (
"log"
"github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/goff"
"github.com/dustinpianalto/goff/internal/services"
)
func OnGuildMemberAdd(s *discordgo.Session, member *discordgo.GuildMemberAdd) {
defer func() {
if r := recover(); r != nil {
log.Println("Recovered from panic in OnGuildMemberAdd", r)
}
}()
user, err := services.UserService.User(member.User.ID)
if err != nil {
log.Println("Error getting user from database: ", err)
user = &goff.User{
ID: member.User.ID,
Banned: false,
Logging: true,
IsActive: true,
IsStaff: false,
IsAdmin: false,
}
err := services.UserService.CreateUser(user)
if err != nil {
log.Println("Error adding user to database: ", err)
}
}
if !user.IsActive {
user.IsActive = true
err = services.UserService.UpdateUser(user)
if err != nil {
log.Println("Error marking user as active: ", err)
}
}
err = services.UserService.AddUserToGuild(user, &goff.Guild{ID: member.GuildID})
if err != nil {
log.Println("Error adding user to guild: ", err)
}
}
func OnGuildMemberRemove(s *discordgo.Session, member *discordgo.GuildMemberRemove) {
defer func() {
if r := recover(); r != nil {
log.Println("Recovered from panic in OnGuildMemberRemove: ", r)
}
}()
user, err := services.UserService.User(member.User.ID)
if err != nil {
log.Println("Error getting user from database: ", err)
return
}
err = services.UserService.RemoveUserFromGuild(user, &goff.Guild{ID: member.GuildID})
if err != nil {
log.Println("Error removing user from guild: ", err)
}
for i, g := range user.Guilds {
if g == member.GuildID {
user.Guilds[len(user.Guilds)-1], user.Guilds[i] = user.Guilds[i], user.Guilds[len(user.Guilds)-1]
user.Guilds = user.Guilds[:len(user.Guilds)-1]
}
}
if len(user.Guilds) == 0 {
err = services.UserService.MarkUserInactive(user)
if err != nil {
log.Println("Error marking user as inactive: ", err)
}
}
}

@ -1,4 +1,4 @@
package events package user_management
import ( import (
"fmt" "fmt"
@ -7,7 +7,8 @@ import (
"time" "time"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/goff/utils" "github.com/dustinpianalto/goff/internal/discord_utils"
"github.com/dustinpianalto/goff/internal/postgres"
) )
func OnGuildMemberAddLogging(s *discordgo.Session, member *discordgo.GuildMemberAdd) { func OnGuildMemberAddLogging(s *discordgo.Session, member *discordgo.GuildMemberAdd) {
@ -17,7 +18,7 @@ func OnGuildMemberAddLogging(s *discordgo.Session, member *discordgo.GuildMember
} }
}() }()
var channelID string var channelID string
row := utils.Database.QueryRow("SELECT logging_channel FROM guilds where id=$1", member.GuildID) row := postgres.DB.QueryRow("SELECT logging_channel FROM guilds where id=$1", member.GuildID)
err := row.Scan(&channelID) err := row.Scan(&channelID)
if err != nil || channelID == "" { if err != nil || channelID == "" {
return return
@ -40,11 +41,11 @@ func OnGuildMemberAddLogging(s *discordgo.Session, member *discordgo.GuildMember
} }
int64ID, _ := strconv.ParseInt(member.User.ID, 10, 64) int64ID, _ := strconv.ParseInt(member.User.ID, 10, 64)
snow := utils.ParseSnowflake(int64ID) snow := discord_utils.ParseSnowflake(int64ID)
field := &discordgo.MessageEmbedField{ field := &discordgo.MessageEmbedField{
Name: "User was created:", Name: "User was created:",
Value: utils.ParseDateString(snow.CreationTime), Value: discord_utils.ParseDateString(snow.CreationTime),
Inline: false, Inline: false,
} }
@ -73,7 +74,7 @@ func OnGuildMemberRemoveLogging(s *discordgo.Session, member *discordgo.GuildMem
}() }()
timeNow := time.Now() timeNow := time.Now()
var channelID string var channelID string
row := utils.Database.QueryRow("SELECT logging_channel FROM guilds where id=$1", member.GuildID) row := postgres.DB.QueryRow("SELECT logging_channel FROM guilds where id=$1", member.GuildID)
err := row.Scan(&channelID) err := row.Scan(&channelID)
if err != nil || channelID == "" { if err != nil || channelID == "" {
return return
@ -103,7 +104,7 @@ func OnGuildMemberRemoveLogging(s *discordgo.Session, member *discordgo.GuildMem
for _, log := range al.AuditLogEntries { for _, log := range al.AuditLogEntries {
if log.TargetID == member.User.ID { if log.TargetID == member.User.ID {
int64ID, _ := strconv.ParseInt(log.ID, 10, 64) int64ID, _ := strconv.ParseInt(log.ID, 10, 64)
logSnow := utils.ParseSnowflake(int64ID) logSnow := discord_utils.ParseSnowflake(int64ID)
if timeNow.Sub(logSnow.CreationTime).Seconds() <= 10 { if timeNow.Sub(logSnow.CreationTime).Seconds() <= 10 {
user, err := s.User(log.UserID) user, err := s.User(log.UserID)
if err == nil { if err == nil {
@ -133,3 +134,34 @@ func OnGuildMemberRemoveLogging(s *discordgo.Session, member *discordgo.GuildMem
} }
s.ChannelMessageSendEmbed(channelID, embed) s.ChannelMessageSendEmbed(channelID, embed)
} }
func AddMemberToDatabase(s *discordgo.Session, m *discordgo.GuildMemberAdd) {
defer func() {
if r := recover(); r != nil {
log.Println("Recovered from panic in AddMemberToDatabase", r)
}
}()
queryString := `INSERT INTO users (id, banned, logging, is_active, is_staff, is_admin)
VALUES ($1, false, false, true, false, false)`
_, err := postgres.DB.Exec(queryString, m.User.ID)
if err != nil {
log.Println(fmt.Errorf("error inserting %s into database: %w", m.User.ID, err))
return
}
log.Printf("New User: %s\n", m.User.ID)
}
func MarkMemberInactive(s *discordgo.Session, m *discordgo.GuildMemberRemove) {
defer func() {
if r := recover(); r != nil {
log.Println("Recovered from panic in MarkMemberInactive")
}
}()
queryString := `UPDATE users SET is_active = false WHERE id = $1`
_, err := postgres.DB.Exec(queryString, m.User.ID)
if err != nil {
log.Println(fmt.Errorf("error marking %s as inactive: %w", m.User.ID, err))
return
}
log.Println("User left: %s")
}

@ -1,4 +1,4 @@
package exts package user_management
import ( import (
"errors" "errors"
@ -8,10 +8,20 @@ import (
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/disgoman" "github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/goff/utils" "github.com/dustinpianalto/goff/internal/exts/logging"
) )
func kickUserCommand(ctx disgoman.Context, args []string) { var KickUserCommand = &disgoman.Command{
Name: "kick",
Aliases: nil,
Description: "Kicks the given user with the given reason",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionKickMembers,
Invoke: kickUserFunc,
}
func kickUserFunc(ctx disgoman.Context, args []string) {
var member *discordgo.Member var member *discordgo.Member
var err error var err error
if len(ctx.Message.Mentions) > 0 { if len(ctx.Message.Mentions) > 0 {
@ -26,7 +36,7 @@ func kickUserCommand(ctx disgoman.Context, args []string) {
err = errors.New("that is not a valid id") err = errors.New("that is not a valid id")
} }
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Couldn't get that member", Message: "Couldn't get that member",
Error: err, Error: err,
@ -35,7 +45,7 @@ func kickUserCommand(ctx disgoman.Context, args []string) {
} }
if higher, _ := disgoman.HasHigherRole(ctx.Session, ctx.Guild.ID, ctx.Message.Author.ID, member.User.ID); !higher { if higher, _ := disgoman.HasHigherRole(ctx.Session, ctx.Guild.ID, ctx.Message.Author.ID, member.User.ID); !higher {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "You must have a higher role than the person you are trying to kick", Message: "You must have a higher role than the person you are trying to kick",
Error: errors.New("need higher role"), Error: errors.New("need higher role"),
@ -44,7 +54,7 @@ func kickUserCommand(ctx disgoman.Context, args []string) {
} }
if higher, _ := disgoman.HasHigherRole(ctx.Session, ctx.Guild.ID, ctx.Session.State.User.ID, member.User.ID); !higher { if higher, _ := disgoman.HasHigherRole(ctx.Session, ctx.Guild.ID, ctx.Session.State.User.ID, member.User.ID); !higher {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "I don't have a high enough role to kick that person", Message: "I don't have a high enough role to kick that person",
Error: errors.New("need higher role"), Error: errors.New("need higher role"),
@ -62,7 +72,7 @@ func kickUserCommand(ctx disgoman.Context, args []string) {
err = ctx.Session.GuildMemberDeleteWithReason(ctx.Guild.ID, member.User.ID, auditReason) err = ctx.Session.GuildMemberDeleteWithReason(ctx.Guild.ID, member.User.ID, auditReason)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: fmt.Sprintf("Something went wrong kicking %v", member.User.Username), Message: fmt.Sprintf("Something went wrong kicking %v", member.User.Username),
Error: err, Error: err,
@ -70,7 +80,7 @@ func kickUserCommand(ctx disgoman.Context, args []string) {
return return
} }
event := &utils.LogEvent{ event := &logging.LogEvent{
Embed: discordgo.MessageEmbed{ Embed: discordgo.MessageEmbed{
Title: "User Kicked", Title: "User Kicked",
Description: fmt.Sprintf( Description: fmt.Sprintf(
@ -85,11 +95,21 @@ func kickUserCommand(ctx disgoman.Context, args []string) {
GuildID: ctx.Guild.ID, GuildID: ctx.Guild.ID,
Session: ctx.Session, Session: ctx.Session,
} }
utils.LoggingChannel <- event logging.LoggingChannel <- event
_, _ = ctx.Send(fmt.Sprintf("User %v#%v has been kicked.", member.User.Username, member.User.Discriminator)) _, _ = ctx.Send(fmt.Sprintf("User %v#%v has been kicked.", member.User.Username, member.User.Discriminator))
} }
func banUserCommand(ctx disgoman.Context, args []string) { var BanUserCommand = &disgoman.Command{
Name: "ban",
Aliases: []string{"ban-no-delete"},
Description: "Bans the given user with the given reason",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionBanMembers,
Invoke: banUserFunc,
}
func banUserFunc(ctx disgoman.Context, args []string) {
var user *discordgo.User var user *discordgo.User
var err error var err error
if len(ctx.Message.Mentions) > 0 { if len(ctx.Message.Mentions) > 0 {
@ -104,7 +124,7 @@ func banUserCommand(ctx disgoman.Context, args []string) {
err = errors.New("that is not a valid id") err = errors.New("that is not a valid id")
} }
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Couldn't get that user", Message: "Couldn't get that user",
Error: err, Error: err,
@ -114,7 +134,7 @@ func banUserCommand(ctx disgoman.Context, args []string) {
if higher, err := disgoman.HasHigherRole(ctx.Session, ctx.Guild.ID, ctx.Message.Author.ID, user.ID); err != nil { if higher, err := disgoman.HasHigherRole(ctx.Session, ctx.Guild.ID, ctx.Message.Author.ID, user.ID); err != nil {
if err.Error() == "can't find caller member" { if err.Error() == "can't find caller member" {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Who are you?", Message: "Who are you?",
Error: err, Error: err,
@ -122,7 +142,7 @@ func banUserCommand(ctx disgoman.Context, args []string) {
return return
} }
} else if !higher { } else if !higher {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "You must have a higher role than the person you are trying to ban", Message: "You must have a higher role than the person you are trying to ban",
Error: errors.New("need higher role"), Error: errors.New("need higher role"),
@ -132,7 +152,7 @@ func banUserCommand(ctx disgoman.Context, args []string) {
if higher, err := disgoman.HasHigherRole(ctx.Session, ctx.Guild.ID, ctx.Session.State.User.ID, user.ID); err != nil { if higher, err := disgoman.HasHigherRole(ctx.Session, ctx.Guild.ID, ctx.Session.State.User.ID, user.ID); err != nil {
if err.Error() == "can't find caller member" { if err.Error() == "can't find caller member" {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Who am I?", Message: "Who am I?",
Error: err, Error: err,
@ -140,7 +160,7 @@ func banUserCommand(ctx disgoman.Context, args []string) {
return return
} }
} else if !higher { } else if !higher {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "I don't have a high enough role to ban that person", Message: "I don't have a high enough role to ban that person",
Error: errors.New("need higher role"), Error: errors.New("need higher role"),
@ -162,7 +182,7 @@ func banUserCommand(ctx disgoman.Context, args []string) {
err = ctx.Session.GuildBanCreateWithReason(ctx.Guild.ID, user.ID, auditReason, days) err = ctx.Session.GuildBanCreateWithReason(ctx.Guild.ID, user.ID, auditReason, days)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: fmt.Sprintf("Something went wrong banning %v", user.Username), Message: fmt.Sprintf("Something went wrong banning %v", user.Username),
Error: err, Error: err,
@ -170,7 +190,7 @@ func banUserCommand(ctx disgoman.Context, args []string) {
return return
} }
event := &utils.LogEvent{ event := &logging.LogEvent{
Embed: discordgo.MessageEmbed{ Embed: discordgo.MessageEmbed{
Title: "User Banned", Title: "User Banned",
Description: fmt.Sprintf( Description: fmt.Sprintf(
@ -185,11 +205,21 @@ func banUserCommand(ctx disgoman.Context, args []string) {
GuildID: ctx.Guild.ID, GuildID: ctx.Guild.ID,
Session: ctx.Session, Session: ctx.Session,
} }
utils.LoggingChannel <- event logging.LoggingChannel <- event
_, _ = ctx.Send(fmt.Sprintf("User %v#%v has been banned.", user.Username, user.Discriminator)) _, _ = ctx.Send(fmt.Sprintf("User %v#%v has been banned.", user.Username, user.Discriminator))
} }
func unbanUserCommand(ctx disgoman.Context, args []string) { var UnbanUserCommand = &disgoman.Command{
Name: "unban",
Aliases: nil,
Description: "Unbans the given user",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionBanMembers,
Invoke: unbanUserFunc,
}
func unbanUserFunc(ctx disgoman.Context, args []string) {
var user *discordgo.User var user *discordgo.User
var err error var err error
if len(ctx.Message.Mentions) > 0 { if len(ctx.Message.Mentions) > 0 {
@ -204,7 +234,7 @@ func unbanUserCommand(ctx disgoman.Context, args []string) {
err = errors.New("that is not a valid id") err = errors.New("that is not a valid id")
} }
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Couldn't get that user", Message: "Couldn't get that user",
Error: err, Error: err,
@ -214,7 +244,7 @@ func unbanUserCommand(ctx disgoman.Context, args []string) {
bans, err := ctx.Session.GuildBans(ctx.Guild.ID) bans, err := ctx.Session.GuildBans(ctx.Guild.ID)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Error processing current bans", Message: "Error processing current bans",
Error: err, Error: err,
@ -225,14 +255,14 @@ func unbanUserCommand(ctx disgoman.Context, args []string) {
if ban.User.ID == user.ID { if ban.User.ID == user.ID {
err = ctx.Session.GuildBanDelete(ctx.Guild.ID, user.ID) err = ctx.Session.GuildBanDelete(ctx.Guild.ID, user.ID)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: fmt.Sprintf("Something went wrong unbanning %v", user.Username), Message: fmt.Sprintf("Something went wrong unbanning %v", user.Username),
Error: err, Error: err,
} }
return return
} }
event := &utils.LogEvent{ event := &logging.LogEvent{
Embed: discordgo.MessageEmbed{ Embed: discordgo.MessageEmbed{
Title: "User Banned", Title: "User Banned",
Description: fmt.Sprintf( Description: fmt.Sprintf(
@ -247,7 +277,7 @@ func unbanUserCommand(ctx disgoman.Context, args []string) {
GuildID: ctx.Guild.ID, GuildID: ctx.Guild.ID,
Session: ctx.Session, Session: ctx.Session,
} }
utils.LoggingChannel <- event logging.LoggingChannel <- event
_, _ = ctx.Send(fmt.Sprintf("User %v#%v has been unbanned.", user.Username, user.Discriminator)) _, _ = ctx.Send(fmt.Sprintf("User %v#%v has been unbanned.", user.Username, user.Discriminator))
return return
} }

@ -1,4 +1,4 @@
package exts package utils
import ( import (
"fmt" "fmt"
@ -9,16 +9,26 @@ import (
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/disgoman" "github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/goff/utils" "github.com/dustinpianalto/goff/internal/discord_utils"
) )
func pingCommand(ctx disgoman.Context, _ []string) { var PingCommand = &disgoman.Command{
Name: "ping",
Aliases: []string{" "},
Description: "Check the bot's ping",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: pingCommandFunc,
}
func pingCommandFunc(ctx disgoman.Context, _ []string) {
timeBefore := time.Now() timeBefore := time.Now()
msg, _ := ctx.Send("Pong!") msg, _ := ctx.Send("Pong!")
took := time.Now().Sub(timeBefore) took := time.Now().Sub(timeBefore)
_, err := ctx.Session.ChannelMessageEdit(ctx.Message.ChannelID, msg.ID, fmt.Sprintf("Pong!\nPing Took **%s**", took.String())) _, err := ctx.Session.ChannelMessageEdit(ctx.Message.ChannelID, msg.ID, fmt.Sprintf("Pong!\nPing Took **%s**", took.String()))
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Ping Failed", Message: "Ping Failed",
Error: err, Error: err,
@ -26,7 +36,17 @@ func pingCommand(ctx disgoman.Context, _ []string) {
} }
} }
func inviteCommand(ctx disgoman.Context, args []string) { var InviteCommand = &disgoman.Command{
Name: "invite",
Aliases: nil,
Description: "Get the invite link for this bot or others",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: inviteCommandFunc,
}
func inviteCommandFunc(ctx disgoman.Context, args []string) {
var ids []string var ids []string
if len(args) == 0 { if len(args) == 0 {
ids = []string{ctx.Session.State.User.ID} ids = []string{ctx.Session.State.User.ID}
@ -39,7 +59,7 @@ func inviteCommand(ctx disgoman.Context, args []string) {
url := fmt.Sprintf("<https://discordapp.com/oauth2/authorize?client_id=%v&scope=bot>", id) url := fmt.Sprintf("<https://discordapp.com/oauth2/authorize?client_id=%v&scope=bot>", id)
_, err := ctx.Send(url) _, err := ctx.Send(url)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Couldn't send the invite link.", Message: "Couldn't send the invite link.",
Error: err, Error: err,
@ -48,7 +68,17 @@ func inviteCommand(ctx disgoman.Context, args []string) {
} }
} }
func gitCommand(ctx disgoman.Context, _ []string) { var GitCommand = &disgoman.Command{
Name: "git",
Aliases: nil,
Description: "Show my github link",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: gitCommandFunc,
}
func gitCommandFunc(ctx disgoman.Context, _ []string) {
embed := &discordgo.MessageEmbed{ embed := &discordgo.MessageEmbed{
Title: "Hi there, My code is on Github", Title: "Hi there, My code is on Github",
Color: 0, Color: 0,
@ -56,7 +86,7 @@ func gitCommand(ctx disgoman.Context, _ []string) {
} }
_, err := ctx.Session.ChannelMessageSendEmbed(ctx.Channel.ID, embed) _, err := ctx.Session.ChannelMessageSendEmbed(ctx.Channel.ID, embed)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Git failed", Message: "Git failed",
Error: err, Error: err,
@ -64,13 +94,24 @@ func gitCommand(ctx disgoman.Context, _ []string) {
} }
} }
func sayCommand(ctx disgoman.Context, args []string) { var SayCommand = &disgoman.Command{
Name: "say",
Aliases: nil,
Description: "Repeat a message",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
SanitizeEveryone: true,
Invoke: sayCommandFunc,
}
func sayCommandFunc(ctx disgoman.Context, args []string) {
resp := strings.Join(args, " ") resp := strings.Join(args, " ")
resp = strings.ReplaceAll(resp, "@everyone", "@\ufff0everyone") resp = strings.ReplaceAll(resp, "@everyone", "@\ufff0everyone")
resp = strings.ReplaceAll(resp, "@here", "@\ufff0here") resp = strings.ReplaceAll(resp, "@here", "@\ufff0here")
_, err := ctx.Session.ChannelMessageSend(ctx.Message.ChannelID, resp) _, err := ctx.Session.ChannelMessageSend(ctx.Message.ChannelID, resp)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Say Failed", Message: "Say Failed",
Error: err, Error: err,
@ -78,7 +119,17 @@ func sayCommand(ctx disgoman.Context, args []string) {
} }
} }
func userCommand(ctx disgoman.Context, args []string) { var UserCommand = &disgoman.Command{
Name: "user",
Aliases: nil,
Description: "Get user info",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: userCommandFunc,
}
func userCommandFunc(ctx disgoman.Context, args []string) {
var member *discordgo.Member var member *discordgo.Member
if len(args) == 0 { if len(args) == 0 {
member, _ = ctx.Session.GuildMember(ctx.Guild.ID, ctx.Message.Author.ID) member, _ = ctx.Session.GuildMember(ctx.Guild.ID, ctx.Message.Author.ID)
@ -90,7 +141,7 @@ func userCommand(ctx disgoman.Context, args []string) {
member, err = ctx.Session.GuildMember(ctx.Guild.ID, args[0]) member, err = ctx.Session.GuildMember(ctx.Guild.ID, args[0])
} }
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Couldn't get that member", Message: "Couldn't get that member",
Error: err, Error: err,
@ -135,15 +186,15 @@ func userCommand(ctx disgoman.Context, args []string) {
guildJoinTime, _ := member.JoinedAt.Parse() guildJoinTime, _ := member.JoinedAt.Parse()
guildJoinedField := &discordgo.MessageEmbedField{ guildJoinedField := &discordgo.MessageEmbedField{
Name: "Joined Guild:", Name: "Joined Guild:",
Value: utils.ParseDateString(guildJoinTime), Value: discord_utils.ParseDateString(guildJoinTime),
Inline: false, Inline: false,
} }
int64ID, _ := strconv.ParseInt(member.User.ID, 10, 64) int64ID, _ := strconv.ParseInt(member.User.ID, 10, 64)
s := utils.ParseSnowflake(int64ID) s := discord_utils.ParseSnowflake(int64ID)
discordJoinedField := &discordgo.MessageEmbedField{ discordJoinedField := &discordgo.MessageEmbedField{
Name: "Joined Discord:", Name: "Joined Discord:",
Value: utils.ParseDateString(s.CreationTime), Value: discord_utils.ParseDateString(s.CreationTime),
Inline: false, Inline: false,
} }
@ -160,7 +211,7 @@ func userCommand(ctx disgoman.Context, args []string) {
} }
_, err := ctx.Session.ChannelMessageSendEmbed(ctx.Channel.ID, embed) _, err := ctx.Session.ChannelMessageSendEmbed(ctx.Channel.ID, embed)
if err != nil { if err != nil {
ctx.ErrorChannel <- disgoman.CommandError{ ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx, Context: ctx,
Message: "Couldn't send the user embed", Message: "Couldn't send the user embed",
Error: err, Error: err,

@ -1,4 +1,4 @@
package utils package postgres
import ( import (
"database/sql" "database/sql"
@ -9,7 +9,7 @@ import (
) )
var ( var (
Database *sql.DB DB *sql.DB
) )
func ConnectDatabase(dbConnString string) { func ConnectDatabase(dbConnString string) {
@ -19,11 +19,14 @@ func ConnectDatabase(dbConnString string) {
} else { } else {
fmt.Println("Database Connected.") fmt.Println("Database Connected.")
} }
Database = db db.SetMaxOpenConns(75) // The RDS instance has a max of 75 open connections
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(300)
DB = db
} }
func InitializeDatabase() { func InitializeDatabase() {
_, err := Database.Query("CREATE TABLE IF NOT EXISTS users(" + _, err := DB.Query("CREATE TABLE IF NOT EXISTS users(" +
"id varchar(30) primary key," + "id varchar(30) primary key," +
"banned bool not null default false," + "banned bool not null default false," +
"logging bool not null default true," + "logging bool not null default true," +
@ -35,7 +38,7 @@ func InitializeDatabase() {
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("CREATE TABLE IF NOT EXISTS guilds(" + _, err = DB.Query("CREATE TABLE IF NOT EXISTS guilds(" +
"id varchar(30) primary key," + "id varchar(30) primary key," +
"welcome_message varchar(1000) NOT NULL DEFAULT ''," + "welcome_message varchar(1000) NOT NULL DEFAULT ''," +
"goodbye_message varchar(1000) NOT NULL DEFAULT ''," + "goodbye_message varchar(1000) NOT NULL DEFAULT ''," +
@ -45,14 +48,14 @@ func InitializeDatabase() {
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("CREATE TABLE IF NOT EXISTS prefixes(" + _, err = DB.Query("CREATE TABLE IF NOT EXISTS prefixes(" +
"id serial primary key," + "id serial primary key," +
"prefix varchar(10) not null unique default 'Go.'" + "prefix varchar(10) not null unique default 'Go.'" +
")") ")")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("CREATE TABLE IF NOT EXISTS tags(" + _, err = DB.Query("CREATE TABLE IF NOT EXISTS tags(" +
"id serial primary key," + "id serial primary key," +
"tag varchar(100) not null unique," + "tag varchar(100) not null unique," +
"content varchar(1000) not null," + "content varchar(1000) not null," +
@ -63,21 +66,21 @@ func InitializeDatabase() {
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("CREATE TABLE IF NOT EXISTS x_users_guilds(" + _, err = DB.Query("CREATE TABLE IF NOT EXISTS x_users_guilds(" +
"guild_id varchar(30) not null references guilds(id)," + "guild_id varchar(30) not null references guilds(id)," +
"user_id varchar(30) not null references users(id)" + "user_id varchar(30) not null references users(id)" +
")") ")")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("CREATE TABLE IF NOT EXISTS x_guilds_prefixes(" + _, err = DB.Query("CREATE TABLE IF NOT EXISTS x_guilds_prefixes(" +
"guild_id varchar(30) not null references guilds(id)," + "guild_id varchar(30) not null references guilds(id)," +
"prefix_id int not null references prefixes(id)" + "prefix_id int not null references prefixes(id)" +
")") ")")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("CREATE TABLE IF NOT EXISTS tasks(" + _, err = DB.Query("CREATE TABLE IF NOT EXISTS tasks(" +
"id serial primary key," + "id serial primary key," +
"type varchar(10) not null," + "type varchar(10) not null," +
"content text not null," + "content text not null," +
@ -91,14 +94,14 @@ func InitializeDatabase() {
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query(`CREATE TABLE IF NOT EXISTS postfixes( _, err = DB.Query(`CREATE TABLE IF NOT EXISTS postfixes(
id serial primary key, id serial primary key,
name varchar(100) not null, name varchar(100) not null,
time timestamp not null default NOW())`) time timestamp not null default NOW())`)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
_, err = Database.Exec(`CREATE TABLE IF NOT EXISTS puzzles( _, err = DB.Exec(`CREATE TABLE IF NOT EXISTS puzzles(
id serial primary key, id serial primary key,
text text not null, text text not null,
time timestamp not null time timestamp not null
@ -106,7 +109,7 @@ func InitializeDatabase() {
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
_, err = Database.Exec(`CREATE TABLE IF NOT EXISTS x_guilds_puzzles( _, err = DB.Exec(`CREATE TABLE IF NOT EXISTS x_guilds_puzzles(
id serial primary key, id serial primary key,
guild_id varchar(30) not null references guilds(id), guild_id varchar(30) not null references guilds(id),
puzzle_id int not null references puzzles(id), puzzle_id int not null references puzzles(id),
@ -116,37 +119,37 @@ func InitializeDatabase() {
} }
func LoadTestData() { func LoadTestData() {
_, err := Database.Query("INSERT INTO users (id, banned, logging, steam_id, is_active, is_staff, is_admin) values " + _, err := DB.Query("INSERT INTO users (id, banned, logging, steam_id, is_active, is_staff, is_admin) values " +
"('351794468870946827', false, true, '76561198024193239', true, true, true)," + "('351794468870946827', false, true, '76561198024193239', true, true, true)," +
"('692908139506434065', false, true, '', true, false, false)," + "('692908139506434065', false, true, '', true, false, false)," +
"('396588996706304010', false, true, '', true, true, false)") "('396588996706304010', false, true, '', true, true, false)")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("INSERT INTO guilds (id, welcome_message, goodbye_message) VALUES " + _, err = DB.Query("INSERT INTO guilds (id, welcome_message, goodbye_message) VALUES " +
"('265828729970753537', 'Hey there is someone new here.', 'Well fine then... Just leave without saying goodbye')") "('265828729970753537', 'Hey there is someone new here.', 'Well fine then... Just leave without saying goodbye')")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("INSERT INTO prefixes (prefix) VALUES ('Godev.'), ('godev.'), ('godev,')") _, err = DB.Query("INSERT INTO prefixes (prefix) VALUES ('Godev.'), ('godev.'), ('godev,')")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("INSERT INTO x_users_guilds (guild_id, user_id) VALUES " + _, err = DB.Query("INSERT INTO x_users_guilds (guild_id, user_id) VALUES " +
"('265828729970753537', '351794468870946827')," + "('265828729970753537', '351794468870946827')," +
"('265828729970753537', '692908139506434065')," + "('265828729970753537', '692908139506434065')," +
"('265828729970753537', '396588996706304010')") "('265828729970753537', '396588996706304010')")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("INSERT INTO x_guilds_prefixes (guild_id, prefix_id) VALUES " + _, err = DB.Query("INSERT INTO x_guilds_prefixes (guild_id, prefix_id) VALUES " +
"('265828729970753537', 1)," + "('265828729970753537', 1)," +
"('265828729970753537', 2)," + "('265828729970753537', 2)," +
"('265828729970753537', 3)") "('265828729970753537', 3)")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
_, err = Database.Query("INSERT INTO tags (tag, content, creator, guild_id) VALUES " + _, err = DB.Query("INSERT INTO tags (tag, content, creator, guild_id) VALUES " +
"('test', 'This is a test of the tag system', '351794468870946827', '265828729970753537')") "('test', 'This is a test of the tag system', '351794468870946827', '265828729970753537')")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)

@ -0,0 +1,127 @@
package postgres
import (
"database/sql"
"log"
"github.com/dustinpianalto/goff"
)
type GuildService struct {
DB *sql.DB
}
func (s *GuildService) Guild(id string) (*goff.Guild, error) {
var g goff.Guild
queryString := `SELECT id, welcome_message, goodbye_message,
logging_channel, welcome_channel, puzzle_channel, puzzle_role
FROM guilds
WHERE id = $1`
row := s.DB.QueryRow(queryString, id)
err := row.Scan(
&g.ID,
&g.WelcomeMessage,
&g.GoodbyeMessage,
&g.LoggingChannel,
&g.WelcomeChannel,
&g.PuzzleChannel,
&g.PuzzleRole,
)
if err != nil {
return nil, err
}
var prefixes []string
queryString = `SELECT p.prefix
FROM prefixes p, x_guilds_prefixes xgp
WHERE p.id = xgp.prefix_id AND xgp.guild_id = $1`
rows, err := s.DB.Query(queryString, id)
if err == nil {
for rows.Next() {
var prefix string
err = rows.Scan(&prefix)
if err != nil {
continue
}
prefixes = append(prefixes, prefix)
}
}
g.Prefixes = prefixes
return &g, nil
}
func (s *GuildService) CreateGuild(g *goff.Guild) error {
queryString := `INSERT INTO guilds (id,
welcome_message,
goodbye_message,
logging_channel,
welcome_channel,
puzzle_channel,
puzzle_role)
VALUES ($1, $2, $3, $4, $5, $6, $7)`
_, err := s.DB.Exec(queryString,
g.ID,
g.WelcomeMessage,
g.GoodbyeMessage,
g.LoggingChannel,
g.WelcomeChannel,
g.PuzzleChannel,
g.PuzzleRole,
)
return err
}
func (s *GuildService) DeleteGuild(g *goff.Guild) error {
queryString := `DELETE CASCADE FROM guilds WHERE id = $1`
_, err := s.DB.Exec(queryString, g.ID)
return err
}
func (s *GuildService) GuildUsers(g *goff.Guild) ([]*goff.User, error) {
var users []*goff.User
queryString := `SELECT u.id, u.banned, u.logging, u.steam_id, u.is_active, u.is_staff, u.is_admin
FROM users u, x_users_guilds xug
WHERE xug.guild_id = $1
AND xug.user_id = u.id`
rows, err := s.DB.Query(queryString, g.ID)
if err != nil {
return nil, err
}
for rows.Next() {
var user goff.User
err := rows.Scan(&user.ID,
&user.Banned,
&user.Logging,
&user.SteamID,
&user.IsActive,
&user.IsStaff,
&user.IsAdmin,
)
if err != nil {
log.Println(err)
continue
}
users = append(users, &user)
}
return users, nil
}
func (s *GuildService) UpdateGuild(g *goff.Guild) error {
queryString := `UPDATE guilds SET
welcome_message = $1,
goodbye_message = $2,
logging_channel = $3,
welcome_channel = $4,
puzzle_channel = $5,
puzzle_role = $6
WHERE id = $7`
_, err := s.DB.Exec(queryString,
g.WelcomeMessage,
g.GoodbyeMessage,
g.LoggingChannel,
g.WelcomeChannel,
g.PuzzleChannel,
g.PuzzleRole,
g.ID,
)
return err
}

@ -1,4 +1,4 @@
package utils package postgres
import "log" import "log"
@ -28,12 +28,16 @@ var postfixes = []postfix{
Name: "3_Update_Guild_Add_Puzzle_Role", Name: "3_Update_Guild_Add_Puzzle_Role",
Invoke: updateGuildsAddPuzzleRole, Invoke: updateGuildsAddPuzzleRole,
}, },
postfix{
Name: "4_Add_Multi_Column_Unique_XUsersGuilds",
Invoke: addMultiColumnUniqueXUsersGuilds,
},
} }
func RunPostfixes() { func RunPostfixes() {
for _, postfix := range postfixes { for _, postfix := range postfixes {
queryString := "SELECT * from postfixes where name = $1" queryString := "SELECT * from postfixes where name = $1"
rows, err := Database.Query(queryString, postfix.Name) rows, err := DB.Query(queryString, postfix.Name)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
continue continue
@ -45,7 +49,7 @@ func RunPostfixes() {
if err != nil { if err != nil {
continue continue
} }
_, err = Database.Exec("INSERT INTO postfixes (name) VALUES ($1)", postfix.Name) _, err = DB.Exec("INSERT INTO postfixes (name) VALUES ($1)", postfix.Name)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
continue continue
@ -63,7 +67,7 @@ func updateGuildForPuzzle(revert bool) error {
queryString = `ALTER TABLE guilds queryString = `ALTER TABLE guilds
DROP COLUMN puzzleChat` DROP COLUMN puzzleChat`
} }
_, err := Database.Exec(queryString) _, err := DB.Exec(queryString)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return err return err
@ -80,7 +84,7 @@ func updateXGuildPrefixesToAddID(revert bool) error {
queryString = `ALTER TABLE x_guilds_prefixes queryString = `ALTER TABLE x_guilds_prefixes
DROP COLUMN id` DROP COLUMN id`
} }
_, err := Database.Exec(queryString) _, err := DB.Exec(queryString)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return err return err
@ -97,7 +101,7 @@ func updateTagsContentLength(revert bool) error {
queryString = `ALTER TABLE tags queryString = `ALTER TABLE tags
ALTER COLUMN content TYPE varchar(1000)` ALTER COLUMN content TYPE varchar(1000)`
} }
_, err := Database.Exec(queryString) _, err := DB.Exec(queryString)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return err return err
@ -118,7 +122,7 @@ func addTableRoles(revert bool) error {
} else { } else {
queryString = `DROP TABLE roles` queryString = `DROP TABLE roles`
} }
_, err := Database.Exec(queryString) _, err := DB.Exec(queryString)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return err return err
@ -135,7 +139,23 @@ func updateGuildsAddPuzzleRole(revert bool) error {
queryString = `ALTER TABLE guilds queryString = `ALTER TABLE guilds
DROP COLUMN puzzle_role` DROP COLUMN puzzle_role`
} }
_, err := Database.Exec(queryString) _, err := DB.Exec(queryString)
if err != nil {
log.Println(err)
return err
}
return nil
}
func addMultiColumnUniqueXUsersGuilds(revert bool) error {
var queryString string
if !revert {
queryString = `ALTER TABLE x_users_guilds
ADD CONSTRAINT u_user_guild UNIQUE(user_id, guild_id)`
} else {
queryString = `ALTER TABLE DROP CONSTRAINT u_user_guild IF EXISTS`
}
_, err := DB.Exec(queryString)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return err return err

@ -0,0 +1,84 @@
package postgres
import (
"database/sql"
"github.com/dustinpianalto/goff"
)
type UserService struct {
DB *sql.DB
}
func (s *UserService) User(id string) (*goff.User, error) {
var u goff.User
queryString := `SELECT id, banned, logging, steam_id, is_active, is_staff, is_admin
FROM users WHERE id=$1`
row := s.DB.QueryRow(queryString, id)
if err := row.Scan(&u.ID, &u.Banned, &u.Logging, &u.SteamID, &u.IsActive, &u.IsStaff, &u.IsAdmin); err != nil {
return nil, err
}
var guilds []string
queryString = `SELECT guild_id from x_users_guilds WHERE user_id=$1`
rows, err := s.DB.Query(queryString, id)
if err != nil {
return nil, err
}
for rows.Next() {
var guildID string
err = rows.Scan(&guildID)
if err != nil {
return nil, err
}
guilds = append(guilds, guildID)
}
u.Guilds = guilds
return &u, nil
}
func (s *UserService) CreateUser(u *goff.User) error {
queryString := `INSERT INTO users (id, banned, logging, steam_id, is_active, is_staff, is_admin)
VALUES ($1, $2, $3, $4, $5, $6, $7)`
_, err := s.DB.Exec(queryString, u.ID, u.Banned, u.Logging, u.SteamID, u.IsActive, u.IsStaff, u.IsAdmin)
return err
}
func (s *UserService) DeleteUser(u *goff.User) error {
queryString := `DELETE CASCADE FROM x_users_guilds WHERE user_id = $1; DELETE FROM users WHERE id = $1`
_, err := s.DB.Exec(queryString, u.ID)
return err
}
func (s *UserService) MarkUserInactive(u *goff.User) error {
queryString := `UPDATE users SET is_active = false WHERE id = $1`
_, err := s.DB.Exec(queryString, u.ID)
if err == nil {
u.IsActive = false
}
return err
}
func (s *UserService) AddUserToGuild(u *goff.User, g *goff.Guild) error {
queryString := `INSERT INTO x_users_guilds (user_id, guild_id) VALUES ($1, $2)`
_, err := s.DB.Exec(queryString, u.ID, g.ID)
return err
}
func (s *UserService) RemoveUserFromGuild(u *goff.User, g *goff.Guild) error {
queryString := `DELETE FROM x_users_guilds WHERE user_id = $1 AND guild_id = $2`
_, err := s.DB.Exec(queryString, u.ID, g.ID)
return err
}
func (s *UserService) UpdateUser(u *goff.User) error {
queryString := `UPDATE users SET
banned = $1,
logging = $2,
steam_id = $3,
is_active = $4,
is_staff = $5,
is_admin = $6
WHERE id = $7`
_, err := s.DB.Exec(queryString, u.Banned, u.Logging, u.SteamID, u.IsActive, u.IsStaff, u.IsAdmin)
return err
}

@ -0,0 +1,11 @@
package services
import "github.com/dustinpianalto/goff"
var UserService goff.UserService
var GuildService goff.GuildService
func InitalizeServices(us goff.UserService, gs goff.GuildService) {
UserService = us
GuildService = gs
}

@ -1,4 +1,4 @@
package utils package email
import ( import (
"io" "io"
@ -9,6 +9,7 @@ import (
"time" "time"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/goff/pkg/puzzles"
imap "github.com/emersion/go-imap" imap "github.com/emersion/go-imap"
"github.com/emersion/go-imap/client" "github.com/emersion/go-imap/client"
"github.com/emersion/go-message/mail" "github.com/emersion/go-message/mail"
@ -117,7 +118,7 @@ func processEmail(r io.Reader, dg *discordgo.Session, wg *sync.WaitGroup) {
if addressIn(from, puzzleAddress) && if addressIn(from, puzzleAddress) &&
strings.Contains(subject, "Daily Coding Problem:") { strings.Contains(subject, "Daily Coding Problem:") {
log.Println("Processing Puzzle") log.Println("Processing Puzzle")
ProcessPuzzleEmail(mr, dg) puzzles.ProcessPuzzleEmail(mr, dg)
} }
} }

@ -1,4 +1,4 @@
package utils package puzzles
import ( import (
"io" "io"
@ -8,6 +8,8 @@ import (
"time" "time"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/goff"
"github.com/dustinpianalto/goff/internal/postgres"
"github.com/emersion/go-message/mail" "github.com/emersion/go-message/mail"
) )
@ -48,14 +50,14 @@ func ProcessPuzzleEmail(mr *mail.Reader, dg *discordgo.Session) {
Text: "Daily Coding Problem", Text: "Daily Coding Problem",
}, },
} }
var guilds []Guild var guilds []goff.Guild
queryString := `SELECT id, puzzle_channel, puzzle_role from guilds` queryString := `SELECT id, puzzle_channel, puzzle_role from guilds`
rows, err := Database.Query(queryString) rows, err := postgres.DB.Query(queryString)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
for rows.Next() { for rows.Next() {
var guild Guild var guild goff.Guild
err := rows.Scan(&guild.ID, &guild.PuzzleChannel, &guild.PuzzleRole) err := rows.Scan(&guild.ID, &guild.PuzzleChannel, &guild.PuzzleRole)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
@ -65,7 +67,7 @@ func ProcessPuzzleEmail(mr *mail.Reader, dg *discordgo.Session) {
} }
var puzzleID int64 var puzzleID int64
queryString = "INSERT INTO puzzles (text, time) VALUES ($1, $2) RETURNING id" queryString = "INSERT INTO puzzles (text, time) VALUES ($1, $2) RETURNING id"
err = Database.QueryRow(queryString, puzzle, date).Scan(&puzzleID) err = postgres.DB.QueryRow(queryString, puzzle, date).Scan(&puzzleID)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return return
@ -91,7 +93,7 @@ func ProcessPuzzleEmail(mr *mail.Reader, dg *discordgo.Session) {
log.Println(err) log.Println(err)
} }
queryString = "INSERT INTO x_guilds_puzzles (guild_id, puzzle_id, message_id) VALUES ($1, $2, $3)" queryString = "INSERT INTO x_guilds_puzzles (guild_id, puzzle_id, message_id) VALUES ($1, $2, $3)"
_, err = Database.Exec(queryString, g.ID, puzzleID, m.ID) _, err = postgres.DB.Exec(queryString, g.ID, puzzleID, m.ID)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
continue continue

@ -1,4 +0,0 @@
#!/bin/bash
/usr/local/bin/docker-compose build || exit
/usr/local/bin/docker-compose up -d

@ -0,0 +1,22 @@
package goff
type User struct {
ID string
Banned bool
Logging bool
SteamID string
IsActive bool
IsStaff bool
IsAdmin bool
Guilds []string
}
type UserService interface {
User(id string) (*User, error)
CreateUser(u *User) error
DeleteUser(u *User) error
MarkUserInactive(u *User) error
AddUserToGuild(u *User, g *Guild) error
RemoveUserFromGuild(u *User, g *Guild) error
UpdateUser(u *User) error
}

@ -1,156 +0,0 @@
package utils
import (
"fmt"
"strconv"
"strings"
)
type Operator struct {
Token string
Precedence int
Association string
}
func (o Operator) HasHigherPrecedence(t Operator) bool {
return o.Precedence < t.Precedence // lower number is higher precedence
}
func (o Operator) HasEqualPrecedence(t Operator) bool {
return o.Precedence == t.Precedence
}
func (o Operator) IsLeftAssociative() bool {
return o.Association == "left"
}
var operators = map[string]Operator{
"+": Operator{
Token: "+",
Precedence: 4,
Association: "left",
},
"-": Operator{
Token: "-",
Precedence: 4,
Association: "left",
},
"*": Operator{
Token: "*",
Precedence: 3,
Association: "left",
},
"/": Operator{
Token: "/",
Precedence: 3,
Association: "left",
},
"%": Operator{
Token: "%",
Precedence: 3,
Association: "left",
},
"(": Operator{
Token: "(",
Precedence: 1,
Association: "left",
},
")": Operator{
Token: ")",
Precedence: 1,
Association: "left",
},
}
type Stack []Operator
func (s *Stack) IsEmpty() bool {
return len(*s) == 0
}
func (s *Stack) Push(op Operator) {
*s = append(*s, op)
}
func (s *Stack) Pop() (Operator, bool) {
if s.IsEmpty() {
return Operator{}, false
}
index := len(*s) - 1
element := (*s)[index]
*s = (*s)[:index]
return element, true
}
func (s *Stack) Top() Operator {
if s.IsEmpty() {
return Operator{}
}
return (*s)[len(*s)-1]
}
func GenerateRPN(tokens []string) (string, error) {
output := ""
s := Stack{}
for _, token := range tokens {
err := processToken(token, &s, &output)
if err != nil {
return "", err
}
}
for !s.IsEmpty() {
ele, _ := s.Pop()
output += " " + ele.Token
}
return strings.TrimSpace(output), nil
}
func processToken(t string, s *Stack, o *string) error {
if _, err := strconv.Atoi(t); err == nil {
*o += " " + t
return nil
} else if op, ok := operators[t]; ok {
if op.Token == "(" {
s.Push(op)
} else if op.Token == ")" {
if s.IsEmpty() {
return fmt.Errorf("mismatched parentheses")
}
for s.Top().Token != "(" {
if ele, ok := s.Pop(); ok {
*o += " " + ele.Token
} else {
return fmt.Errorf("mismatched parentheses")
}
if s.IsEmpty() {
break
}
}
s.Pop() // Pop and discard the (
} else if !s.IsEmpty() {
for {
if (s.Top().HasHigherPrecedence(op) ||
(s.Top().HasEqualPrecedence(op) &&
op.IsLeftAssociative())) &&
s.Top().Token != "(" {
if ele, ok := s.Pop(); ok {
*o += " " + ele.Token
if s.IsEmpty() {
break
}
continue
} else {
break
}
}
break
}
s.Push(op)
} else {
s.Push(op)
}
return nil
}
return fmt.Errorf("invalid character %s", t)
}

@ -1,95 +0,0 @@
package utils
import (
"errors"
"fmt"
"math"
"strconv"
)
type FStack []float64
func (s *FStack) IsEmpty() bool {
return len(*s) == 0
}
func (s *FStack) Push(op float64) {
*s = append(*s, op)
}
func (s *FStack) Pop() (float64, bool) {
if s.IsEmpty() {
return 0, false
}
index := len(*s) - 1
element := (*s)[index]
*s = (*s)[:index]
return element, true
}
func (s *FStack) PopTwo() (float64, float64, bool) {
if s.IsEmpty() || len(*s) < 2 {
return 0, 0, false
}
index := len(*s) - 1
b := (*s)[index]
a := (*s)[index-1]
*s = (*s)[:index-1]
return a, b, true
}
func (s *FStack) Top() float64 {
if s.IsEmpty() {
return 0
}
return (*s)[len(*s)-1]
}
func ParseRPN(args []string) (float64, error) {
s := FStack{}
for _, token := range args {
switch token {
case "+":
if a, b, ok := s.PopTwo(); ok {
s.Push(a + b)
} else {
return 0, fmt.Errorf("not enough operands on stack for +: %v", s)
}
case "-":
if a, b, ok := s.PopTwo(); ok {
s.Push(a - b)
} else {
return 0, fmt.Errorf("not enough operands on stack for -: %v", s)
}
case "*":
if a, b, ok := s.PopTwo(); ok {
s.Push(a * b)
} else {
return 0, fmt.Errorf("not enough operands on stack for *: %v", s)
}
case "/":
if a, b, ok := s.PopTwo(); ok {
s.Push(a / b)
} else {
return 0, fmt.Errorf("not enough operands on stack for /: %v", s)
}
case "%":
if a, b, ok := s.PopTwo(); ok {
s.Push(math.Mod(a, b))
} else {
return 0, fmt.Errorf("not enough operands on stack for %: %v", s)
}
default:
f, err := strconv.ParseFloat(token, 64)
if err != nil {
return 0, err
}
s.Push(f)
}
}
if res, ok := s.Pop(); ok {
return res, nil
}
return 0, errors.New("no result")
}

@ -1,13 +0,0 @@
package utils
import "database/sql"
type Guild struct {
ID string
WelcomeMessage string
GoodbyeMessage string
LoggingChannel string
WelcomeChannel string
PuzzleChannel string
PuzzleRole sql.NullString
}
Loading…
Cancel
Save