Compare commits

...

94 Commits

Author SHA1 Message Date
Dustin Pianalto
940781cb83 Add pgbouncer
Some checks are pending
CI / build (push) Waiting to run
2021-10-10 21:54:49 -08:00
Dustin Pianalto
3a7bf68ba9 Update registry
Some checks are pending
CI / build (push) Waiting to run
2021-10-05 23:47:59 -08:00
Dustin Pianalto
243fa19e36 Don't run migrations
Some checks are pending
CI / build (push) Waiting to run
2021-10-02 17:56:03 -08:00
Dustin Pianalto
fcbf803ae2 Merge branch 'development'
Some checks are pending
CI / build (push) Waiting to run
2021-10-02 17:17:28 -08:00
Dustin Pianalto
47ecefb048 Update action
Some checks are pending
CI / build (push) Waiting to run
2021-10-02 16:59:49 -08:00
Dustin Pianalto
7bffb96431 Update deployment and action
Some checks are pending
CI / build (push) Waiting to run
2021-10-02 16:58:26 -08:00
Dustin Pianalto
14390c5c21 Update deployment and action
Some checks are pending
CI / build (push) Waiting to run
2021-10-02 16:42:40 -08:00
Dustin Pianalto
1e88425853 force bot to run on node with label
Some checks are pending
CI / build (push) Waiting to run
2021-07-19 13:06:16 -08:00
Dustin Pianalto
eacdd455f9 force bot to run on node with label
Some checks are pending
CI / build (push) Waiting to run
2021-07-19 12:49:57 -08:00
Dustin Pianalto
1e184c97a2 Test broadcast response
Some checks are pending
CI / build (push) Waiting to run
2021-06-30 22:00:38 -08:00
Dustin Pianalto
8c2bb50637 Test broadcast response
Some checks are pending
CI / build (push) Waiting to run
2021-06-30 21:54:35 -08:00
Dustin Pianalto
5f20f1b129 Test broadcast response
Some checks are pending
CI / build (push) Waiting to run
2021-06-30 21:46:31 -08:00
Dustin Pianalto
8a9373637f Test broadcast response
Some checks are pending
CI / build (push) Waiting to run
2021-06-30 21:10:53 -08:00
Dustin Pianalto
b1f705746e Test broadcast response
Some checks are pending
CI / build (push) Waiting to run
2021-06-30 21:00:43 -08:00
Dustin Pianalto
8893cc62f4 Test broadcast response
Some checks are pending
CI / build (push) Waiting to run
2021-06-30 20:56:51 -08:00
Dustin Pianalto
0bc5953c65 Test broadcast response
Some checks are pending
CI / build (push) Waiting to run
2021-06-30 14:51:04 -08:00
Dustin Pianalto
821ede69cf Test broadcast response
Some checks are pending
CI / build (push) Waiting to run
2021-06-30 14:34:03 -08:00
Dustin Pianalto
fe2e28357a Add broadcast command
Some checks are pending
CI / build (push) Waiting to run
2021-02-24 17:18:52 -09:00
Dustin Pianalto
b8ca9506c9 Add broadcast command
Some checks are pending
CI / build (push) Waiting to run
2021-02-24 17:09:35 -09:00
Dustin Pianalto
1d8de473c4 Add broadcast command
Some checks are pending
CI / build (push) Waiting to run
2021-02-24 16:29:42 -09:00
Dustin Pianalto
6a08f06101 Compare servernames as lower
Some checks are pending
CI / build (push) Waiting to run
2021-02-24 14:29:32 -09:00
Dustin Pianalto
dddcc8c316 Update format on listplayers output
Some checks are pending
CI / build (push) Waiting to run
2021-02-24 14:10:55 -09:00
Dustin Pianalto
5a384305b0 Add initial listplayers
Some checks are pending
CI / build (push) Waiting to run
2021-02-24 14:06:18 -09:00
Dustin Pianalto
fb5f508fdf Add initial listplayers
Some checks are pending
CI / build (push) Waiting to run
2021-02-24 14:01:20 -09:00
Dustin Pianalto
1fbe5ca7bf Add initial listplayers
Some checks are pending
CI / build (push) Waiting to run
2021-02-24 13:53:43 -09:00
Dustin Pianalto
2e0762ee0f Fix permission bug in close
Some checks are pending
CI / build (push) Waiting to run
2021-02-24 11:37:52 -09:00
Dustin Pianalto
ccb450e543 Add view command and update utils
Some checks are pending
CI / build (push) Waiting to run
2021-02-24 00:03:12 -09:00
Dustin Pianalto
c34f475084 Add view command and update utils
Some checks are pending
CI / build (push) Waiting to run
2021-02-23 23:53:28 -09:00
Dustin Pianalto
1a7d9b824f Add view command and update utils
Some checks are pending
CI / build (push) Waiting to run
2021-02-23 23:42:02 -09:00
Dustin Pianalto
0bf31a3e5d Add view command and update utils
Some checks are pending
CI / build (push) Waiting to run
2021-02-23 23:29:19 -09:00
Dustin Pianalto
128011c79a Add comment command
Some checks are pending
CI / build (push) Waiting to run
2021-02-23 21:56:10 -09:00
Dustin Pianalto
53dc44abda Fix bug when updating request
Some checks are pending
CI / build (push) Waiting to run
2021-02-23 17:28:51 -09:00
Dustin Pianalto
6262ebfeb4 Fix bug with query
Some checks are pending
CI / build (push) Waiting to run
2021-02-23 00:38:20 -09:00
Dustin Pianalto
005dfc815f Move migrations to separate func
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 23:59:13 -09:00
Dustin Pianalto
986d16b346 Add ftp credentials to domain types
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 23:24:19 -09:00
Dustin Pianalto
83c41e2788 Add ftp credentials to db schema
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 23:10:57 -09:00
Dustin Pianalto
24aff1be72 Fix request message
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 22:19:25 -09:00
Dustin Pianalto
b28beaba0c Fix request message 2021-02-22 22:18:59 -09:00
Dustin Pianalto
4f8aaff94a Fix request message 2021-02-22 22:17:18 -09:00
Dustin Pianalto
a21e884bee Fix bug getting messages from db
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 22:12:07 -09:00
Dustin Pianalto
faf64a8bf9 Add message to end of list with count
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 22:03:06 -09:00
Dustin Pianalto
2abe574977 Update database schema to not allow null previous_content
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 21:56:18 -09:00
Dustin Pianalto
04c32955c7 Update database schema to not allow null previous_content
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 21:29:41 -09:00
Dustin Pianalto
1f70318d26 Update database schema to not allow null previous_content
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 21:24:55 -09:00
Dustin Pianalto
47ed519376 Update database schema to not allow null previous_content
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 21:16:28 -09:00
Dustin Pianalto
22912c7367 Fix broken SQL query
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 20:13:29 -09:00
Dustin Pianalto
6b15540d4e Add close and list commands
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 19:59:39 -09:00
Dustin Pianalto
e526d27f4a update actions
Some checks are pending
CI / build (push) Waiting to run
2021-02-22 19:51:04 -09:00
Dustin Pianalto
68c06a7356 Add request close and list commands
Some checks are pending
CI / build (push) Waiting to run
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
Some checks are pending
CI / build (push) Waiting to run
2021-01-30 22:52:25 -09:00
Dustin Pianalto
0b8b57a884 Add sar commands
Some checks are pending
CI / build (push) Waiting to run
2021-01-30 22:42:14 -09:00
Dustin Pianalto
9382798997 Add sar commands
Some checks are pending
CI / build (push) Waiting to run
2021-01-30 22:31:22 -09:00
Dustin Pianalto
24448c79f5 Add sar commands
Some checks are pending
CI / build (push) Waiting to run
2021-01-30 22:17:01 -09:00
Dustin Pianalto
71aac148e0 remove mod/admin role command
Some checks are pending
CI / build (push) Waiting to run
2021-01-26 00:08:20 -09:00
Dustin Pianalto
132bf94332 remove mod/admin role command
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 23:53:32 -09:00
Dustin Pianalto
964be05c48 remove mod/admin role command
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 23:49:58 -09:00
Dustin Pianalto
4895294969 fix role commands
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 23:09:21 -09:00
Dustin Pianalto
9d0d1ddd56 fix role commands
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 23:04:43 -09:00
Dustin Pianalto
a587a64bd9 fix role commands
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 23:01:02 -09:00
Dustin Pianalto
53276a1442 add admin role command
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 22:41:51 -09:00
Dustin Pianalto
cdbeac195f add moderator role command
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 22:21:56 -09:00
Dustin Pianalto
8256b596ff add moderator role command
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 21:52:12 -09:00
Dustin Pianalto
9e1702fa4b fix create request command
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 02:31:36 -09:00
Dustin Pianalto
b6f90b61c5 fix create request command
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 02:27:56 -09:00
Dustin Pianalto
764ceb79ec fix create request sql query
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 02:20:11 -09:00
Dustin Pianalto
e89805bf8e fix create channel sql query
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 02:11:28 -09:00
Dustin Pianalto
cb7c487b42 fix create channel sql query
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 02:05:13 -09:00
Dustin Pianalto
e1ea9cab1f fix create channel sql query
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 01:59:57 -09:00
Dustin Pianalto
a6dc6f5e56 fix get user sql query
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 01:52:14 -09:00
Dustin Pianalto
203d1bbf69 fix get user sql query
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 01:43:31 -09:00
Dustin Pianalto
c504f7b165 fix get user sql query
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 01:38:22 -09:00
Dustin Pianalto
34564140f5 add request command
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 01:33:46 -09:00
Dustin Pianalto
e3ccc56dba add request command
Some checks are pending
CI / build (push) Waiting to run
2021-01-25 01:21:49 -09:00
Dustin Pianalto
e19f987c4e add request command
Some checks are pending
CI / build (push) Waiting to run
2021-01-24 22:57:55 -09:00
Dustin Pianalto
552664268b use custom prefixes
Some checks are pending
CI / build (push) Waiting to run
2021-01-24 01:11:22 -09:00
Dustin Pianalto
414757188e remove duplicate prefixes
Some checks are pending
CI / build (push) Waiting to run
2021-01-24 01:05:16 -09:00
Dustin Pianalto
888d356b67 debug removing prefix
Some checks are pending
CI / build (push) Waiting to run
2021-01-24 00:57:00 -09:00
Dustin Pianalto
c776b25899 debug removing prefix
Some checks are pending
CI / build (push) Waiting to run
2021-01-24 00:53:04 -09:00
Dustin Pianalto
81f6e23487 Fix array in guild service
Some checks are pending
CI / build (push) Waiting to run
2021-01-24 00:46:41 -09:00
Dustin Pianalto
6cf574b22d Add prefix commands
Some checks are pending
CI / build (push) Waiting to run
2021-01-24 00:40:02 -09:00
Dustin Pianalto
623df1d55a Add prefix commands
Some checks are pending
CI / build (push) Waiting to run
2021-01-24 00:26:34 -09:00
Dustin Pianalto
489d96594c Add prefix commands
Some checks are pending
CI / build (push) Waiting to run
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
Some checks are pending
CI / build (push) Waiting to run
2021-01-23 16:05:02 -09:00
Dustin Pianalto
96e8388562 fix bug in user database
Some checks are pending
CI / build (push) Waiting to run
2021-01-23 15:10:04 -09:00
Dustin Pianalto
6369f37ce5 fix bug in user service
Some checks are pending
CI / build (push) Waiting to run
2021-01-23 15:03:15 -09:00
Dustin Pianalto
ab2d51c582 fix bug in user service
Some checks are pending
CI / build (push) Waiting to run
2021-01-23 14:59:35 -09:00
Dustin Pianalto
5400d6acd9 fix bug in user service
Some checks are pending
CI / build (push) Waiting to run
2021-01-23 14:48:59 -09:00
Dustin Pianalto
74edd574b3 fix bug in user service
Some checks are pending
CI / build (push) Waiting to run
2021-01-23 14:46:25 -09:00
Dustin Pianalto
266cde6468 fix bug in running migrations
Some checks are pending
CI / build (push) Waiting to run
2021-01-23 04:27:34 -09:00
Dustin Pianalto
8b646731ee change test command name
Some checks are pending
CI / build (push) Waiting to run
2021-01-23 04:20:17 -09:00
45 changed files with 1681 additions and 93 deletions

View File

@ -20,39 +20,45 @@ jobs:
- name: Get Version
id: get_version
uses: battila7/get-version-action@v2.0.0
- name: install buildx
id: buildx
uses: crazy-max/ghaction-docker-buildx@v1
with:
version: latest
- 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/internal/database/migrations/ -o $GITHUB_WORKSPACE/internal/database/migrations/bindata.go $GITHUB_WORKSPACE/internal/database/migrations/
head $GITHUB_WORKSPACE/internal/database/migrations/bindata.go
- name: Docker Login
# You may pin to the exact commit or the version.
# uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
uses: docker/login-action@v1.10.0
with:
registry: ${{ secrets.DR_URL }}
# Username used to log against the Docker registry
username: ${{ secrets.DH_USERNAME }}
# Password or personal access token used to log against the Docker registry
password: ${{ secrets.DH_PASSWORD }}
# Log out from the Docker registry at the end of a job
logout: true
- name: Build container image
- name: Docker Build & Push
env:
IMAGE_TAG: ${{ steps.get_version.outputs.version-without-v }}
run: docker build -t registry.digitalocean.com/djpianalto/geeksbot:$IMAGE_TAG .
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Login to DigitalOcean Container Registry with short-lived credentials
run: doctl registry login --expiry-seconds 600
- name: Push image to DigitalOcean Container Registry
run: docker push registry.digitalocean.com/djpianalto/geeksbot
run: |
docker buildx build --push \
--tag ${{ secrets.DR_URL }}/geeksbot:$IMAGE_TAG \
--platform linux/amd64,linux/arm/v7,linux/arm64 .
- 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
run: TAG=${{ steps.get_version.outputs.version-without-v }} && sed -i 's|<IMAGE>|${{ secrets.DR_URL }}/geeksbot:'${TAG}'|' $GITHUB_WORKSPACE/deployment.yml
- name: Save DigitalOcean kubeconfig with short-lived credentials
run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 discord-bots
- uses: azure/k8s-set-context@v1
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBE_CONFIG }}
id: setcontext
- name: Deploy to DigitalOcean Kubernetes
- name: Deploy to Kubernetes
run: kubectl apply -f $GITHUB_WORKSPACE/deployment.yml
- name: Verify deployment
run: kubectl rollout status deployment/geeksbot
run: kubectl rollout status -n discord-bots deployment/geeksbot

View File

@ -14,4 +14,5 @@ type ChannelService interface {
DeleteChannel(c Channel) error
GuildChannels(g Guild) ([]Channel, error)
UpdateChannel(c Channel) (Channel, error)
GetOrCreateChannel(id string, guild_id string) (Channel, error)
}

View File

@ -8,9 +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/internal/services"
"github.com/dustinpianalto/geeksbot/pkg/database"
"github.com/dustinpianalto/geeksbot/pkg/services"
)
func main() {
@ -28,6 +28,7 @@ func main() {
}
database.ConnectDatabase(os.Getenv("DATABASE_URL"))
//database.RunMigrations()
services.InitializeServices()
owners := []string{
@ -72,7 +73,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) {

View File

@ -2,7 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: geeksbot
namespace: default
namespace: discord-bots
labels:
app: geeksbot
spec:
@ -21,8 +21,42 @@ spec:
app: geeksbot
spec:
containers:
- name: pgbouncer
image: timoha/pgbouncer:1.15.0
resources:
requests:
memory: "256Mi"
cpu: "0.5"
limits:
memory: "512Mi"
cpu: "1"
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: geeksbot
key: pgbouncer_url
- name: SERVER_TLS_SSLMODE
valueFrom:
secretKeyRef:
name: geeksbot
key: pgbouncer_ssl
- name: AUTH_TYPE
valueFrom:
secretKeyRef:
name: geeksbot
key: pgbouncer_auth
ports:
- containerPort: 5432
- name: geeksbot
image: <IMAGE>
resources:
requests:
memory: "512Mi"
cpu: "1"
limits:
memory: "1Gi"
cpu: "2"
env:
- name: DATABASE_URL
valueFrom:
@ -34,3 +68,5 @@ spec:
secretKeyRef:
name: geeksbot
key: discord_token
imagePullSecrets:
- name: registry-1

2
go.mod
View File

@ -8,5 +8,7 @@ require (
github.com/go-bindata/go-bindata v3.1.2+incompatible // indirect
github.com/golang-migrate/migrate v3.5.4+incompatible // indirect
github.com/golang-migrate/migrate/v4 v4.14.1
github.com/gorcon/rcon v1.3.1
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/lib/pq v1.8.0
)

2
go.sum
View File

@ -152,6 +152,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorcon/rcon v1.3.1 h1:z6a5iOlojfdkvA1qaKEng7QfCJuCzYlC9BUDs6/M+74=
github.com/gorcon/rcon v1.3.1/go.mod h1:2gztBPSV2WxkPkqV4jiJkdHs+NT46mNSGb8JxbPesx4=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=

View File

@ -1,8 +1,10 @@
package geeksbot
import "database/sql"
type Guild struct {
ID string
NewPatronMessage string
NewPatronMessage sql.NullString
Prefixes []string
}
@ -22,4 +24,6 @@ type GuildService interface {
Role(id string) (Role, error)
UpdateRole(r Role) (Role, error)
DeleteRole(r Role) error
GetOrCreateGuild(id string) (Guild, error)
CreateOrUpdateRole(r Role) (Role, error)
}

View File

@ -0,0 +1,11 @@
package discord_utils
import "github.com/dustinpianalto/disgoman"
func GetChannelName(ctx disgoman.Context, id string) string {
channel, err := ctx.Session.Channel(id)
if err != nil {
return ""
}
return channel.Name
}

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
}

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,
}
}

View File

@ -0,0 +1,14 @@
package discord_utils
import "github.com/dustinpianalto/disgoman"
func GetDisplayName(ctx disgoman.Context, id string) string {
member, err := ctx.Session.GuildMember(ctx.Guild.ID, id)
if err != nil {
return ""
}
if member.Nick != "" {
return member.Nick
}
return member.User.Username
}

View File

@ -0,0 +1,184 @@
package arcon
import (
"fmt"
"log"
"strings"
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/geeksbot"
"github.com/dustinpianalto/geeksbot/internal/discord_utils"
"github.com/dustinpianalto/geeksbot/pkg/services"
"github.com/gorcon/rcon"
)
var ListplayersCommand = &disgoman.Command{
Name: "listplayers",
Aliases: nil,
Description: "List the players currently connected to a ARK server.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: listplayersCommandFunc,
}
func listplayersCommandFunc(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
}
author, err := services.UserService.GetOrCreateUser(ctx.Message.Author.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Sorry, there was a problem getting your user.", err)
return
}
if !discord_utils.IsGuildAdmin(ctx, author) && !discord_utils.IsGuildMod(ctx, author) {
return
}
if len(args) == 0 {
servers, err := services.ServerService.GuildServers(guild)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Could not find any servers for this guild", err)
return
}
for _, server := range servers {
go listplayers(ctx, server)
}
return
}
serverName := strings.Join(args, " ")
server, err := services.ServerService.ServerByName(serverName, guild)
if err != nil {
discord_utils.SendErrorMessage(ctx,
fmt.Sprintf("Could not find **%s** in this guild.", serverName),
err,
)
return
}
listplayers(ctx, server)
}
func listplayers(ctx disgoman.Context, server geeksbot.Server) {
msg, err := ctx.Send(fmt.Sprintf("**Getting data for %s**", server.Name))
if err != nil {
discord_utils.SendErrorMessage(ctx, "There was an error getting the player list", err)
return
}
conn, err := rcon.Dial(fmt.Sprintf("%s:%d", server.IPAddr, server.Port), server.Password)
if err != nil {
_, _ = ctx.Session.ChannelMessageEdit(ctx.Channel.ID, msg.ID,
fmt.Sprintf("**Could not open connection to %s**", server.Name),
)
return
}
defer conn.Close()
response, err := conn.Execute("listplayers")
if err != nil {
_, _ = ctx.Session.ChannelMessageEdit(ctx.Channel.ID, msg.ID,
fmt.Sprintf("**There was a problem getting a response from %s**", server.Name),
)
return
}
if strings.HasPrefix(response, "No Players") {
_, _ = ctx.Session.ChannelMessageEdit(ctx.Channel.ID, msg.ID,
fmt.Sprintf("**%s: %s**", server.Name, response),
)
return
}
players := strings.Split(response, "\n")
for i, player := range players {
parts := strings.Split(player, ", ")
steamID := parts[len(parts)-1]
user, err := services.UserService.GetBySteamID(steamID)
if err == nil {
duser, err := ctx.Session.GuildMember(ctx.Guild.ID, user.ID)
if err == nil {
players[i] = fmt.Sprintf("%s (%s)", player, duser.Mention())
}
}
}
_, _ = ctx.Session.ChannelMessageEdit(ctx.Channel.ID, msg.ID,
fmt.Sprintf("**%s:**%s", server.Name, strings.Join(players, "\n")),
)
}
var BroadcastCommand = &disgoman.Command{
Name: "broadcast",
Aliases: nil,
Description: "Broadcast a message to ARK servers.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: broadcastCommandFunc,
}
func broadcastCommandFunc(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
}
author, err := services.UserService.GetOrCreateUser(ctx.Message.Author.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Sorry, there was a problem getting your user.", err)
return
}
if !discord_utils.IsGuildAdmin(ctx, author) && !discord_utils.IsGuildMod(ctx, author) {
return
}
message := strings.Join(args[1:len(args)], " ")
if strings.ToLower(args[0]) == "all" {
servers, err := services.ServerService.GuildServers(guild)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Could not find any servers for this guild", err)
return
}
for _, server := range servers {
go broadcast(ctx, server, message)
}
return
} else {
serverName := strings.Title(strings.ReplaceAll(args[0], "_", " "))
server, err := services.ServerService.ServerByName(serverName, guild)
if err != nil {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("Could not find %s", serverName), err)
return
}
broadcast(ctx, server, message)
}
}
func broadcast(ctx disgoman.Context, server geeksbot.Server, message string) {
msg, err := ctx.Send(fmt.Sprintf("**Broadcasting to: %s**", server.Name))
if err != nil {
discord_utils.SendErrorMessage(ctx, "There was an error getting the player list", err)
return
}
conn, err := rcon.Dial(fmt.Sprintf("%s:%d", server.IPAddr, server.Port), server.Password)
if err != nil {
_, _ = ctx.Session.ChannelMessageEdit(ctx.Channel.ID, msg.ID,
fmt.Sprintf("**Could not open connection to %s**", server.Name),
)
return
}
defer conn.Close()
userName := discord_utils.GetDisplayName(ctx, ctx.Message.Author.ID)
response, err := conn.Execute(fmt.Sprintf("broadcast %s: %s", userName, message))
if err != nil {
_, _ = ctx.Session.ChannelMessageEdit(ctx.Channel.ID, msg.ID,
fmt.Sprintf("**There was a problem getting a response from %s**", server.Name),
)
return
}
log.Printf("%T - %#v", response, response)
if strings.Contains(response, "Server received, But no response!!") {
_, _ = ctx.Session.ChannelMessageEdit(ctx.Channel.ID, msg.ID,
fmt.Sprintf("**%s Broadcast Successful**", server.Name),
)
return
}
_, _ = ctx.Session.ChannelMessageEdit(ctx.Channel.ID, msg.ID,
fmt.Sprintf("**Broadcasting to %s Failed!**", server.Name),
)
}

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)
}
}

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
}

View File

@ -2,6 +2,9 @@ package exts
import (
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/geeksbot/internal/exts/arcon"
"github.com/dustinpianalto/geeksbot/internal/exts/guild"
"github.com/dustinpianalto/geeksbot/internal/exts/requests"
"github.com/dustinpianalto/geeksbot/internal/exts/utils"
)
@ -20,4 +23,20 @@ func AddCommandHandlers(g *disgoman.CommandManager) {
_ = 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)
_ = g.AddCommand(requests.ViewCommand)
_ = g.AddCommand(requests.CommentCommand)
_ = g.AddCommand(arcon.ListplayersCommand)
_ = g.AddCommand(arcon.BroadcastCommand)
}

View File

@ -0,0 +1,449 @@
package requests
import (
"fmt"
"log"
"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\n"+
"%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)
}
dmChannel, err := ctx.Session.UserChannelCreate(request.Author.ID)
if err != nil {
return
}
_, _ = ctx.Session.ChannelMessageSend(dmChannel.ID,
fmt.Sprintf("%s has closed request %d which you opened in the %s channel.\n```%s```\n",
discord_utils.GetDisplayName(ctx, request.CompletedBy.ID),
request.ID,
discord_utils.GetChannelName(ctx, request.Channel.ID),
request.Content,
))
}
}
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
}
commentCount, err := services.RequestService.RequestCommentCount(request)
if err != nil {
commentCount = 0
}
_, _ = ctx.Send(fmt.Sprintf("```md\n"+
"< Request ID Requested By >\n"+
"< %-11d %23s >\n"+
"%s\n\n"+
"Comments: %d\n"+
"Requested At: %s\n"+
"In: %s\n"+
"```",
request.ID,
authorName,
request.Content,
commentCount,
request.RequestedAt.Format("2006-01-02 15:04:05 MST"),
channelName,
))
}
_, _ = ctx.Send(fmt.Sprintf("```There %s currently %d open %s```", utils.PluralizeString("is", len(requests)), len(requests), utils.PluralizeString("request", len(requests))))
}
var CommentCommand = &disgoman.Command{
Name: "comment",
Aliases: []string{"update", "add_comment"},
Description: "Add a comment to an existing request.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: commentCommandFunc,
}
func commentCommandFunc(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
}
id, err := strconv.ParseInt(args[0], 10, 64)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Please include the ID of the request to update.", err)
return
}
message := strings.Join(args[1:len(args)], " ")
author, err := services.UserService.GetOrCreateUser(ctx.Message.Author.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Sorry, there was an issue finding your user account", err)
return
}
request, err := services.RequestService.Request(id)
if err != nil || request.Guild.ID != guild.ID {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%d is not a valid request for this guild", id), err)
return
}
int64ID, _ := strconv.ParseInt(ctx.Message.ID, 10, 64)
s := discord_utils.ParseSnowflake(int64ID)
comment := geeksbot.Comment{
Author: author,
Request: request,
CommentAt: s.CreationTime,
Content: message,
}
comment, err = services.RequestService.CreateComment(comment)
if err != nil {
discord_utils.SendErrorMessage(ctx, "There was a problem adding your comment", err)
return
}
channels, err := services.ChannelService.GuildChannels(guild)
if err == nil {
comments, _ := services.RequestService.RequestComments(request)
var commentString string
var commentStrings []string
commentString = fmt.Sprintf("Comment added:\n```md\n"+
"< Request ID Requested By >\n"+
"< %-11d %23s >\n"+
"%s\n\n"+
"Comments: Not Implemented Yet\n"+
"Requested At: %s\n"+
"In: %s\n"+
"```",
request.ID,
discord_utils.GetDisplayName(ctx, request.Author.ID),
request.Content,
request.RequestedAt.Format("2006-01-02 15:04:05"),
discord_utils.GetChannelName(ctx, request.Channel.ID),
)
for _, c := range comments {
if err != nil {
log.Println(err)
continue
}
cs := fmt.Sprintf("```md\n%s\n- %s At %s\n```\n",
c.Content,
discord_utils.GetDisplayName(ctx, c.Author.ID),
c.CommentAt.Format("2006-01-02 15:04:05"),
)
if len(commentString+cs) >= 2000 {
commentStrings = append(commentStrings, commentString)
commentString = ""
}
commentString += cs
}
commentStrings = append(commentStrings, commentString)
for _, c := range channels {
if c.Admin {
for _, s := range commentStrings {
_, _ = ctx.Session.ChannelMessageSend(c.ID, s)
}
}
}
} else {
log.Println(err)
}
_, err = ctx.Send(fmt.Sprintf("%s your comment has been added.", ctx.Message.Author.Mention()))
dmChannel, err := ctx.Session.UserChannelCreate(request.Author.ID)
if err != nil {
return
}
_, _ = ctx.Session.ChannelMessageSend(dmChannel.ID,
fmt.Sprintf("%s has add a comment to request %d which you opened in the %s channel.\n```%s```\n```%s```",
discord_utils.GetDisplayName(ctx, author.ID),
request.ID,
discord_utils.GetChannelName(ctx, ctx.Channel.ID),
request.Content,
message,
))
}
var ViewCommand = &disgoman.Command{
Name: "view",
Aliases: nil,
Description: "View the details about a request.",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: viewCommandFunc,
}
func viewCommandFunc(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
}
id, err := strconv.ParseInt(args[0], 10, 64)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Please include the ID of the request to view.", err)
return
}
request, err := services.RequestService.Request(id)
if err != nil || request.Guild.ID != guild.ID {
discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%d is not a valid request in this guild", id), err)
return
}
requestor, err := services.UserService.GetOrCreateUser(ctx.Message.Author.ID)
if err != nil {
discord_utils.SendErrorMessage(ctx, "Sorry, there was an issue finding your user account", err)
return
}
if request.Author.ID != ctx.Message.Author.ID &&
!discord_utils.IsGuildMod(ctx, requestor) &&
!discord_utils.IsGuildAdmin(ctx, requestor) {
discord_utils.SendErrorMessage(ctx, "You are not authorized to view that request", nil)
return
}
comments, err := services.RequestService.RequestComments(request)
if err != nil {
discord_utils.SendErrorMessage(ctx, "There was an error getting the comments.", err)
}
var commentString string
var commentStrings []string
commentString = fmt.Sprintf("```md\n"+
"< Request ID Requested By >\n"+
"< %-11d %23s >\n"+
"%s\n\n"+
"Requested At: %s\n"+
"In: %s\n"+
"```",
request.ID,
discord_utils.GetDisplayName(ctx, request.Author.ID),
request.Content,
request.RequestedAt.Format("2006-01-02 15:04:05"),
discord_utils.GetChannelName(ctx, request.Channel.ID),
)
for _, c := range comments {
cs := fmt.Sprintf("```md\n%s\n- %s At %s\n```\n",
c.Content,
discord_utils.GetDisplayName(ctx, c.Author.ID),
c.CommentAt.Format("2006-01-02 15:04:05"),
)
if len(commentString+cs) >= 2000 {
commentStrings = append(commentStrings, commentString)
commentString = ""
}
commentString += cs
}
commentStrings = append(commentStrings, commentString)
for _, c := range commentStrings {
_, _ = ctx.Send(c)
}
}

View File

@ -11,7 +11,7 @@ import (
"github.com/dustinpianalto/disgoman"
"github.com/dustinpianalto/geeksbot"
"github.com/dustinpianalto/geeksbot/internal/discord_utils"
"github.com/dustinpianalto/geeksbot/internal/services"
"github.com/dustinpianalto/geeksbot/pkg/services"
)
var PingCommand = &disgoman.Command{
@ -250,7 +250,7 @@ func userCommandFunc(ctx disgoman.Context, args []string) {
}
var AddUserCommand = &disgoman.Command{
Name: "user",
Name: "adduser",
Aliases: nil,
Description: "Get user info",
OwnerOnly: false,

24
internal/utils/utils.go Normal file
View File

@ -0,0 +1,24 @@
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
}
if s == "is" {
return "are"
}
return s + "s"
}

View File

@ -1,9 +1,14 @@
package geeksbot
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

View File

@ -1,5 +1,7 @@
package geeksbot
import "database/sql"
type PatreonCreator struct {
ID int
Creator string
@ -10,7 +12,7 @@ type PatreonCreator struct {
type PatreonTier struct {
ID int
Name string
Description string
Description sql.NullString
Creator PatreonCreator
Role Role
NextTier *PatreonTier

View File

@ -29,7 +29,7 @@ func (s channelService) Channel(id string) (geeksbot.Channel, error) {
}
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))"
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
}
@ -66,3 +66,22 @@ func (s channelService) GuildChannels(g geeksbot.Guild) ([]geeksbot.Channel, err
}
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
}

View File

@ -5,7 +5,7 @@ import (
"fmt"
"log"
"github.com/dustinpianalto/geeksbot/internal/database/migrations"
"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"
@ -23,11 +23,8 @@ var (
)
func ConnectDatabase(dbConnString string) {
s := bindata.Resource(migrations.AssetNames(),
func(name string) ([]byte, error) {
return migrations.Asset(name)
})
db, err := sql.Open("postgres", dbConnString)
var err error
db, err = sql.Open("postgres", dbConnString)
if err != nil {
log.Fatal(fmt.Errorf("Can't connect to the database: %w", err))
}
@ -35,6 +32,15 @@ func ConnectDatabase(dbConnString string) {
db.SetMaxOpenConns(75)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(300)
initServices()
log.Println("Services Initialized")
}
func RunMigrations() {
s := bindata.Resource(migrations.AssetNames(),
func(name string) ([]byte, error) {
return migrations.Asset(name)
})
d, err := bindata.WithInstance(s)
if err != nil {
log.Fatal(fmt.Errorf("cannot load migrations: %w", err))
@ -49,11 +55,14 @@ func ConnectDatabase(dbConnString string) {
}
err = m.Up()
if err != nil {
log.Fatal(err)
if err.Error() == "no change" {
log.Println(err)
} else {
log.Fatal(err)
}
}
log.Println("Migrations Run")
initServices()
log.Println("Services Initialized")
}
func initServices() {

View File

@ -5,6 +5,7 @@ import (
"log"
"github.com/dustinpianalto/geeksbot"
"github.com/lib/pq"
)
type guildService struct {
@ -15,7 +16,7 @@ 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, &g.Prefixes)
err := row.Scan(&g.ID, &g.NewPatronMessage, pq.Array(&g.Prefixes))
if err != nil {
return geeksbot.Guild{}, err
}
@ -24,7 +25,7 @@ func (s guildService) Guild(id string) (geeksbot.Guild, error) {
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, g.Prefixes)
_, err := s.db.Exec(queryString, g.ID, g.NewPatronMessage, pq.Array(g.Prefixes))
return g, err
}
@ -36,7 +37,7 @@ func (s guildService) DeleteGuild(g geeksbot.Guild) error {
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, g.Prefixes)
_, err := s.db.Exec(queryString, g.ID, g.NewPatronMessage, pq.Array(g.Prefixes))
return g, err
}
@ -98,3 +99,23 @@ func (s guildService) DeleteRole(r geeksbot.Role) error {
_, 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
}

View File

@ -5,6 +5,7 @@ import (
"log"
"github.com/dustinpianalto/geeksbot"
"github.com/lib/pq"
)
type messageService struct {
@ -21,7 +22,7 @@ func (s messageService) Message(id string) (geeksbot.Message, error) {
WHERE m.id = $1`
row := s.db.QueryRow(queryString, id)
err := row.Scan(&m.ID, &m.CreatedAt, &m.ModifiedAt, &m.Content,
&m.PreviousContent, &channel_id, &author_id)
pq.Array(&m.PreviousContent), &channel_id, &author_id)
if err != nil {
return geeksbot.Message{}, err
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1 @@
ALTER TYPE role_type ADD VALUE 'sar';

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,6 @@
BEGIN;
ALTER TABLE servers
DROP COLUMN ftp_port,
DROP COLUMN ftp_username,
DROP COLUMN ftp_password;
COMMIT;

View File

@ -0,0 +1,6 @@
BEGIN;
ALTER TABLE servers
ADD COLUMN ftp_port int4,
ADD COLUMN ftp_username varchar(200),
ADD COLUMN ftp_password varchar(200);
COMMIT;

View File

@ -16,10 +16,10 @@ func (s requestService) Request(id int64) (geeksbot.Request, error) {
var aID string
var cID string
var gID string
var uID 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
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,
@ -39,9 +39,14 @@ func (s requestService) Request(id int64) (geeksbot.Request, error) {
if err != nil {
return geeksbot.Request{}, err
}
completedBy, err := UserService.User(uID)
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 {
@ -50,7 +55,6 @@ func (s requestService) Request(id int64) (geeksbot.Request, error) {
r.Author = author
r.Guild = guild
r.Channel = channel
r.CompletedBy = completedBy
r.Message = message
return r, nil
}
@ -120,6 +124,14 @@ func (s requestService) CreateRequest(r geeksbot.Request) (geeksbot.Request, err
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,
@ -128,7 +140,7 @@ func (s requestService) CreateRequest(r geeksbot.Request) (geeksbot.Request, err
r.RequestedAt,
r.Completed,
r.CompletedAt,
r.CompletedBy.ID,
completedByID,
r.Message.ID,
r.CompletedMessage).Scan(&id)
if err != nil {
@ -142,7 +154,7 @@ func (s requestService) UpdateRequest(r geeksbot.Request) (geeksbot.Request, err
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)
_, err := s.db.Exec(queryString, r.ID, r.Completed, r.CompletedAt, r.CompletedBy.ID, r.CompletedMessage)
return r, err
}
@ -156,7 +168,7 @@ 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 WHERE id = $1"
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 {

View File

@ -14,16 +14,17 @@ type serverService struct {
func (s serverService) ServerByID(id int) (geeksbot.Server, error) {
var server geeksbot.Server
var guildID string
var aChanID string
var iChanID string
var iMsgID string
var sMsgID 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
guild_id, info_channel_id, info_message_id, settings_message_id,
ftp_port, ftp_username, ftp_password
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)
&aChanID, &guildID, &iChanID, &iMsgID, &sMsgID, &server.FTPPort, &server.FTPUser, &server.FTPPass)
if err != nil {
return geeksbot.Server{}, err
}
@ -31,33 +32,49 @@ func (s serverService) ServerByID(id int) (geeksbot.Server, error) {
if err != nil {
return geeksbot.Server{}, err
}
alertChannel, err := ChannelService.Channel(aChanID)
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
}
infoChannel, err := ChannelService.Channel(iChanID)
if err != nil {
return geeksbot.Server{}, err
if !iChanID.Valid {
server.InfoChannel = nil
} else {
infoChannel, err := ChannelService.Channel(iChanID.String)
if err != nil {
return geeksbot.Server{}, err
}
server.InfoChannel = &infoChannel
}
infoMessage, err := MessageService.Message(iMsgID)
if err != nil {
return geeksbot.Server{}, err
if !iMsgID.Valid {
server.InfoMessage = nil
} else {
infoMessage, err := MessageService.Message(iMsgID.String)
if err != nil {
return geeksbot.Server{}, err
}
server.InfoMessage = &infoMessage
}
settingsMessage, err := MessageService.Message(sMsgID)
if err != nil {
return geeksbot.Server{}, err
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
server.AlertsChannel = alertChannel
server.InfoChannel = infoChannel
server.InfoMessage = infoMessage
server.SettingsMessage = settingsMessage
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"
queryString := "SELECT id FROM servers WHERE LOWER(name) = LOWER($1) AND guild_id = $2"
row := s.db.QueryRow(queryString, name, guild.ID)
err := row.Scan(&id)
if err != nil {
@ -99,7 +116,8 @@ func (s serverService) DeleteServer(server geeksbot.Server) error {
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`
settings_message_id = $9, ftp_port = $10, ftp_username = $11,
ftp_password = $12 WHERE id = $1`
_, err := s.db.Exec(queryString,
server.Name,
server.IPAddr,
@ -109,6 +127,9 @@ func (s serverService) UpdateServer(server geeksbot.Server) (geeksbot.Server, er
server.InfoChannel.ID,
server.InfoMessage.ID,
server.SettingsMessage.ID,
server.FTPPort,
server.FTPUser,
server.FTPPass,
)
return server, err
}

View File

@ -12,7 +12,7 @@ type userService struct {
func (s userService) User(id string) (geeksbot.User, error) {
var user geeksbot.User
queryString := "SELECT id, steam_id, active, staff, admin WHERE id = $1"
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
@ -20,7 +20,8 @@ func (s userService) User(id string) (geeksbot.User, error) {
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)"
_, err := s.db.Exec(queryString, u.ID, u.SteamID, u.IsActive, u.IsStaff, u.IsAdmin)
var err error
_, err = s.db.Exec(queryString, u.ID, u.SteamID, u.IsActive, u.IsStaff, u.IsAdmin)
return u, err
}
@ -35,3 +36,27 @@ func (s userService) UpdateUser(u geeksbot.User) (geeksbot.User, error) {
_, 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
}
func (s userService) GetBySteamID(steamID string) (geeksbot.User, error) {
var id string
queryString := "SELECT id FROM users WHERE steam_id = $1"
err := s.db.QueryRow(queryString, steamID).Scan(&id)
if err != nil {
return geeksbot.User{}, err
}
user, err := s.User(id)
return user, err
}

View File

@ -2,7 +2,7 @@ package services
import (
"github.com/dustinpianalto/geeksbot"
"github.com/dustinpianalto/geeksbot/internal/database"
"github.com/dustinpianalto/geeksbot/pkg/database"
)
var (

View File

@ -1,6 +1,9 @@
package geeksbot
import "time"
import (
"database/sql"
"time"
)
type Request struct {
ID int64
@ -10,10 +13,10 @@ type Request struct {
Content string
RequestedAt time.Time
Completed bool
CompletedAt time.Time
CompletedBy User
CompletedAt sql.NullTime
CompletedBy *User
Message Message
CompletedMessage string
CompletedMessage sql.NullString
}
type Comment struct {

View File

@ -6,11 +6,14 @@ type Server struct {
IPAddr string
Port int
Password string
AlertsChannel Channel
AlertsChannel *Channel
Guild Guild
InfoChannel Channel
InfoMessage Message
SettingsMessage Message
InfoChannel *Channel
InfoMessage *Message
SettingsMessage *Message
FTPPort int
FTPUser string
FTPPass string
}
type ServerService interface {

View File

@ -15,4 +15,6 @@ type UserService interface {
CreateUser(u User) (User, error)
DeleteUser(u User) error
UpdateUser(u User) (User, error)
GetOrCreateUser(id string) (User, error)
GetBySteamID(steamID string) (User, error)
}