Compare commits
No commits in common. 'master' and 'release-1.0.0' have entirely different histories.
master
...
release-1.
@ -1,64 +0,0 @@
|
|||||||
name: CI
|
|
||||||
|
|
||||||
# Controls when the action will run. Triggers the workflow on push to master or development
|
|
||||||
# with a tag like v1.0.0 or v1.0.0-dev
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- v[0-9]+.[0-9]+.[0-9]+
|
|
||||||
- v[0-9]+.[0-9]+.[0-9]+-[a-zA-Z]+
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
|
||||||
steps:
|
|
||||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- 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: 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: Docker Build & Push
|
|
||||||
env:
|
|
||||||
IMAGE_TAG: ${{ steps.get_version.outputs.version-without-v }}
|
|
||||||
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>|${{ secrets.DR_URL }}/geeksbot:'${TAG}'|' $GITHUB_WORKSPACE/deployment.yml
|
|
||||||
|
|
||||||
- uses: azure/k8s-set-context@v1
|
|
||||||
with:
|
|
||||||
method: kubeconfig
|
|
||||||
kubeconfig: ${{ secrets.KUBE_CONFIG }}
|
|
||||||
id: setcontext
|
|
||||||
|
|
||||||
- name: Deploy to Kubernetes
|
|
||||||
run: kubectl apply -f $GITHUB_WORKSPACE/deployment.yml
|
|
||||||
|
|
||||||
- name: Verify deployment
|
|
||||||
run: kubectl rollout status -n discord-bots deployment/geeksbot
|
|
||||||
@ -1,2 +1,93 @@
|
|||||||
|
bot_secrets.json
|
||||||
|
google_client_secret.json
|
||||||
|
logs/*
|
||||||
|
*.sh.swp
|
||||||
|
|
||||||
|
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# Environments
|
||||||
.env
|
.env
|
||||||
.idea
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-debug/
|
||||||
|
cmake-build-release/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="TestRunnerService">
|
||||||
|
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (Geeksbot)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/Geeksbot.iml" filepath="$PROJECT_DIR$/.idea/Geeksbot.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@ -1,22 +0,0 @@
|
|||||||
FROM golang:1.14-alpine as dev
|
|
||||||
|
|
||||||
WORKDIR /go/src/Geeksbot
|
|
||||||
COPY ./go.mod .
|
|
||||||
COPY ./go.sum .
|
|
||||||
|
|
||||||
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"]
|
|
||||||
|
|
||||||
from alpine
|
|
||||||
|
|
||||||
WORKDIR /bin
|
|
||||||
|
|
||||||
COPY --from=dev /go/bin/geeksbot ./geeksbot
|
|
||||||
COPY --from=dev /go/bin/go-bindata ./go-bindata
|
|
||||||
|
|
||||||
CMD [ "geeksbot" ]
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2020 Dusty.P
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
@ -1 +1 @@
|
|||||||
# Geeksbot
|
# Geeksbot
|
||||||
@ -1,18 +0,0 @@
|
|||||||
package geeksbot
|
|
||||||
|
|
||||||
type Channel struct {
|
|
||||||
ID string
|
|
||||||
Guild Guild
|
|
||||||
Admin bool
|
|
||||||
Default bool
|
|
||||||
NewPatron bool
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
GetOrCreateChannel(id string, guild_id string) (Channel, error)
|
|
||||||
}
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
"github.com/dustinpianalto/disgoman"
|
|
||||||
"github.com/dustinpianalto/geeksbot/internal/exts"
|
|
||||||
"github.com/dustinpianalto/geeksbot/pkg/database"
|
|
||||||
"github.com/dustinpianalto/geeksbot/pkg/services"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
Token := os.Getenv("DISCORD_TOKEN")
|
|
||||||
dg, err := discordgo.New("Bot " + Token)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("There was an error when creating the Discord Session, ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dg.State.MaxMessageCount = 100
|
|
||||||
dg.StateEnabled = true
|
|
||||||
|
|
||||||
dg.Identify = discordgo.Identify{
|
|
||||||
Intents: discordgo.MakeIntent(discordgo.IntentsAll),
|
|
||||||
}
|
|
||||||
|
|
||||||
database.ConnectDatabase(os.Getenv("DATABASE_URL"))
|
|
||||||
//database.RunMigrations()
|
|
||||||
services.InitializeServices()
|
|
||||||
|
|
||||||
owners := []string{
|
|
||||||
"351794468870946827",
|
|
||||||
}
|
|
||||||
|
|
||||||
manager := disgoman.CommandManager{
|
|
||||||
Prefixes: getPrefixes,
|
|
||||||
Owners: owners,
|
|
||||||
StatusManager: disgoman.GetDefaultStatusManager(),
|
|
||||||
ErrorChannel: make(chan disgoman.CommandError, 10),
|
|
||||||
Commands: make(map[string]*disgoman.Command),
|
|
||||||
IgnoreBots: true,
|
|
||||||
CheckPermissions: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Command Handlers
|
|
||||||
exts.AddCommandHandlers(&manager)
|
|
||||||
|
|
||||||
dg.AddHandler(manager.OnMessage)
|
|
||||||
dg.AddHandler(manager.StatusManager.OnReady)
|
|
||||||
|
|
||||||
err = dg.Open()
|
|
||||||
if err != nil {
|
|
||||||
log.Println("There was an error opening the connection, ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the Error handler in a goroutine
|
|
||||||
go ErrorHandler(manager.ErrorChannel)
|
|
||||||
|
|
||||||
log.Println("The Bot is now running.")
|
|
||||||
sc := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
|
|
||||||
<-sc
|
|
||||||
|
|
||||||
log.Println("Shutting Down...")
|
|
||||||
err = dg.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPrefixes(guildID string) []string {
|
|
||||||
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) {
|
|
||||||
for ce := range ErrorChan {
|
|
||||||
msg := ce.Message
|
|
||||||
if msg == "" {
|
|
||||||
msg = ce.Error.Error()
|
|
||||||
}
|
|
||||||
_, _ = ce.Context.Send(msg)
|
|
||||||
log.Println(ce.Error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
@ -1,72 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: geeksbot
|
|
||||||
namespace: discord-bots
|
|
||||||
labels:
|
|
||||||
app: geeksbot
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: geeksbot
|
|
||||||
strategy:
|
|
||||||
rollingUpdate:
|
|
||||||
maxSurge: 1
|
|
||||||
maxUnavailable: 1
|
|
||||||
minReadySeconds: 120
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
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:
|
|
||||||
secretKeyRef:
|
|
||||||
name: geeksbot
|
|
||||||
key: database_url
|
|
||||||
- name: DISCORD_TOKEN
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: geeksbot
|
|
||||||
key: discord_token
|
|
||||||
imagePullSecrets:
|
|
||||||
- name: registry-1
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
until python -m src; do
|
||||||
|
echo "Geeksbot shutdown with error: $?. Restarting..." >&2
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
@ -1,14 +0,0 @@
|
|||||||
module github.com/dustinpianalto/geeksbot
|
|
||||||
|
|
||||||
go 1.14
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/bwmarrin/discordgo v0.22.1
|
|
||||||
github.com/dustinpianalto/disgoman v0.0.15
|
|
||||||
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
|
|
||||||
)
|
|
||||||
@ -1,591 +0,0 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
|
||||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
|
||||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
|
||||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
|
||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
|
||||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
|
||||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
|
||||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
|
||||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
|
||||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
|
||||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
|
||||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
|
||||||
cloud.google.com/go v0.63.0/go.mod h1:GmezbQc7T2snqkEXWfZ0sy0VfkB/ivI2DdtJL2DEmlg=
|
|
||||||
cloud.google.com/go v0.64.0/go.mod h1:xfORb36jGvE+6EexW71nMEtL025s3x6xvuYUKM4JLv4=
|
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
|
||||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
|
||||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
|
||||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
|
||||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
|
||||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
|
||||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
|
||||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
|
||||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
|
||||||
cloud.google.com/go/spanner v1.9.0/go.mod h1:xvlEn0NZ5v1iJPYsBnUVRDNvccDxsBTEi16pJRKQVws=
|
|
||||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
|
||||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
|
||||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
|
||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
|
||||||
github.com/ClickHouse/clickhouse-go v1.3.12/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
|
||||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
|
||||||
github.com/apache/arrow/go/arrow v0.0.0-20200601151325-b2287a20f230/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0=
|
|
||||||
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
|
||||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
|
||||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
|
||||||
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
|
||||||
github.com/bwmarrin/discordgo v0.22.1 h1:254fNYyfqJWKbPzO5g8j/nUvRgj4dNlI19EB8rnkpt8=
|
|
||||||
github.com/bwmarrin/discordgo v0.22.1/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
|
|
||||||
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
|
||||||
github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
|
||||||
github.com/containerd/containerd v1.4.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
|
||||||
github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
|
||||||
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
|
||||||
github.com/dhui/dktest v0.3.3/go.mod h1:EML9sP4sqJELHn4jV7B0TY8oF6077nk83/tz7M56jcQ=
|
|
||||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
|
||||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
|
||||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
|
||||||
github.com/dustinpianalto/disgoman v0.0.15 h1:kdIw6jhC82WBut7+4BarqxBw06dozU+Hu47LQzkkoGM=
|
|
||||||
github.com/dustinpianalto/disgoman v0.0.15/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g=
|
|
||||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
|
||||||
github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw=
|
|
||||||
github.com/go-bindata/go-bindata v1.0.0 h1:DZ34txDXWn1DyWa+vQf7V9ANc2ILTtrEjtlsdJRF26M=
|
|
||||||
github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7YFTXg5IgGVW4gBr5IbvE=
|
|
||||||
github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
|
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
|
||||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
|
||||||
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
|
|
||||||
github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
|
|
||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
|
||||||
github.com/golang-migrate/migrate v1.3.2 h1:QAlFV1QF9zdkzy/jujlBVkVu+L/+k18cg8tuY1/4JDY=
|
|
||||||
github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA=
|
|
||||||
github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk=
|
|
||||||
github.com/golang-migrate/migrate/v4 v4.14.1 h1:qmRd/rNGjM1r3Ve5gHd5ZplytrD02UcItYNxJ3iUHHE=
|
|
||||||
github.com/golang-migrate/migrate/v4 v4.14.1/go.mod h1:l7Ks0Au6fYHuUIxUhQ0rcVX1uLlJg54C/VvW7tvxSz0=
|
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
|
||||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
|
||||||
github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
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=
|
|
||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
|
||||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
|
||||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
|
||||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
|
||||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
|
||||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
|
||||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
|
||||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
|
||||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
|
||||||
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
|
||||||
github.com/jackc/pgconn v1.3.2/go.mod h1:LvCquS3HbBKwgl7KbX9KyqEIumJAbm1UMcTvGaIf3bM=
|
|
||||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
|
||||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
|
||||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
|
||||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
|
||||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
|
||||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
|
||||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
|
||||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
|
||||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
|
||||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
|
||||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
|
||||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
|
|
||||||
github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
|
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4=
|
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
|
||||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
|
||||||
github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
|
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
|
||||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
|
||||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
|
||||||
github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY=
|
|
||||||
github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
|
|
||||||
github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI=
|
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
|
||||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
|
||||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
|
||||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
|
||||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
|
||||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
|
||||||
github.com/snowflakedb/glog v0.0.0-20180824191149-f5055e6f21ce/go.mod h1:EB/w24pR5VKI60ecFnKqXzxX3dOorz1rnVicQTQrGM0=
|
|
||||||
github.com/snowflakedb/gosnowflake v1.3.5/go.mod h1:13Ky+lxzIm3VqNDZJdyvu9MCGy+WgRdYFdXp96UcLZU=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
|
||||||
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
|
||||||
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
|
|
||||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
|
||||||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
|
||||||
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
|
|
||||||
go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
|
||||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|
||||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
|
|
||||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
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=
|
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
|
||||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
|
||||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
|
||||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
|
||||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190225153610-fe579d43d832/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
|
||||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
|
||||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
|
||||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200806022845-90696ccdc692/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200814230902-9882f1d1823d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200817023811-d00afeaade8f/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200818005847-188abfa75333/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
|
||||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
|
||||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
|
||||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
|
||||||
google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
|
||||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
|
||||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
|
||||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
|
||||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20200911024640-645f7a48b24f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
|
||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
|
||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
|
||||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
|
||||||
modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg=
|
|
||||||
modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8=
|
|
||||||
modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw=
|
|
||||||
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
|
|
||||||
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
|
||||||
modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM=
|
|
||||||
modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8=
|
|
||||||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
|
||||||
modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY=
|
|
||||||
modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k=
|
|
||||||
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
|
||||||
modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4=
|
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
package geeksbot
|
|
||||||
|
|
||||||
import "database/sql"
|
|
||||||
|
|
||||||
type Guild struct {
|
|
||||||
ID string
|
|
||||||
NewPatronMessage sql.NullString
|
|
||||||
Prefixes []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Role struct {
|
|
||||||
ID string
|
|
||||||
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
|
|
||||||
GetOrCreateGuild(id string) (Guild, error)
|
|
||||||
CreateOrUpdateRole(r Role) (Role, error)
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
package discord_utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ParseDateString(inTime time.Time) string {
|
|
||||||
d := time.Now().Sub(inTime)
|
|
||||||
s := int64(d.Seconds())
|
|
||||||
days := s / 86400
|
|
||||||
s = s - (days * 86400)
|
|
||||||
hours := s / 3600
|
|
||||||
s = s - (hours * 3600)
|
|
||||||
minutes := s / 60
|
|
||||||
seconds := s - (minutes * 60)
|
|
||||||
dateString := ""
|
|
||||||
if days != 0 {
|
|
||||||
dateString += fmt.Sprintf("%v days ", days)
|
|
||||||
}
|
|
||||||
if hours != 0 {
|
|
||||||
dateString += fmt.Sprintf("%v hours ", hours)
|
|
||||||
}
|
|
||||||
if minutes != 0 {
|
|
||||||
dateString += fmt.Sprintf("%v minutes ", minutes)
|
|
||||||
}
|
|
||||||
if seconds != 0 {
|
|
||||||
dateString += fmt.Sprintf("%v seconds ", seconds)
|
|
||||||
}
|
|
||||||
if dateString != "" {
|
|
||||||
dateString += " ago."
|
|
||||||
} else {
|
|
||||||
dateString = "Now"
|
|
||||||
}
|
|
||||||
stamp := inTime.Format("2006-01-02 15:04:05")
|
|
||||||
return fmt.Sprintf("%v\n%v", dateString, stamp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseDurationString(inDur time.Duration) string {
|
|
||||||
s := int64(inDur.Seconds())
|
|
||||||
days := s / 86400
|
|
||||||
s = s - (days * 86400)
|
|
||||||
hours := s / 3600
|
|
||||||
s = s - (hours * 3600)
|
|
||||||
minutes := s / 60
|
|
||||||
seconds := s - (minutes * 60)
|
|
||||||
durString := ""
|
|
||||||
if days != 0 {
|
|
||||||
durString += fmt.Sprintf("%v days ", days)
|
|
||||||
}
|
|
||||||
if hours != 0 {
|
|
||||||
durString += fmt.Sprintf("%v hours ", hours)
|
|
||||||
}
|
|
||||||
if minutes != 0 {
|
|
||||||
durString += fmt.Sprintf("%v minutes ", minutes)
|
|
||||||
}
|
|
||||||
if seconds != 0 {
|
|
||||||
durString += fmt.Sprintf("%v seconds ", seconds)
|
|
||||||
}
|
|
||||||
if durString == "" {
|
|
||||||
durString = "0 seconds"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%v", durString)
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
package discord_utils
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type Snowflake struct {
|
|
||||||
CreationTime time.Time
|
|
||||||
WorkerID int8
|
|
||||||
ProcessID int8
|
|
||||||
Increment int16
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseSnowflake(s int64) Snowflake {
|
|
||||||
const (
|
|
||||||
DISCORD_EPOCH = 1420070400000
|
|
||||||
TIME_BITS_LOC = 22
|
|
||||||
WORKER_ID_LOC = 17
|
|
||||||
WORKER_ID_MASK = 0x3E0000
|
|
||||||
PROCESS_ID_LOC = 12
|
|
||||||
PROCESS_ID_MASK = 0x1F000
|
|
||||||
INCREMENT_MASK = 0xFFF
|
|
||||||
)
|
|
||||||
creationTime := time.Unix(((s>>TIME_BITS_LOC)+DISCORD_EPOCH)/1000.0, 0)
|
|
||||||
workerID := (s & WORKER_ID_MASK) >> WORKER_ID_LOC
|
|
||||||
processID := (s & PROCESS_ID_MASK) >> PROCESS_ID_LOC
|
|
||||||
increment := s & INCREMENT_MASK
|
|
||||||
return Snowflake{
|
|
||||||
CreationTime: creationTime,
|
|
||||||
WorkerID: int8(workerID),
|
|
||||||
ProcessID: int8(processID),
|
|
||||||
Increment: int16(increment),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -1,184 +0,0 @@
|
|||||||
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),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -1,109 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,404 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
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"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AddCommandHandlers(g *disgoman.CommandManager) {
|
|
||||||
// Arguments:
|
|
||||||
// name - command name - string
|
|
||||||
// desc - command description - string
|
|
||||||
// owneronly - only allow owners to run - bool
|
|
||||||
// hidden - hide command from non-owners - bool
|
|
||||||
// perms - permissisions required - anpan.Permission (int)
|
|
||||||
// type - command type, sets where the command is available
|
|
||||||
// run - function to run - func(anpan.Context, []string) / CommandRunFunc
|
|
||||||
_ = 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)
|
|
||||||
_ = g.AddCommand(requests.ViewCommand)
|
|
||||||
_ = g.AddCommand(requests.CommentCommand)
|
|
||||||
_ = g.AddCommand(arcon.ListplayersCommand)
|
|
||||||
_ = g.AddCommand(arcon.BroadcastCommand)
|
|
||||||
}
|
|
||||||
@ -1,449 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,281 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"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{
|
|
||||||
Name: "ping",
|
|
||||||
Aliases: []string{" "},
|
|
||||||
Description: "Check the bot's ping",
|
|
||||||
OwnerOnly: false,
|
|
||||||
Hidden: false,
|
|
||||||
RequiredPermissions: 0,
|
|
||||||
Invoke: pingCommandFunc,
|
|
||||||
}
|
|
||||||
|
|
||||||
func pingCommandFunc(ctx disgoman.Context, _ []string) {
|
|
||||||
timeBefore := time.Now()
|
|
||||||
msg, _ := ctx.Send("Pong!")
|
|
||||||
took := time.Now().Sub(timeBefore)
|
|
||||||
_, err := ctx.Session.ChannelMessageEdit(ctx.Message.ChannelID, msg.ID, fmt.Sprintf("Pong!\nPing Took **%s**", took.String()))
|
|
||||||
if err != nil {
|
|
||||||
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
|
|
||||||
Context: ctx,
|
|
||||||
Message: "Ping Failed",
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var InviteCommand = &disgoman.Command{
|
|
||||||
Name: "invite",
|
|
||||||
Aliases: nil,
|
|
||||||
Description: "Get the invite link for this bot or others",
|
|
||||||
OwnerOnly: false,
|
|
||||||
Hidden: false,
|
|
||||||
RequiredPermissions: 0,
|
|
||||||
Invoke: inviteCommandFunc,
|
|
||||||
}
|
|
||||||
|
|
||||||
func inviteCommandFunc(ctx disgoman.Context, args []string) {
|
|
||||||
var ids []string
|
|
||||||
if len(args) == 0 && len(ctx.Message.Mentions) == 0 {
|
|
||||||
ids = []string{ctx.Session.State.User.ID}
|
|
||||||
} else {
|
|
||||||
if len(ctx.Message.Mentions) > 0 {
|
|
||||||
for _, user := range ctx.Message.Mentions {
|
|
||||||
member, err := ctx.Session.GuildMember(ctx.Guild.ID, user.ID)
|
|
||||||
if err != nil {
|
|
||||||
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
|
|
||||||
Context: ctx,
|
|
||||||
Message: "Could not find member " + user.Username,
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ids = append(ids, member.User.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(args) > 0 {
|
|
||||||
for _, id := range args {
|
|
||||||
member, err := ctx.Session.GuildMember(ctx.Guild.ID, id)
|
|
||||||
if err != nil {
|
|
||||||
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
|
|
||||||
Context: ctx,
|
|
||||||
Message: "Could not find member " + id,
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ids = append(ids, member.User.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(ids) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, id := range ids {
|
|
||||||
url := fmt.Sprintf("<https://discordapp.com/oauth2/authorize?client_id=%v&scope=bot>", id)
|
|
||||||
_, err := ctx.Send(url)
|
|
||||||
if err != nil {
|
|
||||||
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
|
|
||||||
Context: ctx,
|
|
||||||
Message: "Couldn't send the invite link.",
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var GitCommand = &disgoman.Command{
|
|
||||||
Name: "git",
|
|
||||||
Aliases: nil,
|
|
||||||
Description: "Show my github link",
|
|
||||||
OwnerOnly: false,
|
|
||||||
Hidden: false,
|
|
||||||
RequiredPermissions: 0,
|
|
||||||
Invoke: gitCommandFunc,
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitCommandFunc(ctx disgoman.Context, _ []string) {
|
|
||||||
embed := &discordgo.MessageEmbed{
|
|
||||||
Title: "Hi there, My code is on Github",
|
|
||||||
Color: 0,
|
|
||||||
URL: "https://github.com/dustinpianalto/Geeksbot",
|
|
||||||
}
|
|
||||||
_, err := ctx.Session.ChannelMessageSendEmbed(ctx.Channel.ID, embed)
|
|
||||||
if err != nil {
|
|
||||||
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
|
|
||||||
Context: ctx,
|
|
||||||
Message: "Git failed",
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var SayCommand = &disgoman.Command{
|
|
||||||
Name: "say",
|
|
||||||
Aliases: nil,
|
|
||||||
Description: "Repeat a message",
|
|
||||||
OwnerOnly: false,
|
|
||||||
Hidden: false,
|
|
||||||
RequiredPermissions: 0,
|
|
||||||
SanitizeEveryone: true,
|
|
||||||
Invoke: sayCommandFunc,
|
|
||||||
}
|
|
||||||
|
|
||||||
func sayCommandFunc(ctx disgoman.Context, args []string) {
|
|
||||||
resp := strings.Join(args, " ")
|
|
||||||
resp = strings.ReplaceAll(resp, "@everyone", "@\ufff0everyone")
|
|
||||||
resp = strings.ReplaceAll(resp, "@here", "@\ufff0here")
|
|
||||||
_, err := ctx.Session.ChannelMessageSend(ctx.Message.ChannelID, resp)
|
|
||||||
if err != nil {
|
|
||||||
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
|
|
||||||
Context: ctx,
|
|
||||||
Message: "Say Failed",
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var UserCommand = &disgoman.Command{
|
|
||||||
Name: "user",
|
|
||||||
Aliases: nil,
|
|
||||||
Description: "Get user info",
|
|
||||||
OwnerOnly: false,
|
|
||||||
Hidden: false,
|
|
||||||
RequiredPermissions: 0,
|
|
||||||
Invoke: userCommandFunc,
|
|
||||||
}
|
|
||||||
|
|
||||||
func userCommandFunc(ctx disgoman.Context, args []string) {
|
|
||||||
var member *discordgo.Member
|
|
||||||
if len(args) == 0 {
|
|
||||||
member, _ = ctx.Session.GuildMember(ctx.Guild.ID, ctx.Message.Author.ID)
|
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
if len(ctx.Message.Mentions) > 0 {
|
|
||||||
member, err = ctx.Session.GuildMember(ctx.Guild.ID, ctx.Message.Mentions[0].ID)
|
|
||||||
} else {
|
|
||||||
member, err = ctx.Session.GuildMember(ctx.Guild.ID, args[0])
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
|
|
||||||
Context: ctx,
|
|
||||||
Message: "Couldn't get that member",
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thumb := &discordgo.MessageEmbedThumbnail{
|
|
||||||
URL: member.User.AvatarURL(""),
|
|
||||||
}
|
|
||||||
|
|
||||||
var botString string
|
|
||||||
if member.User.Bot {
|
|
||||||
botString = "BOT"
|
|
||||||
} else {
|
|
||||||
botString = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var roles []*discordgo.Role
|
|
||||||
for _, roleID := range member.Roles {
|
|
||||||
role, _ := ctx.Session.State.Role(ctx.Guild.ID, roleID)
|
|
||||||
roles = append(roles, role)
|
|
||||||
}
|
|
||||||
sort.Slice(roles, func(i, j int) bool { return roles[i].Position > roles[j].Position })
|
|
||||||
var roleMentions []string
|
|
||||||
for _, role := range roles {
|
|
||||||
roleMentions = append(roleMentions, role.Mention())
|
|
||||||
}
|
|
||||||
var rolesString string
|
|
||||||
if len(roleMentions) > 0 {
|
|
||||||
rolesString = strings.Join(roleMentions, " ")
|
|
||||||
} else {
|
|
||||||
rolesString = "None"
|
|
||||||
}
|
|
||||||
|
|
||||||
rolesField := &discordgo.MessageEmbedField{
|
|
||||||
Name: "Roles:",
|
|
||||||
Value: rolesString,
|
|
||||||
Inline: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
guildJoinTime, _ := member.JoinedAt.Parse()
|
|
||||||
guildJoinedField := &discordgo.MessageEmbedField{
|
|
||||||
Name: "Joined Guild:",
|
|
||||||
Value: discord_utils.ParseDateString(guildJoinTime),
|
|
||||||
Inline: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
int64ID, _ := strconv.ParseInt(member.User.ID, 10, 64)
|
|
||||||
s := discord_utils.ParseSnowflake(int64ID)
|
|
||||||
discordJoinedField := &discordgo.MessageEmbedField{
|
|
||||||
Name: "Joined Discord:",
|
|
||||||
Value: discord_utils.ParseDateString(s.CreationTime),
|
|
||||||
Inline: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
embed := &discordgo.MessageEmbed{
|
|
||||||
Title: fmt.Sprintf("%v#%v %v", member.User.Username, member.User.Discriminator, botString),
|
|
||||||
Description: fmt.Sprintf("**%v** (%v)", member.Nick, member.User.ID),
|
|
||||||
Color: ctx.Session.State.UserColor(member.User.ID, ctx.Channel.ID),
|
|
||||||
Thumbnail: thumb,
|
|
||||||
Fields: []*discordgo.MessageEmbedField{
|
|
||||||
guildJoinedField,
|
|
||||||
discordJoinedField,
|
|
||||||
rolesField,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err := ctx.Session.ChannelMessageSendEmbed(ctx.Channel.ID, embed)
|
|
||||||
if err != nil {
|
|
||||||
ctx.CommandManager.ErrorChannel <- disgoman.CommandError{
|
|
||||||
Context: ctx,
|
|
||||||
Message: "Couldn't send the user embed",
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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, "✅")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
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"
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package geeksbot
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Message struct {
|
|
||||||
ID string
|
|
||||||
CreatedAt time.Time
|
|
||||||
ModifiedAt sql.NullTime
|
|
||||||
Content string
|
|
||||||
PreviousContent []string
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package geeksbot
|
|
||||||
|
|
||||||
import "database/sql"
|
|
||||||
|
|
||||||
type PatreonCreator struct {
|
|
||||||
ID int
|
|
||||||
Creator string
|
|
||||||
Link string
|
|
||||||
Guild Guild
|
|
||||||
}
|
|
||||||
|
|
||||||
type PatreonTier struct {
|
|
||||||
ID int
|
|
||||||
Name string
|
|
||||||
Description sql.NullString
|
|
||||||
Creator PatreonCreator
|
|
||||||
Role Role
|
|
||||||
NextTier *PatreonTier
|
|
||||||
}
|
|
||||||
|
|
||||||
type PatreonService interface {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
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) {
|
|
||||||
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)
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
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")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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}
|
|
||||||
}
|
|
||||||
@ -1,121 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
BEGIN;
|
|
||||||
DROP TABLE IF EXISTS servers;
|
|
||||||
DROP TABLE IF EXISTS comments;
|
|
||||||
DROP TABLE IF EXISTS requests;
|
|
||||||
DROP TABLE IF EXISTS patreon_tier;
|
|
||||||
DROP TABLE IF EXISTS patreon_creator;
|
|
||||||
DROP TABLE IF EXISTS messages;
|
|
||||||
DROP TABLE IF EXISTS users;
|
|
||||||
DROP TABLE IF EXISTS channels;
|
|
||||||
DROP TABLE IF EXISTS roles;
|
|
||||||
DROP TYPE IF EXISTS role_types;
|
|
||||||
DROP TABLE IF EXISTS guilds;
|
|
||||||
COMMIT;
|
|
||||||
@ -1,174 +0,0 @@
|
|||||||
BEGIN;
|
|
||||||
CREATE TABLE IF NOT EXISTS guilds (
|
|
||||||
id varchar(30),
|
|
||||||
new_patron_message varchar(1000),
|
|
||||||
prefixes varchar(10)[],
|
|
||||||
PRIMARY KEY(id)
|
|
||||||
);
|
|
||||||
CREATE TYPE role_type as ENUM (
|
|
||||||
'normal',
|
|
||||||
'moderator',
|
|
||||||
'admin',
|
|
||||||
'patreon'
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS roles (
|
|
||||||
id varchar(30),
|
|
||||||
role_type role_type,
|
|
||||||
guild_id varchar(30),
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
CONSTRAINT fk_guild
|
|
||||||
FOREIGN KEY(guild_id)
|
|
||||||
REFERENCES guilds(id)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS channels (
|
|
||||||
id varchar(30),
|
|
||||||
guild_id varchar(30),
|
|
||||||
admin boolean,
|
|
||||||
default_channel boolean,
|
|
||||||
new_patron boolean,
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
CONSTRAINT fk_guild
|
|
||||||
FOREIGN KEY(guild_id)
|
|
||||||
REFERENCES guilds(id)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
|
||||||
id varchar(30),
|
|
||||||
steam_id varchar(30),
|
|
||||||
active boolean,
|
|
||||||
staff boolean,
|
|
||||||
admin boolean,
|
|
||||||
PRIMARY KEY(id)
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS messages (
|
|
||||||
id varchar(30),
|
|
||||||
created_at timestamp,
|
|
||||||
modified_at timestamp,
|
|
||||||
content varchar(2000),
|
|
||||||
previous_content varchar(2000)[],
|
|
||||||
channel_id varchar(30),
|
|
||||||
author_id varchar(30),
|
|
||||||
embed json,
|
|
||||||
previous_embeds json[],
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
CONSTRAINT fk_channel
|
|
||||||
FOREIGN KEY(channel_id)
|
|
||||||
REFERENCES channels(id)
|
|
||||||
ON DELETE CASCADE,
|
|
||||||
CONSTRAINT fk_user
|
|
||||||
FOREIGN KEY(author_id)
|
|
||||||
REFERENCES users(id)
|
|
||||||
ON DELETE SET NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS patreon_creator (
|
|
||||||
id integer GENERATED ALWAYS AS IDENTITY,
|
|
||||||
creator varchar(100),
|
|
||||||
link varchar(200),
|
|
||||||
guild_id varchar(30),
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
CONSTRAINT fk_guild
|
|
||||||
FOREIGN KEY(guild_id)
|
|
||||||
REFERENCES guilds(id)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS patreon_tier (
|
|
||||||
id integer GENERATED ALWAYS AS IDENTITY,
|
|
||||||
name varchar(100),
|
|
||||||
description varchar(1000),
|
|
||||||
creator integer,
|
|
||||||
role varchar(30),
|
|
||||||
next_tier integer,
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
CONSTRAINT fk_creator
|
|
||||||
FOREIGN KEY(creator)
|
|
||||||
REFERENCES patreon_creator(id)
|
|
||||||
ON DELETE CASCADE,
|
|
||||||
CONSTRAINT fk_role
|
|
||||||
FOREIGN KEY(role)
|
|
||||||
REFERENCES roles(id)
|
|
||||||
ON DELETE SET NULL,
|
|
||||||
CONSTRAINT fk_tier
|
|
||||||
FOREIGN KEY(next_tier)
|
|
||||||
REFERENCES patreon_tier(id)
|
|
||||||
ON DELETE SET NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS requests (
|
|
||||||
id integer GENERATED ALWAYS AS IDENTITY,
|
|
||||||
author_id varchar(30),
|
|
||||||
channel_id varchar(30),
|
|
||||||
content varchar(1000),
|
|
||||||
requested_at timestamp,
|
|
||||||
completed_at timestamp,
|
|
||||||
completed boolean,
|
|
||||||
completed_by varchar(30),
|
|
||||||
message_id varchar(30),
|
|
||||||
completed_message varchar(1000),
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
CONSTRAINT fk_user
|
|
||||||
FOREIGN KEY(author_id)
|
|
||||||
REFERENCES users(id)
|
|
||||||
ON DELETE CASCADE,
|
|
||||||
CONSTRAINT fk_channel
|
|
||||||
FOREIGN KEY(channel_id)
|
|
||||||
REFERENCES channels(id)
|
|
||||||
ON DELETE CASCADE,
|
|
||||||
CONSTRAINT fk_completed_by
|
|
||||||
FOREIGN KEY(completed_by)
|
|
||||||
REFERENCES users(id)
|
|
||||||
ON DELETE SET NULL,
|
|
||||||
CONSTRAINT fk_message
|
|
||||||
FOREIGN KEY(message_id)
|
|
||||||
REFERENCES messages(id)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS comments (
|
|
||||||
id integer GENERATED ALWAYS AS IDENTITY,
|
|
||||||
author_id varchar(30),
|
|
||||||
request_id integer,
|
|
||||||
comment_at timestamp,
|
|
||||||
content varchar(1000),
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
CONSTRAINT fk_user
|
|
||||||
FOREIGN KEY(author_id)
|
|
||||||
REFERENCES users(id)
|
|
||||||
ON DELETE CASCADE,
|
|
||||||
CONSTRAINT fk_request
|
|
||||||
FOREIGN KEY(request_id)
|
|
||||||
REFERENCES requests(id)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS servers (
|
|
||||||
id integer GENERATED ALWAYS AS IDENTITY,
|
|
||||||
name varchar(100),
|
|
||||||
ip_address varchar(15),
|
|
||||||
port integer,
|
|
||||||
password varchar(200),
|
|
||||||
alerts_channel_id varchar(30),
|
|
||||||
guild_id varchar(30),
|
|
||||||
info_channel_id varchar(30),
|
|
||||||
info_message_id varchar(30),
|
|
||||||
settings_message_id varchar(30),
|
|
||||||
PRIMARY KEY(id),
|
|
||||||
CONSTRAINT fk_alert_channel
|
|
||||||
FOREIGN KEY(alerts_channel_id)
|
|
||||||
REFERENCES channels(id)
|
|
||||||
ON DELETE SET NULL,
|
|
||||||
CONSTRAINT fk_guild
|
|
||||||
FOREIGN KEY(guild_id)
|
|
||||||
REFERENCES guilds(id)
|
|
||||||
ON DELETE CASCADE,
|
|
||||||
CONSTRAINT fk_info_channel
|
|
||||||
FOREIGN KEY(info_channel_id)
|
|
||||||
REFERENCES channels(id)
|
|
||||||
ON DELETE SET NULL,
|
|
||||||
CONSTRAINT fk_info_message
|
|
||||||
FOREIGN KEY(info_message_id)
|
|
||||||
REFERENCES messages(id)
|
|
||||||
ON DELETE SET NULL,
|
|
||||||
CONSTRAINT fk_settings_message
|
|
||||||
FOREIGN KEY(settings_message_id)
|
|
||||||
REFERENCES messages(id)
|
|
||||||
ON DELETE SET NULL
|
|
||||||
);
|
|
||||||
COMMIT;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
ALTER TABLE requests DROP COLUMN guild_id;
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE requests
|
|
||||||
ADD COLUMN guild_id varchar(30) CONSTRAINT fk_guild REFERENCES guilds(id) ON DELETE CASCADE;
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
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;
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
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;
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
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;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
ALTER TYPE role_type ADD VALUE 'sar';
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
BEGIN;
|
|
||||||
ALTER TABLE messages
|
|
||||||
ALTER COLUMN previous_content DROP NOT NULL;
|
|
||||||
ALTER TABLE messages
|
|
||||||
ALTER COLUMN previous_content DROP DEFAULT;
|
|
||||||
COMMIT;
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
BEGIN;
|
|
||||||
ALTER TABLE messages
|
|
||||||
ALTER COLUMN previous_content SET NOT NULL;
|
|
||||||
ALTER TABLE messages
|
|
||||||
ALTER COLUMN previous_content SET DEFAULT array[]::varchar[];
|
|
||||||
COMMIT;
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
BEGIN;
|
|
||||||
ALTER TABLE servers
|
|
||||||
DROP COLUMN ftp_port,
|
|
||||||
DROP COLUMN ftp_username,
|
|
||||||
DROP COLUMN ftp_password;
|
|
||||||
COMMIT;
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
BEGIN;
|
|
||||||
ALTER TABLE servers
|
|
||||||
ADD COLUMN ftp_port int4,
|
|
||||||
ADD COLUMN ftp_username varchar(200),
|
|
||||||
ADD COLUMN ftp_password varchar(200);
|
|
||||||
COMMIT;
|
|
||||||
@ -1,267 +0,0 @@
|
|||||||
// 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, "/")...)...)
|
|
||||||
}
|
|
||||||
@ -1,178 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -1,238 +0,0 @@
|
|||||||
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.ID, 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
|
|
||||||
}
|
|
||||||
@ -1,159 +0,0 @@
|
|||||||
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,
|
|
||||||
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, &server.FTPPort, &server.FTPUser, &server.FTPPass)
|
|
||||||
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 LOWER(name) = LOWER($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, ftp_port = $10, ftp_username = $11,
|
|
||||||
ftp_password = $12 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,
|
|
||||||
server.FTPPort,
|
|
||||||
server.FTPUser,
|
|
||||||
server.FTPPass,
|
|
||||||
)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
package geeksbot
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Request struct {
|
|
||||||
ID int64
|
|
||||||
Author User
|
|
||||||
Channel Channel
|
|
||||||
Guild Guild
|
|
||||||
Content string
|
|
||||||
RequestedAt time.Time
|
|
||||||
Completed bool
|
|
||||||
CompletedAt sql.NullTime
|
|
||||||
CompletedBy *User
|
|
||||||
Message Message
|
|
||||||
CompletedMessage sql.NullString
|
|
||||||
}
|
|
||||||
|
|
||||||
type Comment struct {
|
|
||||||
ID int64
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package geeksbot
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
ID int
|
|
||||||
Name string
|
|
||||||
IPAddr string
|
|
||||||
Port int
|
|
||||||
Password string
|
|
||||||
AlertsChannel *Channel
|
|
||||||
Guild Guild
|
|
||||||
InfoChannel *Channel
|
|
||||||
InfoMessage *Message
|
|
||||||
SettingsMessage *Message
|
|
||||||
FTPPort int
|
|
||||||
FTPUser string
|
|
||||||
FTPPass string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ServerService interface {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
@ -0,0 +1,181 @@
|
|||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
import json
|
||||||
|
import aiohttp
|
||||||
|
from googleapiclient.discovery import build
|
||||||
|
from concurrent import futures
|
||||||
|
from src.shared_libs import database
|
||||||
|
|
||||||
|
|
||||||
|
log_format = '{asctime}.{msecs:03.0f}|{levelname:<8}|{name}::{message}'
|
||||||
|
date_format = '%Y.%m.%d %H.%M.%S'
|
||||||
|
|
||||||
|
log_dir = 'logs'
|
||||||
|
|
||||||
|
log_file = '{0}/geeksbot_{1}.log'.format(log_dir, datetime.now().strftime('%Y%m%d_%H%M%S%f'))
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.DEBUG, style='{', filename=log_file, datefmt=date_format, format=log_format)
|
||||||
|
console_handler = logging.StreamHandler()
|
||||||
|
console_handler.setLevel(logging.INFO)
|
||||||
|
formatter = logging.Formatter(log_format, style='{', datefmt=date_format)
|
||||||
|
console_handler.setFormatter(formatter)
|
||||||
|
logging.getLogger('').addHandler(console_handler)
|
||||||
|
|
||||||
|
config_dir = 'src/config/'
|
||||||
|
admin_id_file = 'admin_ids'
|
||||||
|
extension_dir = 'exts'
|
||||||
|
owner_id = 351794468870946827
|
||||||
|
bot_config_file = 'bot_config.json'
|
||||||
|
secrets_file = 'bot_secrets.json'
|
||||||
|
profane_words_file = 'profane_words'
|
||||||
|
|
||||||
|
emojis: Dict[str, str] = {
|
||||||
|
'x': '❌',
|
||||||
|
'y': '✅',
|
||||||
|
'poop': '💩',
|
||||||
|
'boom': '💥',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Geeksbot(commands.Bot):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
kwargs["command_prefix"] = self.get_custom_prefix
|
||||||
|
self.description = 'I am Geeksbot! Fear me!'
|
||||||
|
kwargs['description'] = self.description
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.aio_session = aiohttp.ClientSession(loop=self.loop)
|
||||||
|
with open(f'{config_dir}{bot_config_file}') as file:
|
||||||
|
self.bot_config = json.load(file)
|
||||||
|
with open(f'{config_dir}{secrets_file}') as file:
|
||||||
|
self.bot_secrets = json.load(file)
|
||||||
|
self.guild_config = {}
|
||||||
|
self.infected = {}
|
||||||
|
self.TOKEN = self.bot_secrets['token']
|
||||||
|
self.embed_color = discord.Colour.from_rgb(49, 107, 111)
|
||||||
|
self.error_color = discord.Colour.from_rgb(142, 29, 31)
|
||||||
|
del self.bot_secrets['token']
|
||||||
|
self.db_con = database.DatabaseConnection(**self.bot_secrets['db_con'])
|
||||||
|
self.default_prefix = 'g$'
|
||||||
|
self.voice_chans = {}
|
||||||
|
self.spam_list = {}
|
||||||
|
self.owner_id = 351794468870946827
|
||||||
|
self.__version__ = 'v1.0.0'
|
||||||
|
self.gcs_service = build('customsearch', 'v1', developerKey=self.bot_secrets['google_search_key'])
|
||||||
|
self.tpe = futures.ThreadPoolExecutor()
|
||||||
|
self.geo_api = '2d4e419c2be04c8abe91cb5dd1548c72'
|
||||||
|
self.unicode_emojis: Dict[str, str] = {
|
||||||
|
'x': '❌',
|
||||||
|
'y': '✅',
|
||||||
|
'poop': '💩',
|
||||||
|
'boom': '💥',
|
||||||
|
'left_fist': '🤛',
|
||||||
|
'lock': '🔒',
|
||||||
|
}
|
||||||
|
self.book_emojis: Dict[str, str] = {
|
||||||
|
'unlock': '🔓',
|
||||||
|
'start': '⏮',
|
||||||
|
'back': '◀',
|
||||||
|
'hash': '#\N{COMBINING ENCLOSING KEYCAP}',
|
||||||
|
'forward': '▶',
|
||||||
|
'end': '⏭',
|
||||||
|
'close': '🇽',
|
||||||
|
}
|
||||||
|
|
||||||
|
async def logout(self):
|
||||||
|
await self.db_con.close()
|
||||||
|
super().logout()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def get_custom_prefix(bot_inst, message):
|
||||||
|
return await bot_inst.db_con.fetchval('select prefix from guild_config where guild_id = $1',
|
||||||
|
message.guild.id) or bot_inst.default_prefix
|
||||||
|
|
||||||
|
async def load_ext(self, ctx, mod=None):
|
||||||
|
self.load_extension('src.{0}.{1}'.format(extension_dir, mod))
|
||||||
|
if ctx is not None:
|
||||||
|
await ctx.send('{0} loaded.'.format(mod))
|
||||||
|
|
||||||
|
async def unload_ext(self, ctx, mod=None):
|
||||||
|
self.unload_extension('src.{0}.{1}'.format(extension_dir, mod))
|
||||||
|
if ctx is not None:
|
||||||
|
await ctx.send('{0} unloaded.'.format(mod))
|
||||||
|
|
||||||
|
async def close(self):
|
||||||
|
await super().close()
|
||||||
|
self.aio_session.close() # aiohttp is drunk and can't decide if it's a coro or not
|
||||||
|
|
||||||
|
|
||||||
|
bot = Geeksbot(case_insensitive=True)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def load(ctx, mod=None):
|
||||||
|
"""Allows the owner to load extensions dynamically"""
|
||||||
|
await bot.load_ext(ctx, mod)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def reload(ctx, mod=None):
|
||||||
|
"""Allows the owner to reload extensions dynamically"""
|
||||||
|
if mod == 'all':
|
||||||
|
load_list = bot.bot_config['load_list']
|
||||||
|
for load_item in load_list:
|
||||||
|
await bot.unload_ext(ctx, f'{load_item}')
|
||||||
|
await bot.load_ext(ctx, f'{load_item}')
|
||||||
|
else:
|
||||||
|
await bot.unload_ext(ctx, mod)
|
||||||
|
await bot.load_ext(ctx, mod)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def unload(ctx, mod):
|
||||||
|
"""Allows the owner to unload extensions dynamically"""
|
||||||
|
await bot.unload_ext(ctx, mod)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_message(ctx):
|
||||||
|
if not ctx.author.bot:
|
||||||
|
if ctx.guild:
|
||||||
|
if int(await bot.db_con.fetchval("select channel_lockdown from guild_config where guild_id = $1",
|
||||||
|
ctx.guild.id)):
|
||||||
|
if ctx.channel.id in json.loads(await bot.db_con.fetchval("select allowed_channels from guild_config "
|
||||||
|
"where guild_id = $1",
|
||||||
|
ctx.guild.id)):
|
||||||
|
await bot.process_commands(ctx)
|
||||||
|
elif ctx.channel.id == 418452585683484680:
|
||||||
|
prefix = await bot.db_con.fetchval('select prefix from guild_config where guild_id = $1', ctx.guild.id)
|
||||||
|
prefix = prefix[0] if prefix else bot.default_prefix
|
||||||
|
ctx.content = f'{prefix}{ctx.content}'
|
||||||
|
await bot.process_commands(ctx)
|
||||||
|
else:
|
||||||
|
await bot.process_commands(ctx)
|
||||||
|
else:
|
||||||
|
await bot.process_commands(ctx)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_ready():
|
||||||
|
bot.remove_command('help')
|
||||||
|
bot.recent_msgs = {}
|
||||||
|
logging.info('Logged in as {0.name}|{0.id}'.format(bot.user))
|
||||||
|
load_list = bot.bot_config['load_list']
|
||||||
|
for load_item in load_list:
|
||||||
|
await bot.load_ext(None, f'{load_item}')
|
||||||
|
logging.info('Extension Loaded: {0}'.format(load_item))
|
||||||
|
with open(f'{config_dir}reboot', 'r') as f:
|
||||||
|
reboot = f.readlines()
|
||||||
|
if int(reboot[0]) == 1:
|
||||||
|
await bot.get_channel(int(reboot[1])).send('Restart Finished.')
|
||||||
|
with open(f'{config_dir}reboot', 'w') as f:
|
||||||
|
f.write(f'0')
|
||||||
|
logging.info('Done loading, Geeksbot is active.')
|
||||||
|
|
||||||
|
bot.run(bot.TOKEN)
|
||||||
@ -0,0 +1 @@
|
|||||||
|
351794468870946827
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"load_list": [
|
||||||
|
"admin",
|
||||||
|
"events",
|
||||||
|
"rcon",
|
||||||
|
"repl",
|
||||||
|
"patreon",
|
||||||
|
"fun",
|
||||||
|
"utils",
|
||||||
|
"git"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"rcon_enabled" : false,
|
||||||
|
"channel_lockdown" : false,
|
||||||
|
"raid_status" : 0,
|
||||||
|
"pg_filter" : true,
|
||||||
|
"patreon_enabled" : false,
|
||||||
|
"referral_enabled" : false
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
shit
|
||||||
|
piss
|
||||||
|
fuck
|
||||||
|
cunt
|
||||||
|
cock
|
||||||
|
motherfucker
|
||||||
|
tits
|
||||||
|
ballsack
|
||||||
|
bangbros
|
||||||
|
bitch
|
||||||
|
blow job
|
||||||
|
blowjob
|
||||||
|
clit
|
||||||
|
f u c k
|
||||||
|
gangbang
|
||||||
|
gaylord
|
||||||
|
gaysex
|
||||||
|
god damn
|
||||||
|
goddamn
|
||||||
|
homoerotic
|
||||||
|
hotsex
|
||||||
|
jerk-off
|
||||||
|
jerk off
|
||||||
|
masturbat
|
||||||
|
porn
|
||||||
|
pussy
|
||||||
|
pussi
|
||||||
|
skank
|
||||||
|
whore
|
||||||
@ -0,0 +1 @@
|
|||||||
|
0
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
|||||||
|
{"blobsmirk": "https://discordapp.com/api/emojis/414330931059490827.png", "BlobThinking": "https://discordapp.com/api/emojis/408366351602941952.png", "BlobThinkingCool": "https://discordapp.com/api/emojis/414839939117613057.png", "BlobVote": "https://discordapp.com/api/emojis/414840024266309632.png", "BlobDead": "https://discordapp.com/api/emojis/414840075289886722.png", "BlobIdea": "https://discordapp.com/api/emojis/414840112317333544.png", "BlobOK": "https://discordapp.com/api/emojis/414840149059436544.png", "BlobNausea": "https://discordapp.com/api/emojis/414840414672125992.png", "BlobConfused": "https://discordapp.com/api/emojis/414840484377264158.png", "BlobLenny": "https://discordapp.com/api/emojis/414840707010920459.png", "BlobCrying": "https://discordapp.com/api/emojis/414841411117121556.png", "blobsad": "https://discordapp.com/api/emojis/319122469795397632.png", "blobsmile": "https://discordapp.com/api/emojis/319360049887576074.png", "blobthumbsup": "https://discordapp.com/api/emojis/324917738894000130.png", "blobcouncil": "https://discordapp.com/api/emojis/317793691257274378.png", "FeelsBlobMan": "https://discordapp.com/api/emojis/317969827861889026.png", "BlobPoliceAngry": "https://discordapp.com/api/emojis/317969829854314496.png", "OKBlob": "https://discordapp.com/api/emojis/317970202492928002.png", "blobthinking": "https://discordapp.com/api/emojis/318287662068924416.png", "photoblobs": "https://discordapp.com/api/emojis/318013782662053888.png", "bloblul": "https://discordapp.com/api/emojis/356789385875816448.png", "blobthink": "https://discordapp.com/api/emojis/318799923116113921.png", "blobangry": "https://discordapp.com/api/emojis/319359420997828608.png", "blobsob": "https://discordapp.com/api/emojis/393353541122523136.png", "blobsurprised": "https://discordapp.com/api/emojis/319359953263394817.png", "blobwink": "https://discordapp.com/api/emojis/319360115129974786.png", "blobheadache": "https://discordapp.com/api/emojis/319360532291387392.png", "blobcorner": "https://discordapp.com/api/emojis/319360584703541249.png", "blobrofl": "https://discordapp.com/api/emojis/319360614923370496.png", "blobfacepalm": "https://discordapp.com/api/emojis/319360831626412032.png", "blobdead": "https://discordapp.com/api/emojis/319361012908163072.png", "blobshh": "https://discordapp.com/api/emojis/324917371259060224.png", "blobhammer": "https://discordapp.com/api/emojis/324917546098622466.png", "blobhappy": "https://discordapp.com/api/emojis/324917905257136128.png", "blobexpressionless": "https://discordapp.com/api/emojis/324918006331473923.png", "blobokhand": "https://discordapp.com/api/emojis/324918192763961344.png", "blobwhat": "https://discordapp.com/api/emojis/324918397643128832.png", "blobpat": "https://discordapp.com/api/emojis/324918615994531840.png", "blobpopcorn": "https://discordapp.com/api/emojis/324918859540856832.png", "blobblush": "https://discordapp.com/api/emojis/324918940256174089.png", "blobstraightface": "https://discordapp.com/api/emojis/324919073903476766.png", "blobhifive": "https://discordapp.com/api/emojis/324919278845427713.png", "sadblob": "https://discordapp.com/api/emojis/414017193890545685.png", "blob": "https://discordapp.com/api/emojis/401869697588527105.png"}
|
||||||
@ -0,0 +1,320 @@
|
|||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import inspect
|
||||||
|
import os
|
||||||
|
from src.imports import checks, utils
|
||||||
|
|
||||||
|
config_dir = 'src/config/'
|
||||||
|
admin_id_file = 'admin_ids'
|
||||||
|
owner_id = 351794468870946827
|
||||||
|
embed_color = discord.Colour.from_rgb(49, 107, 111)
|
||||||
|
bot_config_file = 'bot_config.json'
|
||||||
|
invite_match = '(https?://)?(www.)?discord(app.com/(invite|oauth2)|.gg|.io)/[\w\d_\-?=&/]+'
|
||||||
|
|
||||||
|
admin_log = logging.getLogger('admin')
|
||||||
|
|
||||||
|
|
||||||
|
class Admin:
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_config_string(guild_config):
|
||||||
|
config_str = ''
|
||||||
|
for config in guild_config:
|
||||||
|
if isinstance(guild_config[config], dict):
|
||||||
|
config_str = f'{config_str}\n{" "*4}{config}'
|
||||||
|
for item in guild_config[config]:
|
||||||
|
config_str = f'{config_str}\n{" "*8}{item}: {guild_config[config][item]}'
|
||||||
|
elif isinstance(guild_config[config], list):
|
||||||
|
config_str = f'{config_str}\n{" "*4}{config}'
|
||||||
|
for item in guild_config[config]:
|
||||||
|
config_str = f'{config_str}\n{" "*8}{item}'
|
||||||
|
else:
|
||||||
|
config_str = f'{config_str}\n{" "*4}{config}: {guild_config[config]}'
|
||||||
|
return config_str
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def reload_bot_config(self, ctx):
|
||||||
|
with open(f'{config_dir}{bot_config_file}') as file:
|
||||||
|
self.bot.bot_config = json.load(file)
|
||||||
|
del self.bot.bot_config['token']
|
||||||
|
del self.bot.bot_config['db_con']
|
||||||
|
await ctx.send('Config reloaded.')
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def reboot(self, ctx):
|
||||||
|
await ctx.send('Geeksbot is restarting.')
|
||||||
|
with open(f'{config_dir}reboot', 'w') as f:
|
||||||
|
f.write(f'1\n{ctx.channel.id}')
|
||||||
|
# noinspection PyProtectedMember
|
||||||
|
os._exit(1)
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def get_bot_config(self, ctx):
|
||||||
|
n = 2000
|
||||||
|
config = [str(self.bot.bot_config)[i:i+n] for i in range(0, len(str(self.bot.bot_config)), n)]
|
||||||
|
for conf in config:
|
||||||
|
await ctx.message.author.send(conf)
|
||||||
|
await ctx.send(f'{ctx.message.author.mention} check your DMs.')
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def update_emojis(self, ctx):
|
||||||
|
emojis = self.bot.emojis
|
||||||
|
for emoji in emojis:
|
||||||
|
if emoji.animated:
|
||||||
|
emoji_code = f'<a:{emoji.name}:{emoji.id}>'
|
||||||
|
else:
|
||||||
|
emoji_code = f'<:{emoji.name}:{emoji.id}>'
|
||||||
|
if await self.bot.db_con.fetch('select id from geeksbot_emojis where id = $1', emoji.id):
|
||||||
|
await self.bot.db_con.execute("update geeksbot_emojis set id = $2, name = $1, code = $3 "
|
||||||
|
"where name = $1", emoji.name, emoji.id, emoji_code)
|
||||||
|
else:
|
||||||
|
await self.bot.db_con.execute("insert into geeksbot_emojis(id,name,code) values ($2,$1,$3)",
|
||||||
|
emoji.name, emoji.id, emoji_code)
|
||||||
|
await ctx.message.add_reaction('✅')
|
||||||
|
await ctx.send(f'Emojis have been updated in the database.')
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.check(checks.is_guild_owner)
|
||||||
|
async def get_guild_config(self, ctx):
|
||||||
|
config = await self.bot.db_con.fetchrow('select * from guild_config where guild_id = $1', ctx.guild.id)
|
||||||
|
configs = [str(config)[i:i+1990] for i in range(0, len(config), 1990)]
|
||||||
|
await ctx.message.author.send(f'The current config for the {ctx.guild.name} guild is:\n')
|
||||||
|
admin_log.info(configs)
|
||||||
|
for config in configs:
|
||||||
|
await ctx.message.author.send(f'```{config}```')
|
||||||
|
await ctx.send(f'{ctx.message.author.mention} check your DMs.')
|
||||||
|
|
||||||
|
@commands.group(case_insensitive=True)
|
||||||
|
async def set(self, ctx):
|
||||||
|
"""Group for setting configuration options"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@commands.group(case_insensitive=True)
|
||||||
|
async def add(self, ctx):
|
||||||
|
"""Group for adding items to guild config"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@commands.group(case_insensitive=True)
|
||||||
|
async def remove(self, ctx):
|
||||||
|
"""Group for removing items from guild config"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@set.command(name='admin_chan', aliases=['ac', 'admin_chat', 'admin chat'])
|
||||||
|
async def _admin_channel(self, ctx, channel: discord.TextChannel=None):
|
||||||
|
"""Sets the admin notification channel"""
|
||||||
|
if ctx.guild:
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
|
if channel is not None:
|
||||||
|
await self.bot.db_con.execute('update guild_config set admin_chat = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, channel.id)
|
||||||
|
await ctx.send(f'{channel.name} is now set as the Admin Chat channel for this guild.')
|
||||||
|
|
||||||
|
@set.command(name='channel_lockdown', aliases=['lockdown', 'restrict_access', 'cl'])
|
||||||
|
async def _channel_lockdown(self, ctx, config='true'):
|
||||||
|
"""Toggles the channel lockdown restriction
|
||||||
|
When this is active Geeksbot can only respond in channels defined in allowed_channels
|
||||||
|
If you run this before configuring allowed_channels it will tell you to run that command first."""
|
||||||
|
if ctx.guild:
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
|
if str(config).lower() == 'true':
|
||||||
|
if await self.bot.db_con.fetchval('select allowed_channels from guild_config '
|
||||||
|
'where guild_id = $1', ctx.guild.id) is []:
|
||||||
|
await ctx.send('Please set at least one allowed channel before running this command.')
|
||||||
|
else:
|
||||||
|
await self.bot.db_con.execute('update guild_config set channel_lockdown = True '
|
||||||
|
'where guild_id = $1', ctx.guild.id)
|
||||||
|
await ctx.send('Channel Lockdown is now active.')
|
||||||
|
elif str(config).lower() == 'false':
|
||||||
|
if await self.bot.db_con.fetchval('select channel_lockdown from guild_config where guild_id = $1',
|
||||||
|
ctx.guild.id):
|
||||||
|
await self.bot.db_con.execute('update guild_config set channel_lockdown = False '
|
||||||
|
'where guild_id = $1', ctx.guild.id)
|
||||||
|
await ctx.send('Channel Lockdown has been deactivated.')
|
||||||
|
else:
|
||||||
|
await ctx.send('Channel Lockdown is already deactivated.')
|
||||||
|
else:
|
||||||
|
await ctx.send(f'You are not authorized to run this command.')
|
||||||
|
else:
|
||||||
|
await ctx.send('This command must be run from inside a guild.')
|
||||||
|
|
||||||
|
@add.command(name='allowed_channels', aliases=['channel', 'ac'])
|
||||||
|
async def _allowed_channels(self, ctx, *, channels):
|
||||||
|
"""Defines channels Geeksbot can respond in
|
||||||
|
This only takes effect if channel_lockdown is enabled.
|
||||||
|
If one of the channels passed is not found then it is ignored."""
|
||||||
|
if ctx.guild:
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
|
channels = channels.lower().replace(' ', '').split(',')
|
||||||
|
existing_channels = list()
|
||||||
|
channels_add = list()
|
||||||
|
admin_log.info(channels)
|
||||||
|
allowed_channels = await self.bot.db_con.fetchval('select allowed_channels from guild_config '
|
||||||
|
'where guild_id = $1', ctx.guild.id)
|
||||||
|
if allowed_channels == 'null':
|
||||||
|
allowed_channels = None
|
||||||
|
|
||||||
|
channels = [discord.utils.get(ctx.guild.channels, name=channel)
|
||||||
|
for channel in channels if channel is not None]
|
||||||
|
|
||||||
|
if allowed_channels and channels:
|
||||||
|
allowed_channels = [int(channel) for channel in json.loads(allowed_channels)]
|
||||||
|
existing_channels = [channel for channel in channels if channel.id in allowed_channels]
|
||||||
|
channels_add = [channel for channel in channels if channel.id not in allowed_channels]
|
||||||
|
allowed_channels += [channel.id for channel in channels if channel.id not in allowed_channels]
|
||||||
|
await self.bot.db_con.execute('update guild_config set allowed_channels = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, json.dumps(allowed_channels))
|
||||||
|
elif channels:
|
||||||
|
admin_log.info('Config is empty')
|
||||||
|
allowed_channels = [channel.id for channel in channels]
|
||||||
|
await self.bot.db_con.execute('update guild_config set allowed_channels = $2 '
|
||||||
|
'where guild_id = $1', ctx.guild.id,
|
||||||
|
json.dumps(allowed_channels))
|
||||||
|
else:
|
||||||
|
await ctx.send('None of those are valid text channels for this guild.')
|
||||||
|
return
|
||||||
|
|
||||||
|
if existing_channels:
|
||||||
|
channel_str = '\n'.join([str(channel.name) for channel in existing_channels])
|
||||||
|
await ctx.send(f'The following channels were skipped because they are already in the config:\n'
|
||||||
|
f'{channel_str}\n')
|
||||||
|
if channels_add:
|
||||||
|
channel_str = '\n'.join([str(channel.name) for channel in channels_add])
|
||||||
|
await ctx.send('The following channels have been added to the allowed channel list:\n'
|
||||||
|
f'{channel_str}\n')
|
||||||
|
await ctx.message.add_reaction('✅')
|
||||||
|
else:
|
||||||
|
await ctx.send(f'You are not authorized to run this command.')
|
||||||
|
else:
|
||||||
|
await ctx.send('This command must be run from inside a guild.')
|
||||||
|
|
||||||
|
# TODO Fix view_code
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def view_code(self, ctx, code_name):
|
||||||
|
pag = utils.Paginator(self.bot, prefix='```py', suffix='```')
|
||||||
|
pag.add(inspect.getsource(self.bot.all_commands[code_name].callback))
|
||||||
|
for page in pag.pages():
|
||||||
|
await ctx.send(page)
|
||||||
|
|
||||||
|
@add.command(aliases=['prefix', 'p'])
|
||||||
|
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
||||||
|
async def add_prefix(self, ctx, *, prefix=None):
|
||||||
|
"""Adds a custom prefix for the current guild
|
||||||
|
Note: This overwrites the default of g$. If you would
|
||||||
|
like to keep using g$ you will need to add it to the
|
||||||
|
Guild config as well."""
|
||||||
|
if ctx.guild:
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
|
prefixes = await self.bot.db_con.fetchval('select prefix from guild_config where guild_id = $1',
|
||||||
|
ctx.guild.id)
|
||||||
|
if prefix is None:
|
||||||
|
await ctx.send(prefixes)
|
||||||
|
return
|
||||||
|
elif prefixes is None:
|
||||||
|
prefixes = prefix.replace(' ', ',').split(',')
|
||||||
|
else:
|
||||||
|
for p in prefix.replace(' ', ',').split(','):
|
||||||
|
prefixes.append(p)
|
||||||
|
if len(prefixes) > 10:
|
||||||
|
await ctx.send(f'Only 10 prefixes are allowed per guild.\nPlease remove some before adding more.')
|
||||||
|
prefixes = prefixes[:10]
|
||||||
|
await self.bot.db_con.execute('update guild_config set prefix = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, prefixes)
|
||||||
|
await ctx.guild.me.edit(nick=f'[{prefixes[0]}] Geeksbot')
|
||||||
|
await ctx.send(f"Updated. You currently have {len(prefixes)} "
|
||||||
|
f"{'prefix' if len(prefixes) == 1 else 'prefixes'} "
|
||||||
|
f"in your config.\n{', '.join(prefixes)}")
|
||||||
|
else:
|
||||||
|
await ctx.send(f'You are not authorized to run this command.')
|
||||||
|
else:
|
||||||
|
await ctx.send(f'This command must be run from inside a guild.')
|
||||||
|
|
||||||
|
@remove.command(aliases=['prefix', 'p'])
|
||||||
|
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
||||||
|
async def remove_prefix(self, ctx, *, prefix=None):
|
||||||
|
"""Removes custom prefix from the current guild
|
||||||
|
If the last prefix is removed then Geeksbot will default
|
||||||
|
Back to g$"""
|
||||||
|
if ctx.guild:
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
|
prefixes = await self.bot.db_con.fetchval('select prefix from guild_config where guild_id = $1',
|
||||||
|
ctx.guild.id)
|
||||||
|
found = 0
|
||||||
|
if prefix is None:
|
||||||
|
await ctx.send(prefixes)
|
||||||
|
return
|
||||||
|
elif prefixes is None or prefixes == []:
|
||||||
|
await ctx.send('There are no custom prefixes setup for this guild.')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
prefix = prefix.replace(' ', ',').split(',')
|
||||||
|
for p in prefix:
|
||||||
|
if p in prefixes:
|
||||||
|
prefixes.remove(p)
|
||||||
|
found = 1
|
||||||
|
else:
|
||||||
|
await ctx.send(f'The prefix {p} is not in the config for this guild.')
|
||||||
|
if found:
|
||||||
|
await self.bot.db_con.execute('update guild_config set prefix = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, prefixes)
|
||||||
|
await ctx.guild.me.edit(nick=f'[{prefixes[0] if len(prefixes) != 0 else self.bot.default_prefix}] '
|
||||||
|
f'Geeksbot')
|
||||||
|
await ctx.send(f"Updated. You currently have {len(prefixes)} "
|
||||||
|
f"{'prefix' if len(prefixes) == 1 else 'prefixes'} "
|
||||||
|
f"in your config.\n{', '.join(prefixes)}")
|
||||||
|
else:
|
||||||
|
await ctx.send(f'You are not authorized to run this command.')
|
||||||
|
else:
|
||||||
|
await ctx.send(f'This command must be run from inside a guild.')
|
||||||
|
|
||||||
|
@add.command(name='admin_role', aliases=['admin'])
|
||||||
|
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
||||||
|
@commands.check(checks.is_guild_owner)
|
||||||
|
async def _add_admin_role(self, ctx, role=None):
|
||||||
|
"""Adds role to the admin list for current guild
|
||||||
|
Allowing members of that role to run admin commands
|
||||||
|
on the current guild."""
|
||||||
|
role = discord.utils.get(ctx.guild.roles, name=role)
|
||||||
|
if role is not None:
|
||||||
|
roles = json.loads(await self.bot.db_con.fetchval('select admin_roles from guild_config '
|
||||||
|
'where guild_id = $1', ctx.guild.id))
|
||||||
|
if role.name in roles:
|
||||||
|
await ctx.send(f'{role.name} is already registered as an admin role in this guild.')
|
||||||
|
else:
|
||||||
|
roles[role.name] = role.id
|
||||||
|
await self.bot.db_con.execute('update guild_config set admin_roles = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, json.dumps(roles))
|
||||||
|
await ctx.send(f'{role.name} has been added to the list of admin roles for this guild.')
|
||||||
|
else:
|
||||||
|
await ctx.send('You must include a role with this command.')
|
||||||
|
|
||||||
|
@remove.command(name='admin_role', aliases=['admin'])
|
||||||
|
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
||||||
|
@commands.check(checks.is_guild_owner)
|
||||||
|
async def _remove_admin_role(self, ctx, role=None):
|
||||||
|
"""Removes role from admin list in current guild"""
|
||||||
|
role = discord.utils.get(ctx.guild.roles, name=role)
|
||||||
|
if role is not None:
|
||||||
|
roles = json.loads(await self.bot.db_con.fetchval('select admin_roles from guild_config '
|
||||||
|
'where guild_id = $1', ctx.guild.id))
|
||||||
|
if role.name in roles:
|
||||||
|
del roles[role.name]
|
||||||
|
await self.bot.db_con.execute('update guild_config set admin_roles = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, json.dumps(roles))
|
||||||
|
await ctx.send(f'{role.name} has been removed from the list of admin roles for this guild.')
|
||||||
|
else:
|
||||||
|
await ctx.send(f'{role.name} is not registered as an admin role in this guild.')
|
||||||
|
else:
|
||||||
|
await ctx.send('You must include a role with this command.')
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Admin(bot))
|
||||||
@ -0,0 +1,175 @@
|
|||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
import asyncio
|
||||||
|
import youtube_dl
|
||||||
|
|
||||||
|
config_dir = 'config/'
|
||||||
|
admin_id_file = 'admin_ids'
|
||||||
|
extension_dir = 'extensions'
|
||||||
|
owner_id = 351794468870946827
|
||||||
|
guild_config_dir = 'guild_config/'
|
||||||
|
rcon_config_file = 'server_rcon_config'
|
||||||
|
dododex_url = 'http://www.dododex.com'
|
||||||
|
embed_color = discord.Colour.from_rgb(49, 107, 111)
|
||||||
|
bot_config_file = 'bot_config'
|
||||||
|
default_guild_config_file = 'default_guild_config.json'
|
||||||
|
emoji_guild = 408524303164899338
|
||||||
|
|
||||||
|
events_log = logging.getLogger('events')
|
||||||
|
|
||||||
|
emojis = {
|
||||||
|
'x': '❌',
|
||||||
|
'y': '✅',
|
||||||
|
'poop': '💩'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Fun:
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
@commands.cooldown(1, 30, type=commands.BucketType.user)
|
||||||
|
async def infect(self, ctx, member: discord.Member, emoji):
|
||||||
|
"""Infects a user with the given emoji
|
||||||
|
|
||||||
|
Every time the user sends a message that I am also in I will react to that message with said emoji."""
|
||||||
|
if member.id == self.bot.user.id and ctx.author.id != owner_id:
|
||||||
|
await ctx.send(f'You rolled a Critical Fail...\nInfection bounces off and rebounds on the attacker.')
|
||||||
|
member = ctx.author
|
||||||
|
if member in self.bot.infected:
|
||||||
|
await ctx.send(f'{member.display_name} is already infected. '
|
||||||
|
f'Please wait until they are healed before infecting them again...')
|
||||||
|
else:
|
||||||
|
emoji = self.bot.get_emoji(int(emoji.split(':')[2].strip('>'))) if '<:' in emoji \
|
||||||
|
or '<a:' in emoji else emoji
|
||||||
|
self.bot.infected[member] = [emoji, datetime.now().timestamp()]
|
||||||
|
await ctx.send(f"{member.display_name} has been infected with {emoji}")
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
|
async def heal(self, ctx, member: discord.Member):
|
||||||
|
"""Removes infection from user."""
|
||||||
|
if ctx.author == member and ctx.author.id != owner_id:
|
||||||
|
await ctx.send('You can\'t heal yourself silly...')
|
||||||
|
else:
|
||||||
|
if member in self.bot.infected:
|
||||||
|
del self.bot.infected[member]
|
||||||
|
await ctx.send(f'{member.mention} You have been healed by {ctx.author.display_name}.')
|
||||||
|
else:
|
||||||
|
await ctx.send(f'{member.display_name} is not infected...')
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def print_infections(self, ctx):
|
||||||
|
await ctx.author.send(f'```{self.bot.infected}```')
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
|
async def slap(self, ctx, member: discord.Member):
|
||||||
|
"""IRC Style Trout Slap"""
|
||||||
|
trout = await self.bot.db_con.fetchval("select code from geeksbot_emojis where id = 449083238766477312")
|
||||||
|
if member.id == self.bot.user.id and ctx.author.id != owner_id:
|
||||||
|
await ctx.send(f'You rolled a Critical Fail...\nThe trout bounces off and rebounds on the attacker.')
|
||||||
|
await ctx.send(f'{ctx.author.mention} '
|
||||||
|
f'You slap yourself in the face with a large trout {trout}')
|
||||||
|
else:
|
||||||
|
await ctx.send(f'{ctx.author.display_name} slaps '
|
||||||
|
f'{member.mention} around a bit with a large trout {trout}')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_factorial(number):
|
||||||
|
a = 1
|
||||||
|
for i in range(1, int(number)):
|
||||||
|
a = a * (i + 1)
|
||||||
|
return a
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
|
async def fact(self, ctx, number: int):
|
||||||
|
"""Returns the given factorial up to 20,000!"""
|
||||||
|
if 0 < number < 20001:
|
||||||
|
n = 1990
|
||||||
|
with ctx.channel.typing():
|
||||||
|
a = await self.bot.loop.run_in_executor(None, self.get_factorial, number)
|
||||||
|
if len(str(a)) > 6000:
|
||||||
|
for b in [str(a)[i:i+n] for i in range(0, len(str(a)), n)]:
|
||||||
|
await ctx.author.send(f'```py\n{b}```')
|
||||||
|
await ctx.send(f"{ctx.author.mention} Check your DMs.")
|
||||||
|
else:
|
||||||
|
for b in [str(a)[i:i+n] for i in range(0, len(str(a)), n)]:
|
||||||
|
await ctx.send(f'```py\n{b}```')
|
||||||
|
else:
|
||||||
|
await ctx.send("Invalid number. Please enter a number between 0 and 20,000")
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def play(self, ctx, url=None):
|
||||||
|
if ctx.author.voice.channel.name in self.bot.voice_chans:
|
||||||
|
if self.bot.voice_chans[ctx.author.voice.channel.name].is_playing():
|
||||||
|
await ctx.send('There is currently a song playing. Please wait until it is done...')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.bot.voice_chans[ctx.author.voice.channel.name] = await ctx.author.voice.channel.connect()
|
||||||
|
asyncio.sleep(5)
|
||||||
|
if url:
|
||||||
|
opts = {"format": 'webm[abr>0]/bestaudio/best',
|
||||||
|
"ignoreerrors": True,
|
||||||
|
"default_search": "auto",
|
||||||
|
"source_address": "0.0.0.0",
|
||||||
|
'quiet': True}
|
||||||
|
ydl = youtube_dl.YoutubeDL(opts)
|
||||||
|
info = ydl.extract_info(url, download=False)
|
||||||
|
self.bot.player = discord.FFmpegPCMAudio(info['url'])
|
||||||
|
else:
|
||||||
|
self.bot.player = discord.FFmpegPCMAudio('dead_puppies.mp3')
|
||||||
|
self.bot.player = discord.PCMVolumeTransformer(self.bot.player, volume=0.3)
|
||||||
|
self.bot.voice_chans[ctx.author.voice.channel.name].play(self.bot.player)
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def stop(self, ctx):
|
||||||
|
if ctx.author.voice.channel.name in self.bot.voice_chans:
|
||||||
|
if self.bot.voice_chans[ctx.author.voice.channel.name].is_playing():
|
||||||
|
self.bot.voice_chans[ctx.author.voice.channel.name].stop()
|
||||||
|
else:
|
||||||
|
await ctx.send('Nothing is playing...')
|
||||||
|
else:
|
||||||
|
await ctx.send('Not connected to that voice channel.')
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def disconnect(self, ctx):
|
||||||
|
if ctx.author.voice.channel.name in self.bot.voice_chans:
|
||||||
|
await self.bot.voice_chans[ctx.author.voice.channel.name].disconnect()
|
||||||
|
del self.bot.voice_chans[ctx.author.voice.channel.name]
|
||||||
|
else:
|
||||||
|
await ctx.send('Not connected to that voice channel.')
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
@commands.is_owner()
|
||||||
|
async def volume(self, ctx, volume: float):
|
||||||
|
self.bot.player.volume = volume
|
||||||
|
|
||||||
|
@commands.command(name='explode', aliases=['splode'])
|
||||||
|
async def explode_user(self, ctx, member: discord.Member=None):
|
||||||
|
"""Trolls user by punching them to oblivion."""
|
||||||
|
if member is None or member.id == 396588996706304010:
|
||||||
|
member = ctx.author
|
||||||
|
|
||||||
|
trans = await self.bot.db_con.fetchval('select code from geeksbot_emojis where id = 405943174809255956')
|
||||||
|
msg = await ctx.send(f'{member.mention}{trans*20}{self.bot.unicode_emojis["left_fist"]}')
|
||||||
|
for i in range(4):
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
await msg.edit(content=f'{member.mention}{trans*(20-(i*5))}{self.bot.unicode_emojis["left_fist"]}')
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
await msg.edit(content=f'{self.bot.unicode_emojis["boom"]}')
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
await msg.edit(content=f'{self.bot.unicode_emojis["boom"]} <---- {member.mention} that was you...')
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Fun(bot))
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
import logging
|
||||||
|
from src.imports.utils import Paginator, run_command, Book
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
owner_id = 351794468870946827
|
||||||
|
embed_color = discord.Colour.from_rgb(49, 107, 111)
|
||||||
|
|
||||||
|
git_log = logging.getLogger('git')
|
||||||
|
|
||||||
|
|
||||||
|
class Git:
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.group(case_insensitive=True, invoke_without_command=True)
|
||||||
|
async def git(self, ctx):
|
||||||
|
"""Shows my Git link"""
|
||||||
|
em = discord.Embed(style='rich',
|
||||||
|
title=f'Here is where you can find my code',
|
||||||
|
url='https://github.com/dustinpianalto/Geeksbot/tree/development',
|
||||||
|
description='I am the development branch of Geeksbot. You can find the master branch here:\n'
|
||||||
|
'https://github.com/dustinpianalto/Geeksbot/',
|
||||||
|
color=embed_color)
|
||||||
|
em.set_thumbnail(url=f'{ctx.guild.me.avatar_url}')
|
||||||
|
await ctx.send(embed=em)
|
||||||
|
|
||||||
|
@git.command()
|
||||||
|
@commands.is_owner()
|
||||||
|
async def pull(self, ctx):
|
||||||
|
"""Pulls updates from GitHub rebasing branch."""
|
||||||
|
pag = Paginator(self.bot, max_line_length=44, embed=True)
|
||||||
|
pag.set_embed_meta(title='Git Pull',
|
||||||
|
color=self.bot.embed_color,
|
||||||
|
thumbnail=f'{ctx.guild.me.avatar_url}')
|
||||||
|
pag.add('\uFFF6' + await asyncio.wait_for(self.bot.loop.create_task(run_command('git fetch --all')), 120))
|
||||||
|
pag.add(await asyncio.wait_for(self.bot.loop.create_task(run_command('git reset --hard '
|
||||||
|
'origin/$(git '
|
||||||
|
'rev-parse --symbolic-full-name'
|
||||||
|
' --abbrev-ref HEAD)')), 120))
|
||||||
|
pag.add('\uFFF7\n\uFFF8')
|
||||||
|
pag.add(await asyncio.wait_for(self.bot.loop.create_task(run_command('git show --stat | '
|
||||||
|
'sed "s/.*@.*[.].*/ /g"')), 10))
|
||||||
|
book = Book(pag, (None, ctx.channel, self.bot, ctx.message))
|
||||||
|
await book.create_book()
|
||||||
|
|
||||||
|
@git.command()
|
||||||
|
@commands.is_owner()
|
||||||
|
async def status(self, ctx):
|
||||||
|
"""Gets status of current branch."""
|
||||||
|
pag = Paginator(self.bot, max_line_length=44, max_lines=30, embed=True)
|
||||||
|
pag.set_embed_meta(title='Git Status',
|
||||||
|
color=self.bot.embed_color,
|
||||||
|
thumbnail=f'{ctx.guild.me.avatar_url}')
|
||||||
|
result = await asyncio.wait_for(self.bot.loop.create_task(run_command('git status')), 10)
|
||||||
|
pag.add(result)
|
||||||
|
book = Book(pag, (None, ctx.channel, self.bot, ctx.message))
|
||||||
|
await book.create_book()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Git(bot))
|
||||||
@ -0,0 +1,126 @@
|
|||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
from src.imports import checks
|
||||||
|
|
||||||
|
config_dir = 'config'
|
||||||
|
extension_dir = 'extensions'
|
||||||
|
owner_id = 351794468870946827
|
||||||
|
|
||||||
|
|
||||||
|
class Patreon:
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.command(aliases=['get_patreon', 'patreon'])
|
||||||
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
|
async def get_patreon_links(self, ctx, target: discord.Member=None):
|
||||||
|
"""Prints Patreon information for creators on the server."""
|
||||||
|
if await self.bot.db_con.fetchval('select patreon_enabled from guild_config where guild_id = $1', ctx.guild.id):
|
||||||
|
patreon_info = await self.bot.db_con.fetchrow('select patreon_message,patreon_links from guild_config '
|
||||||
|
'where guild_id = $1', ctx.guild.id)
|
||||||
|
message = patreon_info['patreon_message'].replace('\\n', '\n')
|
||||||
|
patreon_links = json.loads(patreon_info['patreon_links'])
|
||||||
|
for key in patreon_links:
|
||||||
|
message = message + '\n{0}: {1}'.format(key, patreon_links[key])
|
||||||
|
if target is None:
|
||||||
|
await ctx.send(message)
|
||||||
|
else:
|
||||||
|
await ctx.send('{0}\n{1}'.format(target.mention, message))
|
||||||
|
else:
|
||||||
|
await ctx.send('Patreon links are not enabled on this guild.')
|
||||||
|
|
||||||
|
@commands.command(aliases=['patreon_message'])
|
||||||
|
async def set_patreon_message(self, ctx, message):
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
|
patreon_message = await self.bot.db_con.fetchval('select patreon_message from guild_config '
|
||||||
|
'where guild_id = $1', ctx.guild.id)
|
||||||
|
if message == patreon_message:
|
||||||
|
await ctx.send('That is already the current message for this guild.')
|
||||||
|
else:
|
||||||
|
await self.bot.db_con.execute('update guild_config set patreon_message = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, message)
|
||||||
|
await ctx.send(f'The patreon message for this guild has been set to:\n{message}')
|
||||||
|
else:
|
||||||
|
await ctx.send(f'You are not authorized to run this command.')
|
||||||
|
|
||||||
|
@commands.command(aliases=['add_patreon', 'set_patreon'])
|
||||||
|
async def add_patreon_info(self, ctx, name, url):
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
|
patreon_info = await self.bot.db_con.fetchval('select patreon_links from guild_config where guild_id = $1',
|
||||||
|
ctx.guild.id)
|
||||||
|
patreon_links = {}
|
||||||
|
update = 0
|
||||||
|
if patreon_info:
|
||||||
|
patreon_links = json.loads(patreon_info)
|
||||||
|
if name in patreon_links:
|
||||||
|
update = 1
|
||||||
|
patreon_links[name] = url
|
||||||
|
await self.bot.db_con.execute('update guild_config set patreon_links = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, json.dumps(patreon_links))
|
||||||
|
await ctx.send(f"The Patreon link for {name} has been "
|
||||||
|
f"{'updated to the new url.' if update else'added to the config for this guild.'}")
|
||||||
|
else:
|
||||||
|
await ctx.send(f'You are not authorized to run this command.')
|
||||||
|
|
||||||
|
@commands.command(aliases=['remove_patreon'])
|
||||||
|
async def remove_patreon_info(self, ctx, name):
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
|
patreon_info = await self.bot.db_con.fetchval('select patreon_links from guild_config where guild_id = $1',
|
||||||
|
ctx.guild.id)
|
||||||
|
if patreon_info:
|
||||||
|
patreon_links = json.loads(patreon_info)
|
||||||
|
if name in patreon_links:
|
||||||
|
del patreon_links[name]
|
||||||
|
await self.bot.db_con.execute('update guild_config set patreon_links = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, json.dumps(patreon_links))
|
||||||
|
await ctx.send(f'The Patreon link for {name} has been removed from the config for this guild.')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
await ctx.send(f'{name} is not in the Patreon config for this guild.')
|
||||||
|
else:
|
||||||
|
await ctx.send(f'There is no Patreon config for this guild.')
|
||||||
|
else:
|
||||||
|
await ctx.send(f'You are not authorized to run this command.')
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def enable_patreon(self, ctx, state: bool=True):
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
|
patreon_status = await self.bot.db_con.fetchval('select patreon_enabled from guild_config '
|
||||||
|
'where guild_id = $1', ctx.guild.id)
|
||||||
|
if patreon_status and state:
|
||||||
|
await ctx.send('Patreon is already enabled for this guild.')
|
||||||
|
elif patreon_status and not state:
|
||||||
|
await self.bot.db_con.execute('update guild_config set patreon_enabled = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, state)
|
||||||
|
await ctx.send('Patreon has been disabled for this guild.')
|
||||||
|
elif not patreon_status and state:
|
||||||
|
await self.bot.db_con.execute('update guild_config set patreon_enabled = $2 where guild_id = $1',
|
||||||
|
ctx.guild.id, state)
|
||||||
|
await ctx.send('Patreon has been enabled for this guild.')
|
||||||
|
elif not patreon_status and not state:
|
||||||
|
await ctx.send('Patreon is already disabled for this guild.')
|
||||||
|
|
||||||
|
@commands.command(aliases=['referral', 'ref'])
|
||||||
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
|
async def referral_links(self, ctx, target: discord.Member=None):
|
||||||
|
"""Prints G-Portal Referral Links."""
|
||||||
|
if await self.bot.db_con.fetchval('select referral_enabled from guild_config where guild_id = $1',
|
||||||
|
ctx.guild.id):
|
||||||
|
referral_info = await self.bot.db_con.fetchval('select referral_message,referral_links from guild_config '
|
||||||
|
'where guild_id = $1', ctx.guild.id)
|
||||||
|
message = referral_info[0]
|
||||||
|
referral_links = json.loads(referral_info[1])
|
||||||
|
for key in referral_links:
|
||||||
|
message = message + '\n{0}: {1}'.format(key, referral_links[key])
|
||||||
|
if target is None:
|
||||||
|
await ctx.send(message)
|
||||||
|
else:
|
||||||
|
await ctx.send('{0}\n{1}'.format(target.mention, message))
|
||||||
|
else:
|
||||||
|
await ctx.send('Referrals are not enabled on this guild.')
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Patreon(bot))
|
||||||
@ -0,0 +1,171 @@
|
|||||||
|
|
||||||
|
from discord.ext import commands
|
||||||
|
import asyncio
|
||||||
|
import traceback
|
||||||
|
import discord
|
||||||
|
import inspect
|
||||||
|
import textwrap
|
||||||
|
from contextlib import redirect_stdout
|
||||||
|
import io
|
||||||
|
from src.imports.utils import run_command, format_output, Paginator
|
||||||
|
|
||||||
|
ownerids = [351794468870946827, 275280442884751360]
|
||||||
|
ownerid = 351794468870946827
|
||||||
|
|
||||||
|
|
||||||
|
class Repl:
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
self._last_result = None
|
||||||
|
self.sessions = set()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cleanup_code(content):
|
||||||
|
"""Automatically removes code blocks from the code."""
|
||||||
|
if content.startswith('```') and content.endswith('```'):
|
||||||
|
return '\n'.join(content.split('\n')[1:(- 1)])
|
||||||
|
return content.strip('` \n')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_syntax_error(e):
|
||||||
|
if e.text is None:
|
||||||
|
return '```py\n{0.__class__.__name__}: {0}\n```'.format(e)
|
||||||
|
return '```py\n{0.text}{1:>{0.offset}}\n{2}: {0}```'.format(e, '^', type(e).__name__)
|
||||||
|
|
||||||
|
@commands.command(hidden=True, name='exec')
|
||||||
|
async def _eval(self, ctx, *, body: str):
|
||||||
|
if ctx.author.id != ownerid:
|
||||||
|
return
|
||||||
|
pag = Paginator(self.bot)
|
||||||
|
env = {
|
||||||
|
'bot': self.bot,
|
||||||
|
'ctx': ctx,
|
||||||
|
'channel': ctx.channel,
|
||||||
|
'author': ctx.author,
|
||||||
|
'server': ctx.guild,
|
||||||
|
'message': ctx.message,
|
||||||
|
'_': self._last_result,
|
||||||
|
}
|
||||||
|
env.update(globals())
|
||||||
|
body = self.cleanup_code(body)
|
||||||
|
stdout = io.StringIO()
|
||||||
|
to_compile = 'async def func():\n%s' % textwrap.indent(body, ' ')
|
||||||
|
try:
|
||||||
|
exec(to_compile, env)
|
||||||
|
except SyntaxError as e:
|
||||||
|
return await ctx.send(self.get_syntax_error(e))
|
||||||
|
func = env['func']
|
||||||
|
# noinspection PyBroadException
|
||||||
|
try:
|
||||||
|
with redirect_stdout(stdout):
|
||||||
|
ret = await func()
|
||||||
|
except Exception:
|
||||||
|
pag.add(stdout.getvalue())
|
||||||
|
pag.add(traceback.format_exc())
|
||||||
|
for page in pag.pages():
|
||||||
|
await ctx.send(page)
|
||||||
|
else:
|
||||||
|
value = stdout.getvalue()
|
||||||
|
# noinspection PyBroadException
|
||||||
|
try:
|
||||||
|
await ctx.message.add_reaction('✅')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
value = format_output(value)
|
||||||
|
pag.add(value)
|
||||||
|
pag.add(f'\nReturned: {ret}')
|
||||||
|
self._last_result = ret
|
||||||
|
for page in pag.pages():
|
||||||
|
await ctx.send(page)
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
async def repl(self, ctx):
|
||||||
|
if ctx.author.id != ownerid:
|
||||||
|
return
|
||||||
|
msg = ctx.message
|
||||||
|
variables = {
|
||||||
|
'ctx': ctx,
|
||||||
|
'bot': self.bot,
|
||||||
|
'message': msg,
|
||||||
|
'server': msg.guild,
|
||||||
|
'channel': msg.channel,
|
||||||
|
'author': msg.author,
|
||||||
|
'_': None,
|
||||||
|
}
|
||||||
|
if msg.channel.id in self.sessions:
|
||||||
|
await ctx.send('Already running a REPL session in this channel. Exit it with `quit`.')
|
||||||
|
return
|
||||||
|
self.sessions.add(msg.channel.id)
|
||||||
|
await ctx.send('Enter code to execute or evaluate. `exit()` or `quit` to exit.')
|
||||||
|
while True:
|
||||||
|
response = await self.bot.wait_for('message', check=(lambda m: m.content.startswith('`')))
|
||||||
|
if response.author.id == ownerid:
|
||||||
|
cleaned = self.cleanup_code(response.content)
|
||||||
|
if cleaned in ('quit', 'exit', 'exit()'):
|
||||||
|
await response.channel.send('Exiting.')
|
||||||
|
self.sessions.remove(msg.channel.id)
|
||||||
|
return
|
||||||
|
executor = exec
|
||||||
|
if cleaned.count('\n') == 0:
|
||||||
|
try:
|
||||||
|
code = compile(cleaned, '<repl session>', 'eval')
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
executor = eval
|
||||||
|
if executor is exec:
|
||||||
|
try:
|
||||||
|
code = compile(cleaned, '<repl session>', 'exec')
|
||||||
|
except SyntaxError as e:
|
||||||
|
await response.channel.send(self.get_syntax_error(e))
|
||||||
|
continue
|
||||||
|
variables['message'] = response
|
||||||
|
fmt = None
|
||||||
|
stdout = io.StringIO()
|
||||||
|
# noinspection PyBroadException
|
||||||
|
try:
|
||||||
|
with redirect_stdout(stdout):
|
||||||
|
result = executor(code, variables)
|
||||||
|
if inspect.isawaitable(result):
|
||||||
|
result = await result
|
||||||
|
except Exception:
|
||||||
|
value = stdout.getvalue()
|
||||||
|
fmt = '{}{}'.format(value, traceback.format_exc())
|
||||||
|
else:
|
||||||
|
value = stdout.getvalue()
|
||||||
|
if result is not None:
|
||||||
|
fmt = '{}{}'.format(value, result)
|
||||||
|
variables['_'] = result
|
||||||
|
elif value:
|
||||||
|
fmt = '{}'.format(value)
|
||||||
|
try:
|
||||||
|
if fmt is not None:
|
||||||
|
pag = Paginator(self.bot)
|
||||||
|
pag.add(fmt)
|
||||||
|
for page in pag.pages():
|
||||||
|
await response.channel.send(page)
|
||||||
|
await ctx.send(response.channel)
|
||||||
|
except discord.Forbidden:
|
||||||
|
pass
|
||||||
|
except discord.HTTPException as e:
|
||||||
|
await msg.channel.send('Unexpected error: `{}`'.format(e))
|
||||||
|
|
||||||
|
@commands.command(hidden=True)
|
||||||
|
async def os(self, ctx, *, body: str):
|
||||||
|
if ctx.author.id != ownerid:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
body = self.cleanup_code(body)
|
||||||
|
pag = Paginator(self.bot)
|
||||||
|
pag.add(await asyncio.wait_for(self.bot.loop.create_task(run_command(body)), 10))
|
||||||
|
for page in pag.pages():
|
||||||
|
await ctx.send(page)
|
||||||
|
await ctx.message.add_reaction('✅')
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await ctx.send(f"Command did not complete in the time allowed.")
|
||||||
|
await ctx.message.add_reaction('❌')
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Repl(bot))
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
import discord
|
||||||
|
import json
|
||||||
|
from src.imports import utils
|
||||||
|
|
||||||
|
owner_id = 351794468870946827
|
||||||
|
|
||||||
|
|
||||||
|
async def check_admin_role(bot, ctx, member):
|
||||||
|
admin_roles = json.loads(await bot.db_con.fetchval(f"select admin_roles from guild_config where guild_id = $1",
|
||||||
|
ctx.guild.id))
|
||||||
|
for role in admin_roles:
|
||||||
|
if discord.utils.get(ctx.guild.roles, id=admin_roles[role]) in member.roles:
|
||||||
|
return True
|
||||||
|
return member.id == ctx.guild.owner.id or member.id == owner_id
|
||||||
|
|
||||||
|
|
||||||
|
async def check_rcon_role(bot, ctx, member):
|
||||||
|
rcon_admin_roles = json.loads(await bot.db_con.fetchval("select rcon_admin_roles from guild_config "
|
||||||
|
"where guild_id = $1", ctx.guild.id))
|
||||||
|
for role in rcon_admin_roles:
|
||||||
|
if discord.utils.get(ctx.guild.roles, id=rcon_admin_roles[role]) in member.roles:
|
||||||
|
return True
|
||||||
|
return member.id == ctx.guild.owner.id or member.id == owner_id
|
||||||
|
|
||||||
|
|
||||||
|
async def is_admin(bot, ctx):
|
||||||
|
admin_roles = json.loads(await bot.db_con.fetchval("select admin_roles from guild_config where guild_id = $1",
|
||||||
|
ctx.guild.id))
|
||||||
|
for role in admin_roles:
|
||||||
|
if discord.utils.get(ctx.guild.roles, id=admin_roles[role]) in ctx.message.author.roles:
|
||||||
|
return True
|
||||||
|
return ctx.message.author.id == ctx.guild.owner.id or ctx.message.author.id == owner_id
|
||||||
|
|
||||||
|
|
||||||
|
async def is_guild_owner(ctx):
|
||||||
|
if ctx.guild:
|
||||||
|
return ctx.message.author.id == ctx.guild.owner.id or ctx.message.author.id == owner_id
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
async def is_rcon_admin(bot, ctx):
|
||||||
|
rcon_admin_roles = json.loads(await bot.db_con.fetchval("select rcon_admin_roles from guild_config "
|
||||||
|
"where guild_id = $1", ctx.guild.id))
|
||||||
|
for role in rcon_admin_roles:
|
||||||
|
if discord.utils.get(ctx.guild.roles, id=rcon_admin_roles[role]) in ctx.message.author.roles:
|
||||||
|
return True
|
||||||
|
return ctx.message.author.id == ctx.guild.owner.id or ctx.message.author.id == owner_id
|
||||||
|
|
||||||
|
|
||||||
|
def is_restricted_chan(ctx):
|
||||||
|
if ctx.guild:
|
||||||
|
if ctx.channel.overwrites_for(ctx.guild.default_role).read_messages is False:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
async def is_spam(bot, ctx):
|
||||||
|
max_rep = 5
|
||||||
|
rep_time = 20
|
||||||
|
spam_rep = 5
|
||||||
|
spam_time = 3
|
||||||
|
spam_check = 0
|
||||||
|
msg_check = 0
|
||||||
|
for msg in bot.recent_msgs[ctx.guild.id]:
|
||||||
|
if msg['author'] == ctx.author:
|
||||||
|
if msg['time'] > ctx.message.created_at.timestamp() - spam_time:
|
||||||
|
spam_check += 1
|
||||||
|
if msg['content'].lower() == ctx.content.lower() \
|
||||||
|
and msg['time'] > ctx.message.created_at.timestamp() - rep_time:
|
||||||
|
msg_check += 1
|
||||||
|
if spam_check == spam_rep - 1 or msg_check == max_rep - 1:
|
||||||
|
await utils.mute(bot, ctx, admin=1, member=ctx.author.id)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
@ -0,0 +1,449 @@
|
|||||||
|
from io import StringIO
|
||||||
|
import sys
|
||||||
|
import asyncio
|
||||||
|
import discord
|
||||||
|
from discord.ext.commands.formatter import Paginator as DannyPag
|
||||||
|
from src.imports import checks
|
||||||
|
import re
|
||||||
|
import typing
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class Capturing(list):
|
||||||
|
def __enter__(self):
|
||||||
|
self._stdout = sys.stdout
|
||||||
|
sys.stdout = self._stringio = StringIO()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *args):
|
||||||
|
self.extend(self._stringio.getvalue().splitlines())
|
||||||
|
del self._stringio # free up some memory
|
||||||
|
sys.stdout = self._stdout
|
||||||
|
|
||||||
|
|
||||||
|
async def mute(bot, ctx, admin=0, member_id=None):
|
||||||
|
mute_role = bot.db_con.fetchval(f'select muted_role from guild_config where guild_id = $1', ctx.guild.id)
|
||||||
|
if mute_role:
|
||||||
|
if admin or await checks.is_admin(bot, ctx):
|
||||||
|
if ctx.guild.me.guild_permissions.manage_roles:
|
||||||
|
if member_id:
|
||||||
|
ctx.guild.get_member(member_id).edit(roles=[discord.utils.get(ctx.guild.roles, id=mute_role)])
|
||||||
|
|
||||||
|
|
||||||
|
def to_list_of_str(items, out: list=list(), level=1, recurse=0):
|
||||||
|
# noinspection PyShadowingNames
|
||||||
|
def rec_loop(item, key, out, level):
|
||||||
|
quote = '"'
|
||||||
|
if type(item) == list:
|
||||||
|
out.append(f'{" "*level}{quote+key+quote+": " if key else ""}[')
|
||||||
|
new_level = level + 1
|
||||||
|
out = to_list_of_str(item, out, new_level, 1)
|
||||||
|
out.append(f'{" "*level}]')
|
||||||
|
elif type(item) == dict:
|
||||||
|
out.append(f'{" "*level}{quote+key+quote+": " if key else ""}{{')
|
||||||
|
new_level = level + 1
|
||||||
|
out = to_list_of_str(item, out, new_level, 1)
|
||||||
|
out.append(f'{" "*level}}}')
|
||||||
|
else:
|
||||||
|
out.append(f'{" "*level}{quote+key+quote+": " if key else ""}{repr(item)},')
|
||||||
|
|
||||||
|
if type(items) == list:
|
||||||
|
if not recurse:
|
||||||
|
out = list()
|
||||||
|
out.append('[')
|
||||||
|
for item in items:
|
||||||
|
rec_loop(item, None, out, level)
|
||||||
|
if not recurse:
|
||||||
|
out.append(']')
|
||||||
|
elif type(items) == dict:
|
||||||
|
if not recurse:
|
||||||
|
out = list()
|
||||||
|
out.append('{')
|
||||||
|
for key in items:
|
||||||
|
rec_loop(items[key], key, out, level)
|
||||||
|
if not recurse:
|
||||||
|
out.append('}')
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def format_output(text):
|
||||||
|
if type(text) == list:
|
||||||
|
text = to_list_of_str(text)
|
||||||
|
elif type(text) == dict:
|
||||||
|
text = to_list_of_str(text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def replace_text_ignorecase(in_str: str, old: str, new: str='') -> str:
|
||||||
|
re_replace = re.compile(re.escape(old), re.IGNORECASE)
|
||||||
|
return re_replace.sub(f'{new}', in_str)
|
||||||
|
|
||||||
|
|
||||||
|
async def run_command(args):
|
||||||
|
# Create subprocess
|
||||||
|
process = await asyncio.create_subprocess_shell(
|
||||||
|
args,
|
||||||
|
# stdout must a pipe to be accessible as process.stdout
|
||||||
|
stdout=asyncio.subprocess.PIPE)
|
||||||
|
# Wait for the subprocess to finish
|
||||||
|
stdout, stderr = await process.communicate()
|
||||||
|
# Return stdout
|
||||||
|
return stdout.decode().strip()
|
||||||
|
|
||||||
|
|
||||||
|
class Paginator:
|
||||||
|
def __init__(self,
|
||||||
|
bot: discord.ext.commands.Bot,
|
||||||
|
*,
|
||||||
|
max_chars: int=1970,
|
||||||
|
max_lines: int=20,
|
||||||
|
prefix: str='```md',
|
||||||
|
suffix: str='```',
|
||||||
|
page_break: str='\uFFF8',
|
||||||
|
field_break: str='\uFFF7',
|
||||||
|
field_name_char: str='\uFFF6',
|
||||||
|
inline_char: str='\uFFF5',
|
||||||
|
max_line_length: int=100,
|
||||||
|
embed=False):
|
||||||
|
_max_len = 6000 if embed else 1980
|
||||||
|
assert 0 < max_lines <= max_chars
|
||||||
|
assert 0 < max_line_length < 120
|
||||||
|
|
||||||
|
self._parts = list()
|
||||||
|
self._prefix = prefix
|
||||||
|
self._suffix = suffix
|
||||||
|
self._max_chars = max_chars if max_chars + len(prefix) + len(suffix) + 2 <= _max_len \
|
||||||
|
else _max_len - len(prefix) - len(suffix) - 2
|
||||||
|
self._max_lines = max_lines - (prefix + suffix).count('\n') + 1
|
||||||
|
self._page_break = page_break
|
||||||
|
self._max_line_length = max_line_length
|
||||||
|
self._pages = list()
|
||||||
|
self._max_field_chars = 1014
|
||||||
|
self._max_field_name = 256
|
||||||
|
self._max_description = 2048
|
||||||
|
self._embed = embed
|
||||||
|
self._field_break = field_break
|
||||||
|
self._field_name_char = field_name_char
|
||||||
|
self._inline_char = inline_char
|
||||||
|
self._embed_title = ''
|
||||||
|
self._embed_description = ''
|
||||||
|
self._embed_color = None
|
||||||
|
self._embed_thumbnail = None
|
||||||
|
self._embed_url = None
|
||||||
|
self._bot = bot
|
||||||
|
|
||||||
|
def set_embed_meta(self, title: str='\uFFF0',
|
||||||
|
description: str='\uFFF0',
|
||||||
|
color: discord.Colour=None,
|
||||||
|
thumbnail: str=None,
|
||||||
|
url: str=None):
|
||||||
|
if len(title) <= self._max_field_name:
|
||||||
|
self._embed_title = title
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Provided Title is too long')
|
||||||
|
if len(description) <= self._max_description:
|
||||||
|
self._embed_description = description
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Provided Description is too long')
|
||||||
|
self._embed_color = color
|
||||||
|
self._embed_thumbnail = thumbnail
|
||||||
|
self._embed_url = url
|
||||||
|
|
||||||
|
def pages(self) -> typing.List[str]:
|
||||||
|
_pages = list()
|
||||||
|
_fields = list()
|
||||||
|
_page = ''
|
||||||
|
_lines = 0
|
||||||
|
_field_name = ''
|
||||||
|
_field_value = ''
|
||||||
|
_inline = False
|
||||||
|
|
||||||
|
def open_page():
|
||||||
|
nonlocal _page, _lines, _fields
|
||||||
|
if not self._embed:
|
||||||
|
_page = self._prefix
|
||||||
|
_lines = 0
|
||||||
|
else:
|
||||||
|
_fields = list()
|
||||||
|
|
||||||
|
def close_page():
|
||||||
|
nonlocal _page, _lines, _fields
|
||||||
|
if not self._embed:
|
||||||
|
_page += self._suffix
|
||||||
|
_pages.append(_page)
|
||||||
|
else:
|
||||||
|
if _fields:
|
||||||
|
_pages.append(_fields)
|
||||||
|
open_page()
|
||||||
|
|
||||||
|
open_page()
|
||||||
|
|
||||||
|
if not self._embed:
|
||||||
|
for part in [str(p) for p in self._parts]:
|
||||||
|
if part == self._page_break:
|
||||||
|
close_page()
|
||||||
|
|
||||||
|
new_chars = len(_page) + len(part)
|
||||||
|
|
||||||
|
if new_chars > self._max_chars:
|
||||||
|
close_page()
|
||||||
|
elif (_lines + (part.count('\n') + 1 or 1)) > self._max_lines:
|
||||||
|
close_page()
|
||||||
|
|
||||||
|
_lines += (part.count('\n') + 1 or 1)
|
||||||
|
_page += '\n' + part
|
||||||
|
else:
|
||||||
|
def open_field(name: str):
|
||||||
|
nonlocal _field_value, _field_name
|
||||||
|
_field_name = name
|
||||||
|
_field_value = self._prefix
|
||||||
|
|
||||||
|
def close_field(next_name: str=None):
|
||||||
|
nonlocal _field_name, _field_value, _fields
|
||||||
|
_field_value += self._suffix
|
||||||
|
if _field_value != self._prefix + self._suffix:
|
||||||
|
_fields.append({'name': _field_name, 'value': _field_value, 'inline': _inline})
|
||||||
|
if next_name:
|
||||||
|
open_field(next_name)
|
||||||
|
|
||||||
|
open_field('\uFFF0')
|
||||||
|
|
||||||
|
for part in [str(p) for p in self._parts]:
|
||||||
|
if part == self._page_break:
|
||||||
|
close_page()
|
||||||
|
continue
|
||||||
|
elif part == self._field_break:
|
||||||
|
if len(_fields) + 1 < 25:
|
||||||
|
close_field(next_name='\uFFF0')
|
||||||
|
else:
|
||||||
|
close_field()
|
||||||
|
close_page()
|
||||||
|
continue
|
||||||
|
|
||||||
|
if part.startswith(self._field_name_char):
|
||||||
|
part = part.replace(self._field_name_char, '')
|
||||||
|
if part.startswith(self._inline_char):
|
||||||
|
_inline = True
|
||||||
|
part = part.replace(self._inline_char, '')
|
||||||
|
else:
|
||||||
|
_inline = False
|
||||||
|
if _field_value and _field_value != self._prefix:
|
||||||
|
close_field(part)
|
||||||
|
else:
|
||||||
|
_field_name = part
|
||||||
|
continue
|
||||||
|
|
||||||
|
_field_value += '\n' + part
|
||||||
|
|
||||||
|
close_field()
|
||||||
|
|
||||||
|
close_page()
|
||||||
|
self._pages = _pages
|
||||||
|
return _pages
|
||||||
|
|
||||||
|
def process_pages(self) -> typing.List[str]:
|
||||||
|
_pages = self._pages or self.pages()
|
||||||
|
_len_pages = len(_pages)
|
||||||
|
_len_page_str = len(f'{_len_pages}/{_len_pages}')
|
||||||
|
if not self._embed:
|
||||||
|
for i, page in enumerate(_pages):
|
||||||
|
if len(page) + _len_page_str <= 2000:
|
||||||
|
_pages[i] = f'{i + 1}/{_len_pages}\n{page}'
|
||||||
|
else:
|
||||||
|
for i, page in enumerate(_pages):
|
||||||
|
em = discord.Embed(title=self._embed_title,
|
||||||
|
description=self._embed_description,
|
||||||
|
color=self._bot.embed_color,
|
||||||
|
)
|
||||||
|
if self._embed_thumbnail:
|
||||||
|
em.set_thumbnail(url=self._embed_thumbnail)
|
||||||
|
if self._embed_url:
|
||||||
|
em.url = self._embed_url
|
||||||
|
if self._embed_color:
|
||||||
|
em.color = self._embed_color
|
||||||
|
em.set_footer(text=f'{i + 1}/{_len_pages}')
|
||||||
|
for field in page:
|
||||||
|
em.add_field(name=field['name'], value=field['value'], inline=field['inline'])
|
||||||
|
_pages[i] = em
|
||||||
|
return _pages
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return sum(len(p) for p in self._parts)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
# noinspection PyProtectedMember
|
||||||
|
return self.__class__ == other.__class__ and self._parts == other._parts
|
||||||
|
|
||||||
|
def add_page_break(self, *, to_beginning: bool=False) -> None:
|
||||||
|
self.add(self._page_break, to_beginning=to_beginning)
|
||||||
|
|
||||||
|
def add(self, item: typing.Any, *, to_beginning: bool=False, keep_intact: bool=False, truncate=False) -> None:
|
||||||
|
item = str(item)
|
||||||
|
i = 0
|
||||||
|
if not keep_intact and not item == self._page_break:
|
||||||
|
item_parts = item.strip('\n').split('\n')
|
||||||
|
for part in item_parts:
|
||||||
|
if len(part) > self._max_line_length:
|
||||||
|
if not truncate:
|
||||||
|
length = 0
|
||||||
|
out_str = ''
|
||||||
|
|
||||||
|
def close_line(line):
|
||||||
|
nonlocal i, out_str, length
|
||||||
|
self._parts.insert(i, out_str) if to_beginning else self._parts.append(out_str)
|
||||||
|
i += 1
|
||||||
|
out_str = line + ' '
|
||||||
|
length = len(out_str)
|
||||||
|
|
||||||
|
bits = part.split(' ')
|
||||||
|
for bit in bits:
|
||||||
|
next_len = length + len(bit) + 1
|
||||||
|
if next_len <= self._max_line_length:
|
||||||
|
out_str += bit + ' '
|
||||||
|
length = next_len
|
||||||
|
elif len(bit) > self._max_line_length:
|
||||||
|
if out_str:
|
||||||
|
close_line(line='')
|
||||||
|
for out_str in [bit[i:i + self._max_line_length]
|
||||||
|
for i in range(0, len(bit), self._max_line_length)]:
|
||||||
|
close_line('')
|
||||||
|
else:
|
||||||
|
close_line(bit)
|
||||||
|
close_line('')
|
||||||
|
else:
|
||||||
|
line = f'{part:.{self._max_line_length-3}}...'
|
||||||
|
self._parts.insert(i, line) if to_beginning else self._parts.append(line)
|
||||||
|
else:
|
||||||
|
self._parts.insert(i, part) if to_beginning else self._parts.append(part)
|
||||||
|
i += 1
|
||||||
|
elif keep_intact and not item == self._page_break:
|
||||||
|
if len(item) >= self._max_chars or item.count('\n') > self._max_lines:
|
||||||
|
raise RuntimeError('{item} is too long to keep on a single page and is marked to keep intact.')
|
||||||
|
if to_beginning:
|
||||||
|
self._parts.insert(0, item)
|
||||||
|
else:
|
||||||
|
self._parts.append(item)
|
||||||
|
else:
|
||||||
|
if to_beginning:
|
||||||
|
self._parts.insert(0, item)
|
||||||
|
else:
|
||||||
|
self._parts.append(item)
|
||||||
|
|
||||||
|
|
||||||
|
class Book:
|
||||||
|
def __init__(self, pag: Paginator, ctx: typing.Tuple[typing.Optional[discord.Message],
|
||||||
|
discord.TextChannel,
|
||||||
|
discord.ext.commands.Bot,
|
||||||
|
discord.Message]) -> None:
|
||||||
|
self._pages = pag.process_pages()
|
||||||
|
self._len_pages = len(self._pages)
|
||||||
|
self._current_page = 0
|
||||||
|
self._message, self._channel, self._bot, self._calling_message = ctx
|
||||||
|
self._locked = True
|
||||||
|
if pag == Paginator(self._bot):
|
||||||
|
raise RuntimeError('Cannot create a book out of an empty Paginator.')
|
||||||
|
|
||||||
|
def advance_page(self) -> None:
|
||||||
|
self._current_page += 1
|
||||||
|
if self._current_page >= self._len_pages:
|
||||||
|
self._current_page = 0
|
||||||
|
|
||||||
|
def reverse_page(self) -> None:
|
||||||
|
self._current_page += -1
|
||||||
|
if self._current_page < 0:
|
||||||
|
self._current_page = self._len_pages - 1
|
||||||
|
|
||||||
|
async def display_page(self) -> None:
|
||||||
|
if isinstance(self._pages[self._current_page], discord.Embed):
|
||||||
|
if self._message:
|
||||||
|
await self._message.edit(content=None, embed=self._pages[self._current_page])
|
||||||
|
else:
|
||||||
|
self._message = await self._channel.send(embed=self._pages[self._current_page])
|
||||||
|
else:
|
||||||
|
if self._message:
|
||||||
|
await self._message.edit(content=self._pages[self._current_page], embed=None)
|
||||||
|
else:
|
||||||
|
self._message = await self._channel.send(self._pages[self._current_page])
|
||||||
|
|
||||||
|
async def create_book(self) -> None:
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
|
async def reaction_checker():
|
||||||
|
# noinspection PyShadowingNames
|
||||||
|
def check(reaction, user):
|
||||||
|
if self._locked:
|
||||||
|
return str(reaction.emoji) in self._bot.book_emojis.values() \
|
||||||
|
and user == self._calling_message.author \
|
||||||
|
and reaction.message.id == self._message.id
|
||||||
|
else:
|
||||||
|
return str(reaction.emoji) in self._bot.book_emojis.values() \
|
||||||
|
and reaction.message.id == self._message.id
|
||||||
|
|
||||||
|
await self.display_page()
|
||||||
|
|
||||||
|
if len(self._pages) > 1:
|
||||||
|
for emoji in self._bot.book_emojis.values():
|
||||||
|
try:
|
||||||
|
await self._message.add_reaction(emoji)
|
||||||
|
except (discord.Forbidden, KeyError):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
await self._message.add_reaction(self._bot.book_emojis['unlock'])
|
||||||
|
await self._message.add_reaction(self._bot.book_emojis['close'])
|
||||||
|
except (discord.Forbidden, KeyError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
reaction, user = await self._bot.wait_for('reaction_add', timeout=60, check=check)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
try:
|
||||||
|
await self._message.clear_reactions()
|
||||||
|
except discord.Forbidden:
|
||||||
|
pass
|
||||||
|
raise asyncio.CancelledError
|
||||||
|
else:
|
||||||
|
await self._message.remove_reaction(reaction, user)
|
||||||
|
if str(reaction.emoji) == self._bot.book_emojis['close']:
|
||||||
|
await self._calling_message.delete()
|
||||||
|
await self._message.delete()
|
||||||
|
raise asyncio.CancelledError
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['forward']:
|
||||||
|
self.advance_page()
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['back']:
|
||||||
|
self.reverse_page()
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['end']:
|
||||||
|
self._current_page = self._len_pages - 1
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['start']:
|
||||||
|
self._current_page = 0
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['hash']:
|
||||||
|
m = await self._channel.send(f'Please enter a number in range 1 to {self._len_pages}')
|
||||||
|
|
||||||
|
def num_check(message):
|
||||||
|
if self._locked:
|
||||||
|
return message.content.isdigit() \
|
||||||
|
and 0 < int(message.content) <= self._len_pages \
|
||||||
|
and message.author == self._calling_message.author
|
||||||
|
else:
|
||||||
|
return message.content.isdigit() \
|
||||||
|
and 0 < int(message.content) <= self._len_pages
|
||||||
|
|
||||||
|
try:
|
||||||
|
msg = await self._bot.wait_for('message', timeout=30, check=num_check)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await m.edit(content='Message Timed out.')
|
||||||
|
else:
|
||||||
|
self._current_page = int(msg.content) - 1
|
||||||
|
try:
|
||||||
|
await m.delete()
|
||||||
|
await msg.delete()
|
||||||
|
except discord.Forbidden:
|
||||||
|
pass
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['unlock']:
|
||||||
|
self._locked = False
|
||||||
|
await self._message.remove_reaction(reaction, self._channel.guild.me)
|
||||||
|
continue
|
||||||
|
await self.display_page()
|
||||||
|
|
||||||
|
self._bot.loop.create_task(reaction_checker())
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import asyncpg
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseConnection:
|
||||||
|
def __init__(self, host: str='localhost', port: int=5432, database: str='', user: str='', password: str=''):
|
||||||
|
if user == '' or password == '' or database == '':
|
||||||
|
raise RuntimeError('Username or Password are blank')
|
||||||
|
self.kwargs = {'host': host, 'port': port, 'database': database, 'user': user, 'password': password}
|
||||||
|
self._conn = None
|
||||||
|
asyncio.get_event_loop().run_until_complete(self.acquire())
|
||||||
|
self.fetchval = self._conn.fetchval
|
||||||
|
self.execute = self._conn.execute
|
||||||
|
self.fetch = self._conn.fetch
|
||||||
|
self.fetchrow = self._conn.fetchrow
|
||||||
|
|
||||||
|
async def acquire(self):
|
||||||
|
if not self._conn:
|
||||||
|
self._conn = await asyncpg.create_pool(**self.kwargs)
|
||||||
|
|
||||||
|
async def close(self):
|
||||||
|
await self._conn.close()
|
||||||
|
self._conn = None
|
||||||
@ -1,20 +0,0 @@
|
|||||||
package geeksbot
|
|
||||||
|
|
||||||
import "database/sql"
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
ID string
|
|
||||||
SteamID sql.NullString
|
|
||||||
IsActive bool
|
|
||||||
IsStaff bool
|
|
||||||
IsAdmin bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserService interface {
|
|
||||||
User(id string) (User, error)
|
|
||||||
CreateUser(u User) (User, error)
|
|
||||||
DeleteUser(u User) error
|
|
||||||
UpdateUser(u User) (User, error)
|
|
||||||
GetOrCreateUser(id string) (User, error)
|
|
||||||
GetBySteamID(steamID string) (User, error)
|
|
||||||
}
|
|
||||||
Loading…
Reference in new issue