Compare commits

..
80 Commits
Author SHA1 Message Date
Dustin Pianalto a21e884bee Fix bug getting messages from db
CI / build (push) Has been cancelled
2021-02-22 22:12:07 -09:00
Dustin Pianalto faf64a8bf9 Add message to end of list with count
CI / build (push) Has been cancelled
2021-02-22 22:03:06 -09:00
Dustin Pianalto 2abe574977 Update database schema to not allow null previous_content
CI / build (push) Has been cancelled
2021-02-22 21:56:18 -09:00
Dustin Pianalto 04c32955c7 Update database schema to not allow null previous_content
CI / build (push) Has been cancelled
2021-02-22 21:29:41 -09:00
Dustin Pianalto 1f70318d26 Update database schema to not allow null previous_content
CI / build (push) Has been cancelled
2021-02-22 21:24:55 -09:00
Dustin Pianalto 47ed519376 Update database schema to not allow null previous_content
CI / build (push) Has been cancelled
2021-02-22 21:16:28 -09:00
Dustin Pianalto 22912c7367 Fix broken SQL query
CI / build (push) Has been cancelled
2021-02-22 20:13:29 -09:00
Dustin Pianalto 6b15540d4e Add close and list commands
CI / build (push) Has been cancelled
2021-02-22 19:59:39 -09:00
Dustin Pianalto e526d27f4a update actions
CI / build (push) Has been cancelled
2021-02-22 19:51:04 -09:00
Dustin Pianalto 68c06a7356 Add request close and list commands
CI / build (push) Has been cancelled
2021-02-22 19:37:38 -09:00
Dustin Pianalto c8277cce42 Merge branch 'development' of github.com:dustinpianalto/Geeksbot into development 2021-02-22 14:05:09 -09:00
Dustin Pianalto 3069e24e8d Move db and services to pkg 2021-02-22 14:04:51 -09:00
Dustin Pianalto 472f23cc2b start close command 2021-02-07 11:27:33 -09:00
Dustin Pianalto 6d920e615d Add sar commands
CI / build (push) Has been cancelled
2021-01-30 22:52:25 -09:00
Dustin Pianalto 0b8b57a884 Add sar commands
CI / build (push) Has been cancelled
2021-01-30 22:42:14 -09:00
Dustin Pianalto 9382798997 Add sar commands
CI / build (push) Has been cancelled
2021-01-30 22:31:22 -09:00
Dustin Pianalto 24448c79f5 Add sar commands
CI / build (push) Has been cancelled
2021-01-30 22:17:01 -09:00
Dustin Pianalto 71aac148e0 remove mod/admin role command
CI / build (push) Has been cancelled
2021-01-26 00:08:20 -09:00
Dustin Pianalto 132bf94332 remove mod/admin role command
CI / build (push) Has been cancelled
2021-01-25 23:53:32 -09:00
Dustin Pianalto 964be05c48 remove mod/admin role command
CI / build (push) Has been cancelled
2021-01-25 23:49:58 -09:00
Dustin Pianalto 4895294969 fix role commands
CI / build (push) Has been cancelled
2021-01-25 23:09:21 -09:00
Dustin Pianalto 9d0d1ddd56 fix role commands
CI / build (push) Has been cancelled
2021-01-25 23:04:43 -09:00
Dustin Pianalto a587a64bd9 fix role commands
CI / build (push) Has been cancelled
2021-01-25 23:01:02 -09:00
Dustin Pianalto 53276a1442 add admin role command
CI / build (push) Has been cancelled
2021-01-25 22:41:51 -09:00
Dustin Pianalto cdbeac195f add moderator role command
CI / build (push) Has been cancelled
2021-01-25 22:21:56 -09:00
Dustin Pianalto 8256b596ff add moderator role command
CI / build (push) Has been cancelled
2021-01-25 21:52:12 -09:00
Dustin Pianalto 9e1702fa4b fix create request command
CI / build (push) Has been cancelled
2021-01-25 02:31:36 -09:00
Dustin Pianalto b6f90b61c5 fix create request command
CI / build (push) Has been cancelled
2021-01-25 02:27:56 -09:00
Dustin Pianalto 764ceb79ec fix create request sql query
CI / build (push) Has been cancelled
2021-01-25 02:20:11 -09:00
Dustin Pianalto e89805bf8e fix create channel sql query
CI / build (push) Has been cancelled
2021-01-25 02:11:28 -09:00
Dustin Pianalto cb7c487b42 fix create channel sql query
CI / build (push) Has been cancelled
2021-01-25 02:05:13 -09:00
Dustin Pianalto e1ea9cab1f fix create channel sql query
CI / build (push) Has been cancelled
2021-01-25 01:59:57 -09:00
Dustin Pianalto a6dc6f5e56 fix get user sql query
CI / build (push) Has been cancelled
2021-01-25 01:52:14 -09:00
Dustin Pianalto 203d1bbf69 fix get user sql query
CI / build (push) Has been cancelled
2021-01-25 01:43:31 -09:00
Dustin Pianalto c504f7b165 fix get user sql query
CI / build (push) Has been cancelled
2021-01-25 01:38:22 -09:00
Dustin Pianalto 34564140f5 add request command
CI / build (push) Has been cancelled
2021-01-25 01:33:46 -09:00
Dustin Pianalto e3ccc56dba add request command
CI / build (push) Has been cancelled
2021-01-25 01:21:49 -09:00
Dustin Pianalto e19f987c4e add request command
CI / build (push) Has been cancelled
2021-01-24 22:57:55 -09:00
Dustin Pianalto 552664268b use custom prefixes
CI / build (push) Has been cancelled
2021-01-24 01:11:22 -09:00
Dustin Pianalto 414757188e remove duplicate prefixes
CI / build (push) Has been cancelled
2021-01-24 01:05:16 -09:00
Dustin Pianalto 888d356b67 debug removing prefix
CI / build (push) Has been cancelled
2021-01-24 00:57:00 -09:00
Dustin Pianalto c776b25899 debug removing prefix
CI / build (push) Has been cancelled
2021-01-24 00:53:04 -09:00
Dustin Pianalto 81f6e23487 Fix array in guild service
CI / build (push) Has been cancelled
2021-01-24 00:46:41 -09:00
Dustin Pianalto 6cf574b22d Add prefix commands
CI / build (push) Has been cancelled
2021-01-24 00:40:02 -09:00
Dustin Pianalto 623df1d55a Add prefix commands
CI / build (push) Has been cancelled
2021-01-24 00:26:34 -09:00
Dustin Pianalto 489d96594c Add prefix commands
CI / build (push) Has been cancelled
2021-01-24 00:24:07 -09:00
Dustin Pianalto 580eea3dfa Fix nullability of columns 2021-01-23 20:10:48 -09:00
Dustin Pianalto 7a8e7bf213 use nullable string in user
CI / build (push) Has been cancelled
2021-01-23 16:05:02 -09:00
Dustin Pianalto 96e8388562 fix bug in user database
CI / build (push) Has been cancelled
2021-01-23 15:10:04 -09:00
Dustin Pianalto 6369f37ce5 fix bug in user service
CI / build (push) Has been cancelled
2021-01-23 15:03:15 -09:00
Dustin Pianalto ab2d51c582 fix bug in user service
CI / build (push) Has been cancelled
2021-01-23 14:59:35 -09:00
Dustin Pianalto 5400d6acd9 fix bug in user service
CI / build (push) Has been cancelled
2021-01-23 14:48:59 -09:00
Dustin Pianalto 74edd574b3 fix bug in user service
CI / build (push) Has been cancelled
2021-01-23 14:46:25 -09:00
Dustin Pianalto 266cde6468 fix bug in running migrations
CI / build (push) Has been cancelled
2021-01-23 04:27:34 -09:00
Dustin Pianalto 8b646731ee change test command name
CI / build (push) Has been cancelled
2021-01-23 04:20:17 -09:00
Dustin Pianalto c54f8450b1 fix sql typo
CI / build (push) Has been cancelled
2021-01-23 04:14:29 -09:00
Dustin Pianalto 12f5b43f35 rework services and add test command
CI / build (push) Has been cancelled
2021-01-23 03:53:34 -09:00
Dustin Pianalto 9724f77c8e Initialize services 2021-01-23 03:11:12 -09:00
Dustin Pianalto 780613d7b9 initial database crud 2021-01-23 01:25:06 -09:00
Dustin Pianalto 94dcb738bc debug errors
CI / build (push) Has been cancelled
2021-01-21 00:19:52 -09:00
Dustin Pianalto 84e2bdea5e debug errors
CI / build (push) Has been cancelled
2021-01-20 23:58:25 -09:00
Dustin Pianalto 63e6212a0b debug errors
CI / build (push) Has been cancelled
2021-01-20 23:28:15 -09:00
Dustin Pianalto cbd899ff8c debug errors
CI / build (push) Has been cancelled
2021-01-20 23:22:23 -09:00
Dustin Pianalto c9ac3235db Fix syntax errors
CI / build (push) Has been cancelled
2021-01-20 23:18:30 -09:00
Dustin Pianalto 4dc9a6e846 Test adding migration files to container
CI / build (push) Has been cancelled
2021-01-20 23:04:17 -09:00
Dustin Pianalto 662db7cd9d Test adding migration files to container 2021-01-20 23:04:14 -09:00
Dustin Pianalto 57072010dc Test adding migration files to container
CI / build (push) Has been cancelled
2021-01-20 22:44:17 -09:00
Dustin Pianalto ab8db644cb Test adding migration files to container
CI / build (push) Has been cancelled
2021-01-20 22:40:15 -09:00
Dustin Pianalto 1d3a218e2d Check error when running migrations
CI / build (push) Has been cancelled
2021-01-20 22:37:04 -09:00
Dustin Pianalto 080a417eff Check error when running migrations
CI / build (push) Has been cancelled
2021-01-20 22:21:01 -09:00
Dustin Pianalto 4e1fa43e8e Fix typo in workflow
CI / build (push) Has been cancelled
2021-01-20 22:13:59 -09:00
Dustin Pianalto eed0ca1865 Fix typo in workflow
CI / build (push) Has been cancelled
2021-01-20 22:11:22 -09:00
Dustin Pianalto 2e7b1d2531 Fix typo in workflow
CI / build (push) Has been cancelled
2021-01-20 22:10:39 -09:00
Dustin Pianalto cd0fb03605 Fix typo in workflow
CI / build (push) Has been cancelled
2021-01-20 22:08:22 -09:00
Dustin Pianalto cc8fff4e3d Fix typo in workflow
CI / build (push) Has been cancelled
2021-01-20 21:59:24 -09:00
Dustin Pianalto 3e98bd145a Fix typo in workflow
CI / build (push) Has been cancelled
2021-01-20 21:53:56 -09:00
Dustin Pianalto 36a3cd26ba Fix typo in workflow
CI / build (push) Has been cancelled
2021-01-20 21:50:13 -09:00
Dustin Pianalto d3bbef1d7f Fix typo in workflow
CI / build (push) Has been cancelled
2021-01-20 21:40:29 -09:00
Dustin Pianalto bec8f37fa5 Fix typo in workflow
CI / build (push) Has been cancelled
2021-01-20 21:37:58 -09:00
Dustin Pianalto a097deefac Fix typo in workflow
CI / build (push) Has been cancelled
2021-01-20 21:36:43 -09:00
41 changed files with 2430 additions and 159 deletions
+10 -13
View File
@@ -21,18 +21,13 @@ jobs:
id: get_version
uses: battila7/get-version-action@v2.0.0
- name: Setup Golang 1.15
uses: actions/setup-go@v1
with:
go-version: 1.15
- name: Install go-bindata
uses: cedrickring/golang-action@1.6.0
with:
args: go get -u github.com/go-bindata/go-bindata/...
- name: Build migrations
run: go-bindata -pkg migrations -o $GITHUB_WORKSPACE/internal/database/migrations/bindata.go $GITHUB_WORKSPACE/internal/database/migrations/
- name: Install go-bindata and build migrations
env:
GOPATH: /home/runner/work/Geeksbot/
run: |
go get -u github.com/go-bindata/go-bindata/...
/home/runner/work/Geeksbot/bin/go-bindata -pkg migrations -prefix $GITHUB_WORKSPACE/pkg/database/migrations/ -o $GITHUB_WORKSPACE/pkg/database/migrations/bindata.go $GITHUB_WORKSPACE/pkg/database/migrations/
head $GITHUB_WORKSPACE/pkg/database/migrations/bindata.go
- name: Build container image
env:
@@ -48,7 +43,9 @@ jobs:
run: doctl registry login --expiry-seconds 600
- name: Push image to DigitalOcean Container Registry
run: docker push registry.digitalocean.com/djpianalto/geeksbot
run: docker push registry.digitalocean.com/djpianalto/geeksbot:$IMAGE_TAG
env:
IMAGE_TAG: ${{ steps.get_version.outputs.version-without-v }}
- name: Update deployment file
run: TAG=${{ steps.get_version.outputs.version-without-v }} && sed -i 's|<IMAGE>|registry.digitalocean.com/djpianalto/geeksbot:'${TAG}'|' $GITHUB_WORKSPACE/deployment.yml
+2
View File
@@ -8,6 +8,7 @@ RUN go mod download
COPY . .
RUN go install github.com/dustinpianalto/geeksbot/...
RUN go get -u github.com/go-bindata/go-bindata/...
CMD [ "go", "run", "cmd/geeksbot/main.go"]
@@ -16,5 +17,6 @@ from alpine
WORKDIR /bin
COPY --from=dev /go/bin/geeksbot ./geeksbot
COPY --from=dev /go/bin/go-bindata ./go-bindata
CMD [ "geeksbot" ]
+6 -5
View File
@@ -9,9 +9,10 @@ type Channel struct {
}
type ChannelService interface {
Channel(id string) (*Channel, error)
CreateChannel(c *Channel) (*Channel, error)
DeleteChannel(c *Channel) error
GuildChannels(g *Guild) ([]*Channel, error)
UpdateChannel(c *Channel) (*Channel, error)
Channel(id string) (Channel, error)
CreateChannel(c Channel) (Channel, error)
DeleteChannel(c Channel) error
GuildChannels(g Guild) ([]Channel, error)
UpdateChannel(c Channel) (Channel, error)
GetOrCreateChannel(id string, guild_id string) (Channel, error)
}
+8 -19
View File
@@ -8,8 +8,9 @@ import (
"github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/geeksbot/internal/database"
"github.com/dustinpianalto/geeksbot/internal/exts"
"github.com/dustinpianalto/geeksbot/pkg/database"
"github.com/dustinpianalto/geeksbot/pkg/services"
)
func main() {
@@ -27,11 +28,7 @@ func main() {
}
database.ConnectDatabase(os.Getenv("DATABASE_URL"))
//postgres.InitializeDatabase()
//utils.LoadTestData()
//us := &postgres.UserService{DB: postgres.DB}
//gs := &postgres.GuildService{DB: postgres.DB}
services.InitializeServices()
owners := []string{
"351794468870946827",
@@ -49,18 +46,9 @@ func main() {
// 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 {
@@ -71,9 +59,6 @@ func main() {
// Start the Error handler in a goroutine
go ErrorHandler(manager.ErrorChannel)
// Start the Logging handler in a goroutine
//go logging.LoggingHandler(logging.LoggingChannel)
log.Println("The Bot is now running.")
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
@@ -87,7 +72,11 @@ func main() {
}
func getPrefixes(guildID string) []string {
return []string{"G.", "g."}
guild, err := services.GuildService.Guild(guildID)
if err != nil || len(guild.Prefixes) == 0 {
return []string{"G$", "g$"}
}
return guild.Prefixes
}
func ErrorHandler(ErrorChan chan disgoman.CommandError) {
+1
View File
@@ -9,4 +9,5 @@ require (
github.com/golang-migrate/migrate v3.5.4+incompatible // indirect
github.com/golang-migrate/migrate/v4 v4.14.1
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/lib/pq v1.8.0
)
+1
View File
@@ -294,6 +294,7 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+15 -11
View File
@@ -1,25 +1,29 @@
package geeksbot
import "database/sql"
type Guild struct {
ID string
NewPatronMessage string
NewPatronMessage sql.NullString
Prefixes []string
}
type Role struct {
ID string
RoleType int
RoleType string
Guild Guild
}
type GuildService interface {
Guild(id string) (*Guild, error)
CreateGuild(g *Guild) (*Guild, error)
DeleteGuild(g *Guild) error
UpdateGuild(g *Guild) (*Guild, error)
GuildRoles(g *Guild) ([]*Role, error)
CreateRole(r *Role) (*Role, error)
Role(id string) (*Role, error)
UpdateRole(r *Role) (*Role, error)
DeleteRole(r *Role) error
Guild(id string) (Guild, error)
CreateGuild(g Guild) (Guild, error)
DeleteGuild(g Guild) error
UpdateGuild(g Guild) (Guild, error)
GuildRoles(g Guild) ([]Role, error)
CreateRole(r Role) (Role, error)
Role(id string) (Role, error)
UpdateRole(r Role) (Role, error)
DeleteRole(r Role) error
GetOrCreateGuild(id string) (Guild, error)
CreateOrUpdateRole(r Role) (Role, error)
}
-44
View File
@@ -1,44 +0,0 @@
package database
import (
"database/sql"
"fmt"
"log"
"github.com/dustinpianalto/geeksbot/internal/database/migrations"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/postgres"
bindata "github.com/golang-migrate/migrate/v4/source/go_bindata"
)
var (
db *sql.DB
)
func ConnectDatabase(dbConnString string) {
s := bindata.Resource(migrations.AssetNames(),
func(name string) ([]byte, error) {
return migrations.Asset(name)
})
db, err := sql.Open("postgres", dbConnString)
if err != nil {
log.Fatal(fmt.Errorf("Can't connect to the database: %w", err))
}
log.Println("Database Connected.")
db.SetMaxOpenConns(75)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(300)
d, err := bindata.WithInstance(s)
if err != nil {
log.Fatal(fmt.Errorf("Cannot load migrations: %w", err))
}
instance, err := postgres.WithInstance(db, &postgres.Config{})
if err != nil {
log.Fatal(fmt.Errorf("Cannot create db driver: %w", err))
}
m, err := migrate.NewWithInstance("go-bindata", d, "postgres", instance)
if err != nil {
log.Fatal(fmt.Errorf("Cannot create migration instance: %w", err))
}
m.Up()
}
+49
View File
@@ -0,0 +1,49 @@
package discord_utils
import (
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/geeksbot"
"github.com/dustinpianalto/geeksbot/pkg/services"
)
func IsGuildMod(ctx disgoman.Context, user geeksbot.User) bool {
discordCloser, err := ctx.Session.GuildMember(ctx.Guild.ID, user.ID)
if err != nil {
return false
}
guildRoles, err := services.GuildService.GuildRoles(geeksbot.Guild{ID: ctx.Guild.ID})
if err != nil {
return false
}
for _, role := range guildRoles {
if role.RoleType == "moderator" {
for _, rID := range discordCloser.Roles {
if rID == role.ID {
return true
}
}
}
}
return false
}
func IsGuildAdmin(ctx disgoman.Context, user geeksbot.User) bool {
discordCloser, err := ctx.Session.GuildMember(ctx.Guild.ID, user.ID)
if err != nil {
return false
}
guildRoles, err := services.GuildService.GuildRoles(geeksbot.Guild{ID: ctx.Guild.ID})
if err != nil {
return false
}
for _, role := range guildRoles {
if role.RoleType == "admin" {
for _, rID := range discordCloser.Roles {
if rID == role.ID {
return true
}
}
}
}
return false
}
+11
View File
@@ -0,0 +1,11 @@
package discord_utils
import "github.com/dustinpianalto/disgoman"
func SendErrorMessage(ctx disgoman.Context, msg string, err error) {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: msg,
Error: err,
}
}
+109
View File
@@ -0,0 +1,109 @@
package guild
import (
"fmt"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/geeksbot"
"github.com/dustinpianalto/geeksbot/internal/discord_utils"
"github.com/dustinpianalto/geeksbot/internal/utils"
"github.com/dustinpianalto/geeksbot/pkg/services"
)
var AddPrefixCommand = &disgoman.Command{
Name: "addPrefix",
Aliases: []string{"ap"},
Description: "Add a prefix for use in this guild.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: addPrefixCommandFunc,
}
func addPrefixCommandFunc(ctx disgoman.Context, args []string) {
if len(args) == 0 {
discord_utils.SendErrorMessage(ctx, "Please include at least one prefix to add", nil)
return
}
guild, err := services.GuildService.Guild(ctx.Guild.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Guild not configured, adding new guild to the database", nil)
guild = geeksbot.Guild{
ID: ctx.Guild.ID,
Prefixes: args,
}
guild, err = services.GuildService.CreateGuild(guild)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error adding guild to database.", err)
return
}
} else {
guild.Prefixes = append(guild.Prefixes, args...)
guild.Prefixes = utils.RemoveDuplicateStrings(guild.Prefixes)
guild, err = services.GuildService.UpdateGuild(guild)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error adding prefixes to guild.", err)
return
}
}
_, err = ctx.Send(fmt.Sprintf("Prefixes Updates.\nThe Prefixes for this guild are currently %#v", guild.Prefixes))
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error sending update message", err)
}
}
var RemovePrefixCommand = &disgoman.Command{
Name: "removePrefix",
Aliases: []string{"rp"},
Description: "Remove a prefix so it can't be used in this guild",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: removePrefixCommandFunc,
}
func removePrefixCommandFunc(ctx disgoman.Context, args []string) {
if len(args) == 0 {
discord_utils.SendErrorMessage(ctx, "Please include at least one prefix to remove", nil)
return
}
guild, err := services.GuildService.Guild(ctx.Guild.ID)
var removed []string
if err != nil {
discord_utils.SendErrorMessage(ctx, "Guild not configured, adding new guild to the database", nil)
guild = geeksbot.Guild{
ID: ctx.Guild.ID,
Prefixes: []string{},
}
guild, err = services.GuildService.CreateGuild(guild)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error adding guild to database.", err)
return
}
} else {
for _, a := range args {
l := len(guild.Prefixes)
for i := 0; i < l; i++ {
if a == guild.Prefixes[i] {
guild.Prefixes = append(guild.Prefixes[:i], guild.Prefixes[i+1:]...)
l--
i--
removed = append(removed, a)
}
}
}
removed = utils.RemoveDuplicateStrings(removed)
guild.Prefixes = utils.RemoveDuplicateStrings(guild.Prefixes)
guild, err = services.GuildService.UpdateGuild(guild)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error removing prefixes from guild.", err)
return
}
}
_, err = ctx.Send(fmt.Sprintf("Prefixes Updates.\n"+
"The Prefixes for this guild are currently %#v\n"+
"Removed: %#v", guild.Prefixes, removed))
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error sending update message", err)
}
}
+404
View File
@@ -0,0 +1,404 @@
package guild
import (
"fmt"
"strconv"
"strings"
"github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/geeksbot"
"github.com/dustinpianalto/geeksbot/internal/discord_utils"
"github.com/dustinpianalto/geeksbot/internal/utils"
"github.com/dustinpianalto/geeksbot/pkg/services"
)
var AddModeratorRoleCommand = &disgoman.Command{
Name: "addMod",
Aliases: []string{"addModerator", "addModRole"},
Description: "Add a role which is allowed to run moderator commands",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: addModeratorRoleCommandFunc,
}
func addModeratorRoleCommandFunc(ctx disgoman.Context, args []string) {
var count int
added := make(map[string]bool)
guild, err := services.GuildService.GetOrCreateGuild(ctx.Guild.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Something went wrong getting the guild", err)
return
}
roles := append(args, ctx.Message.MentionRoles...)
if len(roles) > 0 {
for _, id := range roles {
if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") {
continue
}
if _, ok := added[id]; ok {
continue
}
if _, err = ctx.Session.State.Role(ctx.Guild.ID, id); err != nil {
_, _ = ctx.Send(fmt.Sprintf("%s does not reference a valid role for this guild.", id))
continue
}
_, err := services.GuildService.CreateOrUpdateRole(geeksbot.Role{
ID: id,
RoleType: "moderator",
Guild: guild,
})
if err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("There was a problem adding <@&%s>", id), err)
continue
}
added[id] = true
count++
_, _ = ctx.Send(fmt.Sprintf("Added <@&%s> as a moderator role.", id))
}
_, _ = ctx.Send(fmt.Sprintf("Added %d moderator %s.", count, utils.PluralizeString("role", count)))
} else {
_, _ = ctx.Send("Please include at least one role to make a moderator role.")
}
}
var AddAdminRoleCommand = &disgoman.Command{
Name: "addAdmin",
Aliases: []string{"addAdminRole"},
Description: "Add a role which is allowed to run admin commands",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: addAdminRoleCommandFunc,
}
func addAdminRoleCommandFunc(ctx disgoman.Context, args []string) {
var count int
added := make(map[string]bool)
guild, err := services.GuildService.GetOrCreateGuild(ctx.Guild.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Something went wrong getting the guild", err)
return
}
roles := append(args, ctx.Message.MentionRoles...)
if len(roles) > 0 {
for _, id := range roles {
if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") {
continue
}
if _, ok := added[id]; ok {
continue
}
if _, err = ctx.Session.State.Role(ctx.Guild.ID, id); err != nil {
_, _ = ctx.Send(fmt.Sprintf("%s does not reference a valid role for this guild.", id))
continue
}
_, err := services.GuildService.CreateOrUpdateRole(geeksbot.Role{
ID: id,
RoleType: "admin",
Guild: guild,
})
if err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("There was a problem adding <@&%s>", id), err)
continue
}
added[id] = true
count++
_, _ = ctx.Send(fmt.Sprintf("Added <@&%s> as an admin role.", id))
}
_, _ = ctx.Send(fmt.Sprintf("Added %d admin %s.", count, utils.PluralizeString("role", count)))
} else {
_, _ = ctx.Send("Please include at least one role to make an admin role.")
}
}
var RemoveModRoleCommand = &disgoman.Command{
Name: "removeMod",
Aliases: []string{"removeModeratorRole", "removeModRole", "removeAdmin", "removeAdminRole"},
Description: "Remove a role or several roles from the moderator or admin list",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: disgoman.PermissionManageServer,
Invoke: removeModRoleCommandFunc,
}
func removeModRoleCommandFunc(ctx disgoman.Context, args []string) {
var count int
added := make(map[string]bool)
guild, err := services.GuildService.GetOrCreateGuild(ctx.Guild.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Something went wrong getting the guild", err)
return
}
roles := append(args, ctx.Message.MentionRoles...)
if len(roles) > 0 {
for _, id := range roles {
if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") {
continue
}
if _, ok := added[id]; ok {
continue
}
if _, err = ctx.Session.State.Role(ctx.Guild.ID, id); err != nil {
if r, err := services.GuildService.Role(id); err != nil {
_, _ = ctx.Send(fmt.Sprintf("%s does not reference a valid role for this guild.", id))
continue
} else {
err = services.GuildService.DeleteRole(r)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Something went wrong deleting the role", err)
}
_, _ = ctx.Send(fmt.Sprintf("Deleted <@&%s> as a no longer a valid role.", id))
continue
}
}
_, err := services.GuildService.CreateOrUpdateRole(geeksbot.Role{
ID: id,
RoleType: "normal",
Guild: guild,
})
if err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("There was a problem updating <@&%s>", id), err)
continue
}
added[id] = true
count++
_, _ = ctx.Send(fmt.Sprintf("Set <@&%s> as a normal role.", id))
}
_, _ = ctx.Send(fmt.Sprintf("Set %d %s to normal.", count, utils.PluralizeString("role", count)))
} else {
_, _ = ctx.Send("Please include at least one role to remove from the moderator or admin lists.")
}
}
var MakeRoleSelfAssignableCommand = &disgoman.Command{
Name: "make-role-self-assignable",
Aliases: []string{"makesar", "addsar"},
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) {
added := make(map[string]bool)
guild, err := services.GuildService.GetOrCreateGuild(ctx.Guild.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Something went wrong getting the guild", err)
return
}
roles := append(args, ctx.Message.MentionRoles...)
if len(roles) > 0 {
for _, id := range roles {
if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") {
continue
}
if _, ok := added[id]; ok {
continue
}
var role *discordgo.Role
var err error
if role, err = ctx.Session.State.Role(ctx.Guild.ID, id); err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%s does not reference a valid role for this guild", id), err)
return
}
_, err = services.GuildService.CreateOrUpdateRole(geeksbot.Role{
ID: role.ID,
RoleType: "sar",
Guild: guild,
})
if err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("There was a problem updating <@&%s>", role.ID), err)
return
}
_, _ = ctx.Send(fmt.Sprintf("%s is now self assignable", role.Name))
}
} else {
_, _ = ctx.Send("Please include at least one role to make self assignable")
}
}
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) {
removed := make(map[string]bool)
guild, err := services.GuildService.GetOrCreateGuild(ctx.Guild.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Something went wrong getting the guild", err)
return
}
roles := append(args, ctx.Message.MentionRoles...)
if len(roles) > 0 {
for _, id := range roles {
if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") {
continue
}
if _, ok := removed[id]; ok {
continue
}
var err error
var role *discordgo.Role
if role, err = ctx.Session.State.Role(ctx.Guild.ID, id); err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%s does not reference a valid role for this guild", id), err)
return
}
_, err = services.GuildService.CreateOrUpdateRole(geeksbot.Role{
ID: role.ID,
RoleType: "normal",
Guild: guild,
})
if err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("There was a problem updating <@&%s>", role.ID), err)
return
}
_, _ = ctx.Send(fmt.Sprintf("%s's self assignability has been removed.", role.Name))
}
} else {
_, _ = ctx.Send("Please include at least one role to make self assignable")
}
}
var SelfAssignRoleCommand = &disgoman.Command{
Name: "giverole",
Aliases: []string{"iwant", "givetome", "addrole"},
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) {
added := make(map[string]bool)
roles := append(args, ctx.Message.MentionRoles...)
if len(roles) > 0 {
for _, id := range roles {
var roleID string
if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") {
continue
} else if _, err := strconv.Atoi(id); err == nil {
roleID = id
} else {
for _, role := range ctx.Guild.Roles {
if strings.ToLower(id) == strings.ToLower(role.Name) {
roleID = role.ID
}
}
}
if _, ok := added[id]; ok {
continue
}
var role *discordgo.Role
var err error
if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%s does not reference a valid role for this guild", roleID), err)
return
}
if memberHasRole(ctx.Member, role.ID) {
_, _ = ctx.Send(fmt.Sprintf("You already have the %s role silly...", role.Name))
return
}
r, err := services.GuildService.Role(role.ID)
if err != nil || r.RoleType != "sar" {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("You aren't allowed to assign yourself the %s role", role.Name), err)
return
}
err = ctx.Session.GuildMemberRoleAdd(ctx.Guild.ID, ctx.User.ID, role.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "There was a problem adding that role to you.", err)
return
}
_, _ = ctx.Send(fmt.Sprintf("Congratulations! The %s role has been added to your... Ummm... Thing.", role.Name))
}
} else {
_, _ = ctx.Send("Please include at least one role to make self assignable")
}
}
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) {
removed := make(map[string]bool)
roles := append(args, ctx.Message.MentionRoles...)
if len(roles) > 0 {
for _, id := range roles {
var roleID string
if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") {
continue
} else if _, err := strconv.Atoi(id); err == nil {
roleID = id
} else {
for _, role := range ctx.Guild.Roles {
if strings.ToLower(id) == strings.ToLower(role.Name) {
roleID = role.ID
}
}
}
if _, ok := removed[id]; ok {
continue
}
var role *discordgo.Role
var err error
if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%s does not reference a valid role for this guild", roleID), err)
return
}
if !memberHasRole(ctx.Member, role.ID) {
_, _ = ctx.Send(fmt.Sprintf("I can't remove the %s role from you because you don't have it...", role.Name))
return
}
r, err := services.GuildService.Role(role.ID)
if err != nil || r.RoleType != "sar" {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("You aren't allowed to assign yourself the %s role", role.Name), err)
return
}
err = ctx.Session.GuildMemberRoleRemove(ctx.Guild.ID, ctx.User.ID, role.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "There was a problem removing that role from your account", err)
return
}
_, _ = ctx.Send(fmt.Sprintf("Sad to see you go... but the %s role has been removed.", role.Name))
}
} else {
_, _ = ctx.Send("Please include at least one role to make self assignable")
}
}
func memberHasRole(m *discordgo.Member, id string) bool {
for _, r := range m.Roles {
if r == id {
return true
}
}
return false
}
+21 -6
View File
@@ -2,10 +2,12 @@ package exts
import (
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/geeksbot/internal/exts/guild"
"github.com/dustinpianalto/geeksbot/internal/exts/requests"
"github.com/dustinpianalto/geeksbot/internal/exts/utils"
)
func AddCommandHandlers(h *disgoman.CommandManager) {
func AddCommandHandlers(g *disgoman.CommandManager) {
// Arguments:
// name - command name - string
// desc - command description - string
@@ -14,9 +16,22 @@ func AddCommandHandlers(h *disgoman.CommandManager) {
// 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)
_ = g.AddCommand(utils.UserCommand)
_ = g.AddCommand(utils.AddUserCommand)
_ = g.AddCommand(utils.SayCommand)
_ = g.AddCommand(utils.GitCommand)
_ = g.AddCommand(utils.InviteCommand)
_ = g.AddCommand(utils.PingCommand)
_ = g.AddCommand(guild.AddPrefixCommand)
_ = g.AddCommand(guild.RemovePrefixCommand)
_ = g.AddCommand(guild.AddModeratorRoleCommand)
_ = g.AddCommand(guild.AddAdminRoleCommand)
_ = g.AddCommand(guild.RemoveModRoleCommand)
_ = g.AddCommand(guild.MakeRoleSelfAssignableCommand)
_ = g.AddCommand(guild.RemoveSelfAssignableCommand)
_ = g.AddCommand(guild.SelfAssignRoleCommand)
_ = g.AddCommand(guild.UnAssignRoleCommand)
_ = g.AddCommand(requests.RequestCommand)
_ = g.AddCommand(requests.CloseCommand)
_ = g.AddCommand(requests.ListCommand)
}
+253
View File
@@ -0,0 +1,253 @@
package requests
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/geeksbot"
"github.com/dustinpianalto/geeksbot/internal/discord_utils"
"github.com/dustinpianalto/geeksbot/internal/utils"
"github.com/dustinpianalto/geeksbot/pkg/services"
)
var RequestCommand = &disgoman.Command{
Name: "request",
Aliases: nil,
Description: "Submit a request for the guild staff",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: requestCommandFunc,
}
func requestCommandFunc(ctx disgoman.Context, args []string) {
guild, err := services.GuildService.GetOrCreateGuild(ctx.Guild.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error getting Guild from the database", err)
return
}
requestMsg := strings.Join(args, " ")
author, err := services.UserService.GetOrCreateUser(ctx.Message.Author.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error creating the request. Could not get user.", err)
return
}
channel, err := services.ChannelService.GetOrCreateChannel(ctx.Message.ChannelID, ctx.Guild.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error creating the request. Could not get channel.", err)
return
}
int64ID, _ := strconv.ParseInt(ctx.Message.ID, 10, 64)
s := discord_utils.ParseSnowflake(int64ID)
message, err := services.MessageService.CreateMessage(geeksbot.Message{
ID: ctx.Message.ID,
CreatedAt: s.CreationTime,
Content: ctx.Message.Content,
Channel: channel,
Author: author,
})
request := geeksbot.Request{
Author: author,
Channel: channel,
Guild: guild,
Content: requestMsg,
RequestedAt: s.CreationTime,
Completed: false,
Message: message,
}
request, err = services.RequestService.CreateRequest(request)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error creating the request", err)
return
}
channels, err := services.ChannelService.GuildChannels(guild)
if err == nil {
var mentionRolesString string
roles, err := services.GuildService.GuildRoles(guild)
if err == nil {
for _, r := range roles {
if r.RoleType == "admin" || r.RoleType == "moderator" {
mentionRolesString += fmt.Sprintf("<@&%s> ", r.ID)
}
}
}
for _, c := range channels {
if c.Admin {
_, _ = ctx.Session.ChannelMessageSend(c.ID,
fmt.Sprintf("%s\n"+
"New Request ID %d "+
"%s has requested assistance: \n"+
"```\n%s\n```\n"+
"Requested At: %s\n"+
"In: %s",
mentionRolesString,
request.ID,
ctx.Message.Author.Mention(),
request.Content,
request.RequestedAt.UTC().Format(time.UnixDate),
ctx.Channel.Mention(),
),
)
}
}
}
_, err = ctx.Send(fmt.Sprintf("%s The admin have recieved your request.\n "+
"If you would like to close or add a comment to this request please reference ID `%v`",
ctx.Message.Author.Mention(), request.ID,
))
if err != nil {
discord_utils.SendErrorMessage(ctx, "There was an error sending the message. The request was created.", err)
}
}
var CloseCommand = &disgoman.Command{
Name: "close",
Aliases: nil,
Description: "Close a request and mark it as completed.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: closeCommandFunc,
}
func closeCommandFunc(ctx disgoman.Context, args []string) {
var ids []int64
var reason string
_, err := strconv.ParseInt(args[len(args)-1], 10, 64)
if err != nil {
reason = args[len(args)-1]
args = args[0 : len(args)-1]
}
for _, a := range args {
a = strings.Trim(a, ",")
id, err := strconv.ParseInt(a, 10, 64)
if err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%s is not a valid request id", a), err)
continue
}
ids = append(ids, id)
}
if len(ids) == 0 {
discord_utils.SendErrorMessage(ctx, "No requests to close", nil)
return
}
guild, err := services.GuildService.GetOrCreateGuild(ctx.Guild.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error getting Guild from the database", err)
return
}
closer, err := services.UserService.GetOrCreateUser(ctx.Message.Author.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error closing the request. Could not get user.", err)
return
}
int64ID, _ := strconv.ParseInt(ctx.Message.ID, 10, 64)
s := discord_utils.ParseSnowflake(int64ID)
for _, id := range ids {
request, err := services.RequestService.Request(id)
if err != nil || request.Guild.ID != guild.ID {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%d is not a request in this guild.", id), err)
continue
}
if request.Author != closer && !closer.IsStaff && !closer.IsAdmin {
if !discord_utils.IsGuildMod(ctx, closer) || !discord_utils.IsGuildAdmin(ctx, closer) {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("You are not authorized to close %d", id), nil)
continue
}
}
if request.Completed {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%d is already closed", id), err)
continue
}
request.Completed = true
request.CompletedAt.Valid = true
request.CompletedAt.Time = s.CreationTime
request.CompletedBy = &closer
if reason != "" {
request.CompletedMessage.Valid = true
request.CompletedMessage.String = reason
}
request, err = services.RequestService.UpdateRequest(request)
if err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("Error closing %d", id), err)
continue
}
_, err = ctx.Send(fmt.Sprintf("%d has been closed", request.ID))
if err != nil {
discord_utils.SendErrorMessage(ctx, "There was an error sending the message. The request was closed.", err)
}
}
}
var ListCommand = &disgoman.Command{
Name: "list",
Aliases: []string{"request_list", "requests_list"},
Description: "List your open requests or all open requests if the caller is a moderator",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: listCommandFunc,
}
func listCommandFunc(ctx disgoman.Context, args []string) {
user, err := services.UserService.GetOrCreateUser(ctx.Message.Author.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error closing the request. Could not get user.", err)
return
}
guild, err := services.GuildService.GetOrCreateGuild(ctx.Guild.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Error getting Guild from the database", err)
return
}
var requests []geeksbot.Request
if discord_utils.IsGuildMod(ctx, user) || discord_utils.IsGuildAdmin(ctx, user) {
requests, err = services.RequestService.GuildRequests(guild, false)
} else {
requests, err = services.RequestService.UserRequests(user, false)
}
for _, request := range requests {
var authorName string
author, err := ctx.Session.GuildMember(guild.ID, request.Author.ID)
if err != nil {
authorName = "Unknown"
} else {
if author.Nick == "" {
authorName = author.User.Username
} else {
authorName = author.Nick
}
}
var channelName string
channel, err := ctx.Session.Channel(request.Channel.ID)
if err != nil {
channelName = "Unknown"
} else {
channelName = channel.Name
}
_, _ = ctx.Send(fmt.Sprintf("```md\n"+
"< Request ID Requested By >\n"+
"< %11s %-23s >\n"+
"%s\n\n"+
"Comments: Not Implemented Yet\n"+
"Requested At: %s\n"+
"In: %s\n"+
"```",
request.ID,
authorName,
request.Content,
request.RequestedAt.Format("2006-01-02 15:04:05 MST"),
channelName,
))
}
_, _ = ctx.Send(fmt.Sprintf("There are currently %d open %s", len(requests), utils.PluralizeString("request", len(requests))))
}
+33
View File
@@ -9,7 +9,9 @@ import (
"github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/geeksbot"
"github.com/dustinpianalto/geeksbot/internal/discord_utils"
"github.com/dustinpianalto/geeksbot/pkg/services"
)
var PingCommand = &disgoman.Command{
@@ -246,3 +248,34 @@ func userCommandFunc(ctx disgoman.Context, args []string) {
}
}
}
var AddUserCommand = &disgoman.Command{
Name: "adduser",
Aliases: nil,
Description: "Get user info",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: addUserCommandFunc,
}
func addUserCommandFunc(ctx disgoman.Context, args []string) {
if ctx.Message.Author.ID == ctx.CommandManager.Owners[0] {
user := geeksbot.User{
ID: ctx.Message.Author.ID,
IsActive: true,
IsStaff: true,
IsAdmin: true,
}
user, err := services.UserService.CreateUser(user)
if err != nil {
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
Context: ctx,
Message: "Error with adding user",
Error: err,
}
return
}
ctx.Session.MessageReactionAdd(ctx.Channel.ID, ctx.Message.ID, "✅")
}
}
+21
View File
@@ -0,0 +1,21 @@
package utils
func RemoveDuplicateStrings(s []string) []string {
keys := make(map[string]bool)
o := []string{}
for _, e := range s {
if _, v := keys[e]; !v {
keys[e] = true
o = append(o, e)
}
}
return o
}
func PluralizeString(s string, i int) string {
if i == 1 {
return s
}
return s + "s"
}
+13 -12
View File
@@ -1,23 +1,24 @@
package geeksbot
import "github.com/bwmarrin/discordgo"
import (
"database/sql"
"time"
)
type Message struct {
ID string
CreatedAt int64
ModifiedAt int64
CreatedAt time.Time
ModifiedAt sql.NullTime
Content string
PreviousContent []string
Channel *Channel
Author *User
Embed *discordgo.MessageEmbed
PreviousEmbeds []*discordgo.MessageEmbed
Channel Channel
Author User
}
type MessageService interface {
Message(id string) (*Message, error)
CreateMessage(m *Message) (*Message, error)
DeleteMessage(m *Message) error
ChannelMessages(c *Channel) ([]*Message, error)
UpdateMessage(m *Message) (*Message, error)
Message(id string) (Message, error)
CreateMessage(m Message) (Message, error)
DeleteMessage(m Message) error
ChannelMessages(c Channel) ([]Message, error)
UpdateMessage(m Message) (Message, error)
}
+18 -15
View File
@@ -1,31 +1,34 @@
package geeksbot
import "database/sql"
type PatreonCreator struct {
ID int
Creator string
Link string
Guild *Guild
Guild Guild
}
type PatreonTier struct {
ID int
Name string
Description string
Creator *PatreonCreator
Role *Role
Description sql.NullString
Creator PatreonCreator
Role Role
NextTier *PatreonTier
}
type PatreonService interface {
PatreonCreatorByID(id int) (*PatreonCreator, error)
PatreonCreatorByName(name string) (*PatreonCreator, error)
CreatePatreonCreator(c *PatreonCreator) (*PatreonCreator, error)
UpdatePatreonCreator(c *PatreonCreator) (*PatreonCreator, error)
DeletePatreonCreator(c *PatreonCreator) error
PatreonTierByID(id int) (*PatreonTier, error)
PatreonTierByName(name string) (*PatreonTier, error)
CreatePatreonTier(t *PatreonTier) (*PatreonTier, error)
UpdatePatreonTier(t *PatreonTier) (*PatreonTier, error)
DeletePatreonTier(t *PatreonTier) error
GuildPatreonCreators(g *Guild) ([]*PatreonCreator, error)
PatreonCreatorByID(id int) (PatreonCreator, error)
PatreonCreatorByName(name string, guild Guild) (PatreonCreator, error)
CreatePatreonCreator(c PatreonCreator) (PatreonCreator, error)
UpdatePatreonCreator(c PatreonCreator) (PatreonCreator, error)
DeletePatreonCreator(c PatreonCreator) error
PatreonTierByID(id int) (PatreonTier, error)
PatreonTierByName(name string, creator string) (PatreonTier, error)
CreatePatreonTier(t PatreonTier) (PatreonTier, error)
UpdatePatreonTier(t PatreonTier) (PatreonTier, error)
DeletePatreonTier(t PatreonTier) error
GuildPatreonCreators(g Guild) ([]PatreonCreator, error)
CreatorPatreonTiers(c PatreonCreator) ([]PatreonTier, error)
}
+87
View File
@@ -0,0 +1,87 @@
package database
import (
"database/sql"
"log"
"github.com/dustinpianalto/geeksbot"
)
type channelService struct {
db *sql.DB
}
func (s channelService) Channel(id string) (geeksbot.Channel, error) {
var channel geeksbot.Channel
var guild_id string
queryString := "SELECT id, guild_id, admin, default_channel, new_patron FROM channels WHERE id = $1"
row := s.db.QueryRow(queryString, id)
err := row.Scan(&channel.ID, &guild_id, &channel.Admin, &channel.Default, &channel.NewPatron)
if err != nil {
return geeksbot.Channel{}, err
}
guild, err := GuildService.Guild(guild_id)
if err != nil {
return geeksbot.Channel{}, err
}
channel.Guild = guild
return channel, nil
}
func (s channelService) CreateChannel(c geeksbot.Channel) (geeksbot.Channel, error) {
queryString := "INSERT INTO channels (id, guild_id, admin, default_channel, new_patron) VALUES ($1, $2, $3, $4, $5)"
_, err := s.db.Exec(queryString, c.ID, c.Guild.ID, c.Admin, c.Default, c.NewPatron)
return c, err
}
func (s channelService) DeleteChannel(c geeksbot.Channel) error {
queryString := "DELETE FROM channels WHERE id = $1"
_, err := s.db.Exec(queryString, c.ID)
return err
}
func (s channelService) UpdateChannel(c geeksbot.Channel) (geeksbot.Channel, error) {
queryString := "UPDATE channels SET admin = $2, default_channel = $3, new_patron = $4 WHERE id = $1"
_, err := s.db.Exec(queryString, c.ID, c.Admin, c.Default, c.NewPatron)
return c, err
}
func (s channelService) GuildChannels(g geeksbot.Guild) ([]geeksbot.Channel, error) {
var channels []geeksbot.Channel
queryString := "SELECT id FROM channels WHERE guild_id = $1"
rows, err := s.db.Query(queryString, g.ID)
for rows.Next() {
var id string
err = rows.Scan(&id)
if err != nil {
log.Println(err)
continue
}
channel, err := s.Channel(id)
if err != nil {
log.Println(err)
continue
}
channels = append(channels, channel)
}
return channels, nil
}
func (s channelService) GetOrCreateChannel(id string, guild_id string) (geeksbot.Channel, error) {
channel, err := s.Channel(id)
if err == sql.ErrNoRows {
var guild geeksbot.Guild
guild, err = GuildService.GetOrCreateGuild(guild_id)
if err != nil {
return geeksbot.Channel{}, err
}
channel, err = s.CreateChannel(geeksbot.Channel{
ID: id,
Guild: guild,
Admin: false,
Default: false,
NewPatron: false,
})
}
return channel, err
}
+72
View File
@@ -0,0 +1,72 @@
package database
import (
"database/sql"
"fmt"
"log"
"github.com/dustinpianalto/geeksbot/pkg/database/migrations"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/postgres"
bindata "github.com/golang-migrate/migrate/v4/source/go_bindata"
)
var (
db *sql.DB
GuildService guildService
UserService userService
ChannelService channelService
MessageService messageService
RequestService requestService
PatreonService patreonService
ServerService serverService
)
func ConnectDatabase(dbConnString string) {
s := bindata.Resource(migrations.AssetNames(),
func(name string) ([]byte, error) {
return migrations.Asset(name)
})
var err error
db, err = sql.Open("postgres", dbConnString)
if err != nil {
log.Fatal(fmt.Errorf("Can't connect to the database: %w", err))
}
log.Println("Database Connected.")
db.SetMaxOpenConns(75)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(300)
d, err := bindata.WithInstance(s)
if err != nil {
log.Fatal(fmt.Errorf("cannot load migrations: %w", err))
}
instance, err := postgres.WithInstance(db, &postgres.Config{})
if err != nil {
log.Fatal(fmt.Errorf("cannot create db driver: %w", err))
}
m, err := migrate.NewWithInstance("go-bindatafoo", d, "postgres", instance)
if err != nil {
log.Fatal(fmt.Errorf("cannot create migration instance: %w", err))
}
err = m.Up()
if err != nil {
if err.Error() == "no change" {
log.Println(err)
} else {
log.Fatal(err)
}
}
log.Println("Migrations Run")
initServices()
log.Println("Services Initialized")
}
func initServices() {
GuildService = guildService{db: db}
UserService = userService{db: db}
ChannelService = channelService{db: db}
MessageService = messageService{db: db}
PatreonService = patreonService{db: db}
RequestService = requestService{db: db}
ServerService = serverService{db: db}
}
+121
View File
@@ -0,0 +1,121 @@
package database
import (
"database/sql"
"log"
"github.com/dustinpianalto/geeksbot"
"github.com/lib/pq"
)
type guildService struct {
db *sql.DB
}
func (s guildService) Guild(id string) (geeksbot.Guild, error) {
var g geeksbot.Guild
queryString := "SELECT id, new_patron_message, prefixes FROM guilds WHERE id = $1"
row := s.db.QueryRow(queryString, id)
err := row.Scan(&g.ID, &g.NewPatronMessage, pq.Array(&g.Prefixes))
if err != nil {
return geeksbot.Guild{}, err
}
return g, nil
}
func (s guildService) CreateGuild(g geeksbot.Guild) (geeksbot.Guild, error) {
queryString := "INSERT INTO guilds (id, new_patron_message, prefixes) VALUES ($1, $2, $3)"
_, err := s.db.Exec(queryString, g.ID, g.NewPatronMessage, pq.Array(g.Prefixes))
return g, err
}
func (s guildService) DeleteGuild(g geeksbot.Guild) error {
queryString := "DELETE FROM guilds WHERE id = $1"
_, err := s.db.Exec(queryString, g.ID)
return err
}
func (s guildService) UpdateGuild(g geeksbot.Guild) (geeksbot.Guild, error) {
queryString := "UPDATE guilds SET new_patron_message = $2, prefixes = $3 WHERE id = $1"
_, err := s.db.Exec(queryString, g.ID, g.NewPatronMessage, pq.Array(g.Prefixes))
return g, err
}
func (s guildService) GuildRoles(g geeksbot.Guild) ([]geeksbot.Role, error) {
var roles []geeksbot.Role
queryString := "SELECT id FROM roles WHERE guild_id = $1"
rows, err := s.db.Query(queryString, g.ID)
if err != nil {
return nil, err
}
for rows.Next() {
var id string
err = rows.Scan(&id)
if err != nil {
log.Println(err)
continue
}
role, err := s.Role(id)
if err != nil {
log.Println(err)
continue
}
roles = append(roles, role)
}
return roles, nil
}
func (s guildService) CreateRole(r geeksbot.Role) (geeksbot.Role, error) {
queryString := "INSERT INTO roles (id, role_type, guild_id) VALUES ($1, $2, $3)"
_, err := s.db.Exec(queryString, r.ID, r.RoleType, r.Guild.ID)
return r, err
}
func (s guildService) Role(id string) (geeksbot.Role, error) {
var role geeksbot.Role
var guild_id string
queryString := "SELECT id, role_type, guild_id FROM roles WHERE id = $1"
row := s.db.QueryRow(queryString, id)
err := row.Scan(&role.ID, &role.RoleType, &guild_id)
if err != nil {
return geeksbot.Role{}, err
}
guild, err := s.Guild(guild_id)
if err != nil {
return geeksbot.Role{}, err
}
role.Guild = guild
return role, nil
}
func (s guildService) UpdateRole(r geeksbot.Role) (geeksbot.Role, error) {
queryString := "UPDATE roles SET role_type = $2 WHERE id = $1"
_, err := s.db.Exec(queryString, r.ID, r.RoleType)
return r, err
}
func (s guildService) DeleteRole(r geeksbot.Role) error {
queryString := "DELETE FROM roles WHERE id = $1"
_, err := s.db.Exec(queryString, r.ID)
return err
}
func (s guildService) GetOrCreateGuild(id string) (geeksbot.Guild, error) {
guild, err := s.Guild(id)
if err == sql.ErrNoRows {
guild = geeksbot.Guild{
ID: id,
Prefixes: []string{},
}
guild, err = s.CreateGuild(guild)
}
return guild, err
}
func (s guildService) CreateOrUpdateRole(r geeksbot.Role) (geeksbot.Role, error) {
role, err := s.CreateRole(r)
if err != nil && err.Error() == `pq: duplicate key value violates unique constraint "roles_pkey"` {
role, err = s.UpdateRole(r)
}
return role, err
}
+95
View File
@@ -0,0 +1,95 @@
package database
import (
"database/sql"
"log"
"github.com/dustinpianalto/geeksbot"
"github.com/lib/pq"
)
type messageService struct {
db *sql.DB
}
func (s messageService) Message(id string) (geeksbot.Message, error) {
var m geeksbot.Message
var channel_id string
var author_id string
queryString := `SELECT m.id, m.created_at, m.modified_at, m.content,
m.previous_content, m.channel_id, m.author_id
FROM messages as m
WHERE m.id = $1`
row := s.db.QueryRow(queryString, id)
err := row.Scan(&m.ID, &m.CreatedAt, &m.ModifiedAt, &m.Content,
pq.Array(&m.PreviousContent), &channel_id, &author_id)
if err != nil {
return geeksbot.Message{}, err
}
author, err := UserService.User(author_id)
if err != nil {
return geeksbot.Message{}, err
}
m.Author = author
channel, err := ChannelService.Channel(channel_id)
if err != nil {
return geeksbot.Message{}, err
}
m.Channel = channel
return m, nil
}
func (s messageService) CreateMessage(m geeksbot.Message) (geeksbot.Message, error) {
queryString := `INSERT INTO messages (id, created_at, content, channel_id, author_id)
VALUES ($1, $2, $3, $4, $5)`
_, err := s.db.Exec(queryString, m.ID, m.CreatedAt, m.Content, m.Channel.ID, m.Author.ID)
return m, err
}
func (s messageService) UpdateMessage(m geeksbot.Message) (geeksbot.Message, error) {
var content string
var previousContent []string
queryString := "SELECT content, previous_content FROM messages WHERE id = $1"
row := s.db.QueryRow(queryString, m.ID)
err := row.Scan(&content, &previousContent)
if err != nil {
return geeksbot.Message{}, err
}
if m.Content != content {
previousContent = append(previousContent, content)
}
queryString = "UPDATE messages SET modified_at = $2, content = $3, previous_content = $4 WHERE id = $1"
_, err = s.db.Exec(queryString, m.ID, m.ModifiedAt, m.Content, previousContent)
m.PreviousContent = previousContent
return m, nil
}
func (s messageService) DeleteMessage(m geeksbot.Message) error {
queryString := "DELETE FROM messages WHERE id = $1"
_, err := s.db.Exec(queryString, m.ID)
return err
}
func (s messageService) ChannelMessages(c geeksbot.Channel) ([]geeksbot.Message, error) {
var messages []geeksbot.Message
queryString := `SELECT id FROM messages WHERE channel_id = $1`
rows, err := s.db.Query(queryString, c.ID)
if err != nil {
return nil, err
}
for rows.Next() {
var id string
err = rows.Scan(&id)
if err != nil {
log.Println(err)
continue
}
m, err := s.Message(id)
if err != nil {
log.Println(err)
continue
}
messages = append(messages, m)
}
return messages, nil
}
@@ -5,7 +5,7 @@ BEGIN;
prefixes varchar(10)[],
PRIMARY KEY(id)
);
CREATE TYPE IF NOT EXISTS role_type as ENUM (
CREATE TYPE role_type as ENUM (
'normal',
'moderator',
'admin',
@@ -25,7 +25,7 @@ BEGIN;
id varchar(30),
guild_id varchar(30),
admin boolean,
default boolean,
default_channel boolean,
new_patron boolean,
PRIMARY KEY(id),
CONSTRAINT fk_guild
@@ -45,7 +45,7 @@ BEGIN;
id varchar(30),
created_at timestamp,
modified_at timestamp,
content varchar(2000)
content varchar(2000),
previous_content varchar(2000)[],
channel_id varchar(30),
author_id varchar(30),
@@ -89,7 +89,7 @@ BEGIN;
REFERENCES roles(id)
ON DELETE SET NULL,
CONSTRAINT fk_tier
FOREIGN_KEY(next_tier)
FOREIGN KEY(next_tier)
REFERENCES patreon_tier(id)
ON DELETE SET NULL
);
@@ -0,0 +1 @@
ALTER TABLE requests DROP COLUMN guild_id;
@@ -0,0 +1,2 @@
ALTER TABLE requests
ADD COLUMN guild_id varchar(30) CONSTRAINT fk_guild REFERENCES guilds(id) ON DELETE CASCADE;
@@ -0,0 +1,48 @@
BEGIN;
ALTER TABLE users
ALTER COLUMN active DROP NOT NULL,
ALTER COLUMN staff DROP NOT NULL,
ALTER COLUMN admin DROP NOT NULL;
ALTER TABLE channels
ALTER COLUMN guild_id DROP NOT NULL,
ALTER COLUMN admin DROP NOT NULL,
ALTER COLUMN default_channel DROP NOT NULL,
ALTER COLUMN new_patron DROP NOT NULL;
ALTER TABLE messages
ALTER COLUMN created_at DROP NOT NULL,
ALTER COLUMN content DROP NOT NULL,
ALTER COLUMN channel_id DROP NOT NULL,
ALTER COLUMN author_id DROP NOT NULL;
ALTER TABLE messages
ADD COLUMN embed json,
ADD COLUMN previous_embeds json[];
ALTER TABLE patreon_creators
ALTER COLUMN creator DROP NOT NULL,
ALTER COLUMN link DROP NOT NULL,
ALTER COLUMN guild_id DROP NOT NULL;
ALTER TABLE patreon_creators
RENAME TO patreon_creator;
ALTER TABLE patreon_tiers
ALTER COLUMN name DROP NOT NULL,
ALTER COLUMN creator DROP NOT NULL,
ALTER COLUMN role DROP NOT NULL;
ALTER TABLE patreon_tiers
RENAME TO patreon_tier;
ALTER TABLE requests
ALTER COLUMN author_id DROP NOT NULL,
ALTER COLUMN channel_id DROP NOT NULL,
ALTER COLUMN content DROP NOT NULL,
ALTER COLUMN requested_at DROP NOT NULL,
ALTER COLUMN completed DROP NOT NULL,
ALTER COLUMN message_id DROP NOT NULL,
ALTER COLUMN guild_id DROP NOT NULL;
ALTER TABLE roles
ALTER COLUMN role_type DROP NOT NULL,
ALTER COLUMN guild_id DROP NOT NULL;
ALTER TABLE servers
ALTER COLUMN name DROP NOT NULL,
ALTER COLUMN ip_address DROP NOT NULL,
ALTER COLUMN port DROP NOT NULL,
ALTER COLUMN password DROP NOT NULL,
ALTER COLUMN guild_id DROP NOT NULL;
COMMIT;
@@ -0,0 +1,48 @@
BEGIN;
ALTER TABLE users
ALTER COLUMN active SET NOT NULL,
ALTER COLUMN staff SET NOT NULL,
ALTER COLUMN admin SET NOT NULL;
ALTER TABLE channels
ALTER COLUMN guild_id SET NOT NULL,
ALTER COLUMN admin SET NOT NULL,
ALTER COLUMN default_channel SET NOT NULL,
ALTER COLUMN new_patron SET NOT NULL;
ALTER TABLE messages
ALTER COLUMN created_at SET NOT NULL,
ALTER COLUMN content SET NOT NULL,
ALTER COLUMN channel_id SET NOT NULL,
ALTER COLUMN author_id SET NOT NULL;
ALTER TABLE messages
DROP COLUMN embed,
DROP COLUMN previous_embeds;
ALTER TABLE patreon_creator
ALTER COLUMN creator SET NOT NULL,
ALTER COLUMN link SET NOT NULL,
ALTER COLUMN guild_id SET NOT NULL;
ALTER TABLE patreon_creator
RENAME TO patreon_creators;
ALTER TABLE patreon_tier
ALTER COLUMN name SET NOT NULL,
ALTER COLUMN creator SET NOT NULL,
ALTER COLUMN role SET NOT NULL;
ALTER TABLE patreon_tier
RENAME TO patreon_tiers;
ALTER TABLE requests
ALTER COLUMN author_id SET NOT NULL,
ALTER COLUMN channel_id SET NOT NULL,
ALTER COLUMN content SET NOT NULL,
ALTER COLUMN requested_at SET NOT NULL,
ALTER COLUMN completed SET NOT NULL,
ALTER COLUMN message_id SET NOT NULL,
ALTER COLUMN guild_id SET NOT NULL;
ALTER TABLE roles
ALTER COLUMN role_type SET NOT NULL,
ALTER COLUMN guild_id SET NOT NULL;
ALTER TABLE servers
ALTER COLUMN name SET NOT NULL,
ALTER COLUMN ip_address SET NOT NULL,
ALTER COLUMN port SET NOT NULL,
ALTER COLUMN password SET NOT NULL,
ALTER COLUMN guild_id SET NOT NULL;
COMMIT;
@@ -0,0 +1,14 @@
BEGIN;
CREATE TYPE role_type_new AS ENUM (
'normal',
'moderator',
'admin',
'patreon',
);
UPDATE roles SET role_type = 'normal' WHERE role_type = 'sar';
ALTER TABLE roles
ALTER COLUMN roles TYPE role_type_new;
USING (roles::text::role_type_new)
DROP TYPE role_type;
ALTER TYPE role_type_new RENAME TO role_type;
COMMIT;
@@ -0,0 +1 @@
ALTER TYPE role_type ADD VALUE 'sar';
@@ -0,0 +1,6 @@
BEGIN;
ALTER TABLE messages
ALTER COLUMN previous_content DROP NOT NULL;
ALTER TABLE messages
ALTER COLUMN previous_content DROP DEFAULT;
COMMIT;
@@ -0,0 +1,6 @@
BEGIN;
ALTER TABLE messages
ALTER COLUMN previous_content SET NOT NULL;
ALTER TABLE messages
ALTER COLUMN previous_content SET DEFAULT array[]::varchar[];
COMMIT;
+267
View File
@@ -0,0 +1,267 @@
// Code generated for package migrations by go-bindata DO NOT EDIT. (@generated)
// sources:
// 000001_init_schema.down.sql
// 000001_init_schema.up.sql
package migrations
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
}
var buf bytes.Buffer
_, err = io.Copy(&buf, gz)
clErr := gz.Close()
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
}
if clErr != nil {
return nil, err
}
return buf.Bytes(), nil
}
type asset struct {
bytes []byte
info os.FileInfo
}
type bindataFileInfo struct {
name string
size int64
mode os.FileMode
modTime time.Time
}
// Name return file name
func (fi bindataFileInfo) Name() string {
return fi.name
}
// Size return file size
func (fi bindataFileInfo) Size() int64 {
return fi.size
}
// Mode return file mode
func (fi bindataFileInfo) Mode() os.FileMode {
return fi.mode
}
// Mode return file modify time
func (fi bindataFileInfo) ModTime() time.Time {
return fi.modTime
}
// IsDir return file whether a directory
func (fi bindataFileInfo) IsDir() bool {
return fi.mode&os.ModeDir != 0
}
// Sys return file is sys mode
func (fi bindataFileInfo) Sys() interface{} {
return nil
}
var __000001_init_schemaDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\xcf\x3d\x0e\xc2\x30\x0c\x86\xe1\x3d\xa7\xf0\x3d\x32\x51\x08\x28\x12\xa5\x15\xcd\x00\x53\x15\x15\xab\x54\xca\x4f\xb1\x13\x24\x6e\xcf\x0c\x83\x61\xf6\x23\x7d\x7e\x1b\x73\xb0\x27\xad\x00\x00\x76\xe7\xae\x07\xb7\x69\x8e\x06\xec\x1e\xcc\xc5\x0e\x6e\x00\x46\x7a\x22\xb1\x20\xa6\x1c\x23\xa6\x22\x11\xc2\x47\x45\x16\xc9\xea\x0b\x61\x4e\x63\x59\x90\xfe\x60\x13\xa1\x2f\x59\x92\x11\x99\xfd\x8c\xd2\x66\xe5\x1f\x65\x77\x9f\x12\x06\xb1\x2c\x87\xcf\x89\x6b\xff\x7d\x1e\xcb\x6b\x15\xdf\x98\xeb\x12\x6e\xac\xd5\xb6\x6b\x5b\xeb\xb4\x7a\x07\x00\x00\xff\xff\x57\xde\x8f\x03\x93\x01\x00\x00")
func _000001_init_schemaDownSqlBytes() ([]byte, error) {
return bindataRead(
__000001_init_schemaDownSql,
"000001_init_schema.down.sql",
)
}
func _000001_init_schemaDownSql() (*asset, error) {
bytes, err := _000001_init_schemaDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "000001_init_schema.down.sql", size: 403, mode: os.FileMode(420), modTime: time.Unix(1611206279, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __000001_init_schemaUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x58\x5d\x6f\xa3\x38\x14\x7d\xef\xaf\xf0\x5b\x12\x69\x1f\xba\xbb\xda\xa7\x3e\xd1\xc4\xad\xd0\x26\xa4\x22\x54\xbb\xd1\x68\x84\xdc\x70\x93\x7a\x0a\x36\x63\x3b\x69\xfb\xef\x47\x50\x3e\x1c\xc0\xe0\x51\x99\x6a\xca\x53\xe4\x7b\xb1\x8f\xcf\x3d\xf7\x83\x5c\xe3\x5b\xd7\xbb\xba\x40\x08\xa1\xb9\x8f\x9d\x00\xa3\xc0\xb9\x5e\x62\xe4\xde\x20\x6f\x1d\x20\xfc\xbf\xbb\x09\x36\xe8\x70\xa4\x71\x24\xd1\x34\xf7\xcb\x1e\x1a\xa1\x13\x11\xbb\x47\x22\xa6\x7f\x5f\xce\xfe\xa8\xd6\x19\x3c\x87\x29\x51\x82\xb3\x30\x01\x29\xc9\x01\x2a\xbf\x3f\x2f\x2f\x75\xcf\x54\xc0\x9e\xbe\x80\xd4\xec\xb3\x2f\x5f\x6b\xfb\x9d\xef\xae\x1c\x7f\x8b\xfe\xc5\xdb\x29\x8d\x66\xf9\xfa\xec\x1c\xe8\xf6\x0e\x23\xc1\x63\x08\xd5\x6b\x0a\x88\x48\x84\xbd\xfb\x95\x06\x72\xc2\xb8\x48\x48\x3c\xa9\x37\x9d\x24\x3c\x02\x41\x14\x17\xfa\x22\x89\x12\xca\xf4\x85\xec\x06\xc0\xd9\xa4\xeb\xd0\x0e\x76\x32\x0c\x36\xe4\xd4\x58\xab\x5f\xb5\x31\xa7\x38\x34\xbd\xda\x60\xa3\x36\xcc\xd7\xde\x26\xf0\x1d\xd7\x0b\xd0\xfe\x29\xcc\x37\xa9\x6c\xd9\x73\xb3\xf6\xb1\x7b\xeb\xe5\x2f\x96\x47\xcc\xce\x3c\xb2\xc7\xc7\x37\xd8\xc7\xde\x1c\x97\xa1\x9e\x76\x79\xad\x3d\xb4\xc0\x4b\x1c\x60\x34\x77\x36\x73\x67\x81\x2d\xf9\xd9\x3d\x12\xc6\x20\xb6\xa1\xa8\x9f\x85\x3c\x50\xe8\x81\xf3\x18\x08\xab\x97\x23\xd8\x93\x63\xac\xc2\xe2\x9c\xb6\x43\xad\xca\xb6\xed\x53\x33\x7b\x94\x20\x6c\x68\x95\x0a\x48\x62\xa6\x75\xa7\xe8\x09\xda\xd4\x48\x45\xf6\xfb\xf6\xb2\x21\x0a\x16\x09\xdb\x71\x83\xa2\x4a\xd8\x5c\x62\x27\x80\x28\x88\x42\xa2\x90\xa2\x09\x48\x45\x92\xb4\xb6\x26\x3c\xa2\x7b\x6a\x34\xef\x38\x53\xc0\x54\xb5\xf3\x5f\xad\x6a\x74\xa2\xfc\x28\xc3\x4e\x3f\xbd\x2e\x15\x22\x33\x93\x79\x54\x8f\x5c\x18\xcd\x90\x3c\x40\x84\xbe\x49\xce\x3a\x0e\xcf\x8d\x32\xb7\xf6\x94\x42\x93\x44\x0b\x64\x46\x91\xd6\xc8\x7b\x65\x5a\x66\xab\x9d\x50\x4d\x60\x32\x65\x1a\x91\x54\x1c\xf5\x02\xc9\xc5\x3d\x80\x62\x83\x03\xe4\xdd\x2f\x97\x96\x6a\x2b\x0a\x7b\x98\x4b\x89\x8b\x73\xd1\x51\xa6\xe0\x00\x02\xdd\x62\x0f\xfb\x4e\x80\x17\xc8\x59\xfe\xe7\x6c\x37\xc8\xd9\x20\x77\x81\xbd\xc0\x0d\xb6\x0d\x35\x72\xa1\xb7\x37\x2d\x32\x31\x65\x4f\xba\x86\xac\x4b\xdc\xa7\x2e\x47\x25\xbd\x8a\x42\x83\xdb\x9f\x24\x97\x91\x04\x0c\xcc\x46\x20\x77\x82\xa6\x8a\x72\x66\x1a\x2d\xca\xd0\x14\x67\x9e\x37\x60\xd3\xdc\xf2\xa2\xde\x60\xb7\x5e\xb2\xcd\xbe\xb7\x43\xcd\xd9\xf7\x66\xef\x0d\x49\x43\x9e\xef\xcb\xc0\xec\xb2\x46\x34\x99\xb1\x17\x4a\x3e\xd3\x58\x26\x9f\x09\x41\xc6\xa7\x11\x41\xc5\xb8\x15\x23\x99\xe3\xb8\xa5\x40\xc0\xf7\x23\x48\x25\xdf\x53\x03\x06\x6a\xfd\x50\xab\x68\xf6\x9a\x86\x8c\x0b\x84\x3d\x2d\x2d\x49\x63\xb0\xb0\xb7\x7b\x75\xfd\xea\xc3\x6b\x37\xb6\xa2\x2f\xf7\x60\x2f\x77\x18\x98\xf3\x2d\xd3\xe7\x83\xfa\xc5\x40\xce\xfc\x56\x2d\x54\x0f\x92\x19\x91\xe6\x34\x5a\x37\x35\x21\x2a\x42\x6d\x04\x53\x8b\xa6\x17\x4a\x39\xf3\x8d\xfb\x91\xc1\x93\x04\xd8\x2f\xcd\xe7\x22\x21\xc3\x7a\xdf\xb3\x7c\xc8\x8e\xb7\x9c\x3e\x3f\x73\x8e\x14\x2c\x98\x5b\x4b\xc5\x52\x7f\x83\x29\xea\xef\xa8\x22\x90\x20\x4e\xad\x2f\xa2\xd1\x46\x0f\x9a\x86\x24\x8a\x04\x48\xed\x4f\x8b\x7f\xf4\x8f\x08\x2e\x54\x5b\x19\x29\x91\xf2\x99\x8b\xc8\x30\x0e\x92\x18\x84\x92\xe1\x50\xaf\xe8\x9f\x1a\x29\xdb\xf3\xc1\x2d\x72\xa7\xa1\xba\x2e\x41\x29\xca\x0e\x72\xd0\xd1\x52\xb3\xf9\xf5\x06\xeb\x6a\x8b\x84\x31\xca\xeb\x50\x35\xfb\xe0\x19\xda\x04\x43\x8f\x9d\x11\x4d\x23\xc0\x1f\x41\x8f\x2e\x97\x7e\x5c\xe3\x96\xfd\x21\x5c\x4d\x85\x1a\xb1\x75\x48\x79\x4c\x7c\x65\x49\x9a\xaf\x57\x2b\x37\xb8\xba\xf8\x11\x00\x00\xff\xff\xb3\xc0\x11\x7f\x4a\x15\x00\x00")
func _000001_init_schemaUpSqlBytes() ([]byte, error) {
return bindataRead(
__000001_init_schemaUpSql,
"000001_init_schema.up.sql",
)
}
func _000001_init_schemaUpSql() (*asset, error) {
bytes, err := _000001_init_schemaUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "000001_init_schema.up.sql", size: 5450, mode: os.FileMode(420), modTime: time.Unix(1611216889, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
}
return a.bytes, nil
}
return nil, fmt.Errorf("Asset %s not found", name)
}
// MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables.
func MustAsset(name string) []byte {
a, err := Asset(name)
if err != nil {
panic("asset: Asset(" + name + "): " + err.Error())
}
return a
}
// AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
}
return a.info, nil
}
return nil, fmt.Errorf("AssetInfo %s not found", name)
}
// AssetNames returns the names of the assets.
func AssetNames() []string {
names := make([]string, 0, len(_bindata))
for name := range _bindata {
names = append(names, name)
}
return names
}
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"000001_init_schema.down.sql": _000001_init_schemaDownSql,
"000001_init_schema.up.sql": _000001_init_schemaUpSql,
}
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
// AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) {
node := _bintree
if len(name) != 0 {
cannonicalName := strings.Replace(name, "\\", "/", -1)
pathList := strings.Split(cannonicalName, "/")
for _, p := range pathList {
node = node.Children[p]
if node == nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
}
}
if node.Func != nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
rv := make([]string, 0, len(node.Children))
for childName := range node.Children {
rv = append(rv, childName)
}
return rv, nil
}
type bintree struct {
Func func() (*asset, error)
Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
"000001_init_schema.down.sql": &bintree{_000001_init_schemaDownSql, map[string]*bintree{}},
"000001_init_schema.up.sql": &bintree{_000001_init_schemaUpSql, map[string]*bintree{}},
}}
// RestoreAsset restores an asset under the given directory
func RestoreAsset(dir, name string) error {
data, err := Asset(name)
if err != nil {
return err
}
info, err := AssetInfo(name)
if err != nil {
return err
}
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
if err != nil {
return err
}
return nil
}
// RestoreAssets restores an asset under the given directory recursively
func RestoreAssets(dir, name string) error {
children, err := AssetDir(name)
// File
if err != nil {
return RestoreAsset(dir, name)
}
// Dir
for _, child := range children {
err = RestoreAssets(dir, filepath.Join(name, child))
if err != nil {
return err
}
}
return nil
}
func _filePath(dir, name string) string {
cannonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
}
+178
View File
@@ -0,0 +1,178 @@
package database
import (
"database/sql"
"log"
"github.com/dustinpianalto/geeksbot"
)
type patreonService struct {
db *sql.DB
}
func (s patreonService) PatreonCreatorByID(id int) (geeksbot.PatreonCreator, error) {
var creator geeksbot.PatreonCreator
var gID string
queryString := "SELECT id, creator, link, guild_id FROM patreon_creator WHERE id = $1"
row := s.db.QueryRow(queryString, id)
err := row.Scan(&creator.ID, &creator.Creator, &creator.Link, &gID)
if err != nil {
return geeksbot.PatreonCreator{}, err
}
guild, err := GuildService.Guild(gID)
if err != nil {
return geeksbot.PatreonCreator{}, err
}
creator.Guild = guild
return creator, nil
}
func (s patreonService) PatreonCreatorByName(name string, g geeksbot.Guild) (geeksbot.PatreonCreator, error) {
var id int
queryString := "SELECT id FROM patreon_creator WHERE creator = $1 AND guild_id = $2"
err := s.db.QueryRow(queryString, name, g.ID).Scan(&id)
if err != nil {
return geeksbot.PatreonCreator{}, nil
}
creator, err := s.PatreonCreatorByID(id)
return creator, err
}
func (s patreonService) CreatePatreonCreator(c geeksbot.PatreonCreator) (geeksbot.PatreonCreator, error) {
var id int
queryString := `INSERT INTO patreon_creator (creator, link, guild_id) VALUES ($1, $2, $3) RETURNING id`
err := s.db.QueryRow(queryString, c.Creator, c.Link, c.Guild.ID).Scan(&id)
if err != nil {
return geeksbot.PatreonCreator{}, err
}
c.ID = id
return c, nil
}
func (s patreonService) UpdatePatreonCreator(c geeksbot.PatreonCreator) (geeksbot.PatreonCreator, error) {
queryString := `UPDATE patreon_creator SET creator = $2, link = $3 WHERE id = $1`
_, err := s.db.Exec(queryString, c.ID, c.Creator, c.Link)
return c, err
}
func (s patreonService) DeletePatreonCreator(c geeksbot.PatreonCreator) error {
queryString := `DELETE FROM patreon_creator WHERE id = $1`
_, err := s.db.Exec(queryString, c.ID)
return err
}
func (s patreonService) PatreonTierByID(id int) (geeksbot.PatreonTier, error) {
var tier geeksbot.PatreonTier
var cID int
var rID string
var next int
queryString := `SELECT id, name, description, creator, role, next_tier FROM patreon_tier WHERE id = id`
err := s.db.QueryRow(queryString, id).Scan(&tier.ID, &tier.Name, &tier.Description, &cID, &rID, &next)
if err != nil {
return geeksbot.PatreonTier{}, err
}
creator, err := s.PatreonCreatorByID(cID)
if err != nil {
return geeksbot.PatreonTier{}, err
}
tier.Creator = creator
role, err := GuildService.Role(rID)
if err != nil {
return geeksbot.PatreonTier{}, err
}
tier.Role = role
if next == -1 {
tier.NextTier = nil
return tier, nil
}
nextTier, err := s.PatreonTierByID(next)
if err != nil {
return geeksbot.PatreonTier{}, err
}
tier.NextTier = &nextTier
return tier, nil
}
func (s patreonService) PatreonTierByName(name string, creator string) (geeksbot.PatreonTier, error) {
var id int
queryString := `SELECT id FROM patreon_tier WHERE name = $1 AND creator = $2`
err := s.db.QueryRow(queryString, name, creator).Scan(&id)
if err != nil {
return geeksbot.PatreonTier{}, err
}
tier, err := s.PatreonTierByID(id)
return tier, err
}
func (s patreonService) CreatePatreonTier(t geeksbot.PatreonTier) (geeksbot.PatreonTier, error) {
var id int
queryString := `INSERT INTO patreon_tier (name, description, creator, role, next_tier)
VALUES ($1, $2, $3, $4, $5) RETURNING id`
err := s.db.QueryRow(queryString, t.Name, t.Description, t.Creator.ID, t.Role.ID, t.NextTier.ID).Scan(&id)
if err != nil {
return geeksbot.PatreonTier{}, err
}
t.ID = id
return t, nil
}
func (s patreonService) UpdatePatreonTier(t geeksbot.PatreonTier) (geeksbot.PatreonTier, error) {
queryString := `UPDATE patreon_tier SET name = $2, description = $3, role = $4, next_tier = $5 WHERE id = $1`
_, err := s.db.Exec(queryString, t.ID, t.Name, t.Description, t.Role.ID, t.NextTier.ID)
return t, err
}
func (s patreonService) DeletePatreonTier(t geeksbot.PatreonTier) error {
queryString := `DELETE FROM patreon_tier WHERE id = $1`
_, err := s.db.Exec(queryString, t.ID)
return err
}
func (s patreonService) GuildPatreonCreators(g geeksbot.Guild) ([]geeksbot.PatreonCreator, error) {
var creators []geeksbot.PatreonCreator
queryString := `SELECT id FROM patreon_creator WHERE guild_id = $1`
rows, err := s.db.Query(queryString, g.ID)
if err != nil {
return nil, err
}
for rows.Next() {
var id int
err := rows.Scan(&id)
if err != nil {
log.Println(err)
continue
}
creator, err := s.PatreonCreatorByID(id)
if err != nil {
log.Println(err)
continue
}
creators = append(creators, creator)
}
return creators, nil
}
func (s patreonService) CreatorPatreonTiers(c geeksbot.PatreonCreator) ([]geeksbot.PatreonTier, error) {
var tiers []geeksbot.PatreonTier
queryString := `SELECT id FROM patreon_tier WHERE creator = $1`
rows, err := s.db.Query(queryString, c.ID)
if err != nil {
return nil, err
}
for rows.Next() {
var id int
err := rows.Scan(&id)
if err != nil {
log.Println(err)
continue
}
tier, err := s.PatreonTierByID(id)
if err != nil {
log.Println(err)
continue
}
tiers = append(tiers, tier)
}
return tiers, nil
}
+238
View File
@@ -0,0 +1,238 @@
package database
import (
"database/sql"
"log"
"github.com/dustinpianalto/geeksbot"
)
type requestService struct {
db *sql.DB
}
func (s requestService) Request(id int64) (geeksbot.Request, error) {
var r geeksbot.Request
var aID string
var cID string
var gID string
var uID sql.NullString
var mID string
queryString := `SELECT id, author_id, channel_id, guild_id, content, requested_at, completed,
completed_at, completed_by, message_id, completed_message FROM requests
WHERE id = $1`
row := s.db.QueryRow(queryString, id)
err := row.Scan(&r.ID, &aID, &cID, &gID, &r.Content, &r.RequestedAt, &r.Completed,
&r.CompletedAt, &uID, &mID, &r.CompletedMessage)
if err != nil {
return geeksbot.Request{}, err
}
author, err := UserService.User(aID)
if err != nil {
return geeksbot.Request{}, err
}
guild, err := GuildService.Guild(gID)
if err != nil {
return geeksbot.Request{}, err
}
channel, err := ChannelService.Channel(cID)
if err != nil {
return geeksbot.Request{}, err
}
if !uID.Valid {
r.CompletedBy = nil
} else {
completedBy, err := UserService.User(uID.String)
if err != nil {
return geeksbot.Request{}, err
}
r.CompletedBy = &completedBy
}
message, err := MessageService.Message(mID)
if err != nil {
return geeksbot.Request{}, err
}
r.Author = author
r.Guild = guild
r.Channel = channel
r.Message = message
return r, nil
}
func (s requestService) UserRequests(u geeksbot.User, completed bool) ([]geeksbot.Request, error) {
var requests []geeksbot.Request
var queryString string
if completed {
queryString = "SELECT id FROM requests WHERE author_id = $1"
} else {
queryString = "SELECT id FROM requests WHERE author_id = $1 AND completed = False"
}
rows, err := s.db.Query(queryString, u.ID)
if err != nil {
return nil, err
}
for rows.Next() {
var id int64
err = rows.Scan(&id)
if err != nil {
log.Println(err)
continue
}
request, err := s.Request(id)
if err != nil {
log.Println(err)
continue
}
requests = append(requests, request)
}
return requests, nil
}
func (s requestService) GuildRequests(g geeksbot.Guild, completed bool) ([]geeksbot.Request, error) {
var requests []geeksbot.Request
var queryString string
if completed {
queryString = "SELECT id FROM requests WHERE guild_id = $1"
} else {
queryString = "SELECT id FROM requests WHERE guild_id = $1 AND completed = False"
}
rows, err := s.db.Query(queryString, g.ID)
if err != nil {
return nil, err
}
for rows.Next() {
var id int64
err = rows.Scan(&id)
if err != nil {
log.Println(err)
continue
}
request, err := s.Request(id)
if err != nil {
log.Println(err)
continue
}
requests = append(requests, request)
}
return requests, nil
}
func (s requestService) CreateRequest(r geeksbot.Request) (geeksbot.Request, error) {
queryString := `INSERT INTO requests
(author_id, channel_id, guild_id, content, requested_at,
completed, completed_at, completed_by, message_id, completed_message)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING id`
var id int64
var completedByID sql.NullString
if r.CompletedBy == nil {
completedByID.String = ""
completedByID.Valid = false
} else {
completedByID.String = r.CompletedBy.ID
completedByID.Valid = true
}
err := s.db.QueryRow(queryString,
r.Author.ID,
r.Channel.ID,
r.Guild.ID,
r.Content,
r.RequestedAt,
r.Completed,
r.CompletedAt,
completedByID,
r.Message.ID,
r.CompletedMessage).Scan(&id)
if err != nil {
return geeksbot.Request{}, err
}
r.ID = id
return r, nil
}
func (s requestService) UpdateRequest(r geeksbot.Request) (geeksbot.Request, error) {
queryString := `UPDATE requests SET
completed = $2, completed_at = $3, completed_by = $4, completed_message = $5
WHERE id = $1`
_, err := s.db.Exec(queryString, r.ID, r.Completed, r.CompletedAt, r.CompletedBy, r.CompletedMessage)
return r, err
}
func (s requestService) DeleteRequest(r geeksbot.Request) error {
queryString := "DELETE FROM requests WHERE id = $1"
_, err := s.db.Exec(queryString, r.ID)
return err
}
func (s requestService) Comment(id int64) (geeksbot.Comment, error) {
var c geeksbot.Comment
var aID string
var rID int64
queryString := "SELECT id, author_id, request_id, comment_at, content FROM comments WHERE id = $1"
row := s.db.QueryRow(queryString, id)
err := row.Scan(&c.ID, &aID, &rID, &c.CommentAt, &c.Content)
if err != nil {
return geeksbot.Comment{}, err
}
author, err := UserService.User(aID)
if err != nil {
return geeksbot.Comment{}, err
}
c.Author = author
request, err := s.Request(rID)
if err != nil {
return geeksbot.Comment{}, err
}
c.Request = request
return c, nil
}
func (s requestService) RequestComments(r geeksbot.Request) ([]geeksbot.Comment, error) {
var comments []geeksbot.Comment
queryString := "SELECT id FROM comments WHERE request_id = $1"
rows, err := s.db.Query(queryString, r.ID)
if err != nil {
return nil, err
}
for rows.Next() {
var id int64
err := rows.Scan(&id)
if err != nil {
log.Println(err)
continue
}
comment, err := s.Comment(id)
if err != nil {
log.Println(err)
continue
}
comments = append(comments, comment)
}
return comments, nil
}
func (s requestService) RequestCommentCount(r geeksbot.Request) (int, error) {
var count int
queryString := "SELECT COUNT(id) FROM comments WHERE request_id = $1"
row := s.db.QueryRow(queryString, r.ID)
err := row.Scan(&count)
return count, err
}
func (s requestService) CreateComment(c geeksbot.Comment) (geeksbot.Comment, error) {
queryString := `INSERT INTO comments (author_id, request_id, comment_at, content)
VALUES ($1, $2, $3, $4) RETURNING id`
var id int64
err := s.db.QueryRow(queryString, c.Author.ID, c.Request.ID, c.CommentAt, c.Content).Scan(&id)
if err != nil {
return geeksbot.Comment{}, err
}
c.ID = id
return c, nil
}
func (s requestService) DeleteComment(c geeksbot.Comment) error {
queryString := "DELETE FROM comments WHERE id = $1"
_, err := s.db.Exec(queryString, c.ID)
return err
}
+154
View File
@@ -0,0 +1,154 @@
package database
import (
"database/sql"
"log"
"github.com/dustinpianalto/geeksbot"
)
type serverService struct {
db *sql.DB
}
func (s serverService) ServerByID(id int) (geeksbot.Server, error) {
var server geeksbot.Server
var guildID string
var aChanID sql.NullString
var iChanID sql.NullString
var iMsgID sql.NullString
var sMsgID sql.NullString
queryString := `SELECT id, name, ip_address, port, password, alerts_channel_id,
guild_id, info_channel_id, info_message_id, settings_message_id
FROM servers WHERE id = $1`
row := s.db.QueryRow(queryString, id)
err := row.Scan(&server.ID, &server.Name, &server.IPAddr, &server.Port, &server.Password,
&aChanID, &guildID, &iChanID, &iMsgID, &sMsgID)
if err != nil {
return geeksbot.Server{}, err
}
guild, err := GuildService.Guild(guildID)
if err != nil {
return geeksbot.Server{}, err
}
if !aChanID.Valid {
server.AlertsChannel = nil
} else {
alertChannel, err := ChannelService.Channel(aChanID.String)
if err != nil {
return geeksbot.Server{}, err
}
server.AlertsChannel = &alertChannel
}
if !iChanID.Valid {
server.InfoChannel = nil
} else {
infoChannel, err := ChannelService.Channel(iChanID.String)
if err != nil {
return geeksbot.Server{}, err
}
server.InfoChannel = &infoChannel
}
if !iMsgID.Valid {
server.InfoMessage = nil
} else {
infoMessage, err := MessageService.Message(iMsgID.String)
if err != nil {
return geeksbot.Server{}, err
}
server.InfoMessage = &infoMessage
}
if !sMsgID.Valid {
server.SettingsMessage = nil
} else {
settingsMessage, err := MessageService.Message(sMsgID.String)
if err != nil {
return geeksbot.Server{}, err
}
server.SettingsMessage = &settingsMessage
}
server.Guild = guild
return server, nil
}
func (s serverService) ServerByName(name string, guild geeksbot.Guild) (geeksbot.Server, error) {
var id int
queryString := "SELECT id FROM servers WHERE name = $1 AND guild_id = $2"
row := s.db.QueryRow(queryString, name, guild.ID)
err := row.Scan(&id)
if err != nil {
return geeksbot.Server{}, err
}
server, err := s.ServerByID(id)
return server, err
}
func (s serverService) CreateServer(server geeksbot.Server) (geeksbot.Server, error) {
var id int
queryString := `INSERT INTO servers (name, ip_address, port, password, alerts_channel_id,
guild_id, info_channel_id, info_message_id, settings_message_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id`
err := s.db.QueryRow(queryString,
server.Name,
server.IPAddr,
server.Port,
server.Password,
server.AlertsChannel,
server.Guild,
server.InfoChannel,
server.InfoMessage,
server.SettingsMessage,
).Scan(&id)
if err != nil {
return geeksbot.Server{}, err
}
server.ID = id
return server, nil
}
func (s serverService) DeleteServer(server geeksbot.Server) error {
queryString := `DELETE FROM servers WHERE id = $1`
_, err := s.db.Exec(queryString, server.ID)
return err
}
func (s serverService) UpdateServer(server geeksbot.Server) (geeksbot.Server, error) {
queryString := `UPDATE servers SET name = $2, ip_address = $3, port = $4, password = $5,
alerts_channel_id = $6, info_channel_id = $7, info_message_id = $8,
settings_message_id = $9 WHERE id = $1`
_, err := s.db.Exec(queryString,
server.Name,
server.IPAddr,
server.Port,
server.Password,
server.AlertsChannel.ID,
server.InfoChannel.ID,
server.InfoMessage.ID,
server.SettingsMessage.ID,
)
return server, err
}
func (s serverService) GuildServers(g geeksbot.Guild) ([]geeksbot.Server, error) {
var servers []geeksbot.Server
queryString := `SELECT id FROM servers WHERE guild_id = $1`
rows, err := s.db.Query(queryString, g.ID)
if err != nil {
return nil, err
}
for rows.Next() {
var id int
err = rows.Scan(&id)
if err != nil {
log.Println(err)
continue
}
server, err := s.ServerByID(id)
if err != nil {
log.Println(err)
continue
}
servers = append(servers, server)
}
return servers, nil
}
+51
View File
@@ -0,0 +1,51 @@
package database
import (
"database/sql"
"github.com/dustinpianalto/geeksbot"
)
type userService struct {
db *sql.DB
}
func (s userService) User(id string) (geeksbot.User, error) {
var user geeksbot.User
queryString := "SELECT id, steam_id, active, staff, admin FROM users WHERE id = $1"
row := s.db.QueryRow(queryString, id)
err := row.Scan(&user.ID, &user.SteamID, &user.IsActive, &user.IsStaff, &user.IsAdmin)
return user, err
}
func (s userService) CreateUser(u geeksbot.User) (geeksbot.User, error) {
queryString := "INSERT INTO users (id, steam_id, active, staff, admin) VALUES ($1, $2, $3, $4, $5)"
var err error
_, err = s.db.Exec(queryString, u.ID, u.SteamID, u.IsActive, u.IsStaff, u.IsAdmin)
return u, err
}
func (s userService) DeleteUser(u geeksbot.User) error {
queryString := "DELETE FROM users WHERE id = $1"
_, err := s.db.Exec(queryString, u.ID)
return err
}
func (s userService) UpdateUser(u geeksbot.User) (geeksbot.User, error) {
queryString := "UPDATE users SET steam_id = $2, active = $3, staff = $4, admin = $5 WHERE id = $1"
_, err := s.db.Exec(queryString, u.ID, u.SteamID, u.IsActive, u.IsStaff, u.IsAdmin)
return u, err
}
func (s userService) GetOrCreateUser(id string) (geeksbot.User, error) {
user, err := s.User(id)
if err == sql.ErrNoRows {
user, err = s.CreateUser(geeksbot.User{
ID: id,
IsActive: true,
IsAdmin: false,
IsStaff: false,
})
}
return user, err
}
+26
View File
@@ -0,0 +1,26 @@
package services
import (
"github.com/dustinpianalto/geeksbot"
"github.com/dustinpianalto/geeksbot/pkg/database"
)
var (
GuildService geeksbot.GuildService
UserService geeksbot.UserService
ChannelService geeksbot.ChannelService
MessageService geeksbot.MessageService
PatreonService geeksbot.PatreonService
RequestService geeksbot.RequestService
ServerService geeksbot.ServerService
)
func InitializeServices() {
GuildService = database.GuildService
UserService = database.UserService
ChannelService = database.ChannelService
MessageService = database.MessageService
PatreonService = database.PatreonService
RequestService = database.RequestService
ServerService = database.ServerService
}
+24 -19
View File
@@ -1,37 +1,42 @@
package geeksbot
import "time"
import (
"database/sql"
"time"
)
type Request struct {
ID int64
Author *User
Channel *Channel
Author User
Channel Channel
Guild Guild
Content string
RequestedAt time.Time
CompletedAt time.Time
Completed bool
CompletedAt sql.NullTime
CompletedBy *User
Message *Message
CompletedMessage string
Message Message
CompletedMessage sql.NullString
}
type Comment struct {
ID int64
Author *User
Request *Request
Author User
Request Request
CommentAt time.Time
Content string
}
type RequestService interface {
Request(id int64) (*Request, error)
UserRequests(u *User, completed bool) ([]*Request, error)
GuildRequests(g *Guild, completed bool) ([]*Request, error)
CreateRequest(r *Request) (*Request, error)
UpdateRequest(r *Request) (*Request, error)
DeleteRequest(r *Request) error
Comment(id int64) (*Comment, error)
RequestComments(r *Request) ([]*Comment, error)
RequestCommentCount(r *Request) (int, error)
CreateComment(c *Comment) (*Comment, error)
DeleteComment(c *Comment) error
Request(id int64) (Request, error)
UserRequests(u User, completed bool) ([]Request, error)
GuildRequests(g Guild, completed bool) ([]Request, error)
CreateRequest(r Request) (Request, error)
UpdateRequest(r Request) (Request, error)
DeleteRequest(r Request) error
Comment(id int64) (Comment, error)
RequestComments(r Request) ([]Comment, error)
RequestCommentCount(r Request) (int, error)
CreateComment(c Comment) (Comment, error)
DeleteComment(c Comment) error
}
+7 -7
View File
@@ -7,17 +7,17 @@ type Server struct {
Port int
Password string
AlertsChannel *Channel
Guild *Guild
Guild Guild
InfoChannel *Channel
InfoMessage *Message
SettingsMessage *Message
}
type ServerService interface {
ServerByID(id int) (*Server, error)
ServerByName(name string) (*Server, error)
CreateServer(s *Server) (*Server, error)
DeleteServer(s *Server) error
UpdateServer(s *Server) (*Server, error)
GuildServers(g *Guild) ([]*Server, error)
ServerByID(id int) (Server, error)
ServerByName(name string, guild Guild) (Server, error)
CreateServer(s Server) (Server, error)
DeleteServer(s Server) error
UpdateServer(s Server) (Server, error)
GuildServers(g Guild) ([]Server, error)
}
+5 -4
View File
@@ -11,8 +11,9 @@ type User struct {
}
type UserService interface {
User(id string) (*User, error)
CreateUser(u *User) (*User, error)
DeleteUser(u *User) error
UpdateUser(u *User) (*User, error)
User(id string) (User, error)
CreateUser(u User) (User, error)
DeleteUser(u User) error
UpdateUser(u User) (User, error)
GetOrCreateUser(id string) (User, error)
}