Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4db28f5c0b | ||
|
|
fb4d7977aa | ||
|
|
30394b35e5 | ||
|
|
87961c5081 | ||
|
|
562ec6acaf | ||
|
|
3169953f3f | ||
|
|
d119425236 | ||
|
|
ce1bbbc445 | ||
|
|
f4ec8a7a49 | ||
|
|
bec52ad5a5 | ||
|
|
5411730a96 | ||
|
|
187f9816ca | ||
|
|
feab8e661c | ||
|
|
96b63a4e83 | ||
|
|
fcddca2226 | ||
|
|
28d78bdb8c | ||
|
|
35882993c2 | ||
|
|
85bcb31d56 | ||
|
|
23c0434ed3 | ||
|
|
e9adc05536 | ||
|
|
b8ee6a1505 | ||
|
|
ac46753546 | ||
|
|
d16521e5e3 | ||
|
|
4955f4bf88 | ||
|
|
c3d2073b2b | ||
|
|
1ddc4d4c36 | ||
|
|
d66a25a525 | ||
|
|
6c05518146 |
44
.github/workflows/main.yml
vendored
Normal file
44
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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: Configure AWS credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v1
|
||||||
|
with:
|
||||||
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
aws-region: us-east-1
|
||||||
|
|
||||||
|
- name: Login to Amazon ECR
|
||||||
|
id: login-ecr
|
||||||
|
uses: aws-actions/amazon-ecr-login@v1
|
||||||
|
|
||||||
|
- name: Get Version
|
||||||
|
id: get_version
|
||||||
|
uses: battila7/get-version-action@v2.0.0
|
||||||
|
|
||||||
|
- name: Build, tag, and push image to Amazon ECR
|
||||||
|
env:
|
||||||
|
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||||
|
ECR_REPOSITORY: goff
|
||||||
|
IMAGE_TAG: ${{ steps.get_version.outputs.version-without-v }}
|
||||||
|
run: |
|
||||||
|
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
|
||||||
|
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
|
||||||
|
docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest
|
||||||
|
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest
|
||||||
19
Dockerfile
19
Dockerfile
@ -1,13 +1,20 @@
|
|||||||
FROM golang:1.14-alpine
|
FROM golang:1.14-alpine as dev
|
||||||
|
|
||||||
WORKDIR /go/src/Goff
|
WORKDIR /go/src/Goff
|
||||||
COPY ./go.mod .
|
COPY ./go.mod .
|
||||||
|
COPY ./go.sum .
|
||||||
|
|
||||||
RUN apk add --no-cache git
|
RUN go mod download
|
||||||
|
|
||||||
RUN go get -d -v ./...
|
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN go install -v ./...
|
RUN go install github.com/dustinpianalto/goff
|
||||||
|
|
||||||
ENTRYPOINT /go/bin/goff
|
CMD [ "go", "run", "goff.go"]
|
||||||
|
|
||||||
|
from alpine
|
||||||
|
|
||||||
|
WORKDIR /bin
|
||||||
|
|
||||||
|
COPY --from=dev /go/bin/goff ./goff
|
||||||
|
|
||||||
|
CMD [ "goff" ]
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
package events
|
package events
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/dustinpianalto/goff/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func OnGuildMemberAddLogging(s *discordgo.Session, member *discordgo.GuildMemberAdd) {
|
func OnGuildMemberAddLogging(s *discordgo.Session, member *discordgo.GuildMemberAdd) {
|
||||||
@ -4,8 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/dustinpianalto/goff/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func OnMessageUpdate(session *discordgo.Session, m *discordgo.MessageUpdate) {
|
func OnMessageUpdate(session *discordgo.Session, m *discordgo.MessageUpdate) {
|
||||||
@ -2,8 +2,11 @@ package exts
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dustinpianalto/disgoman"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/dustinpianalto/disgoman"
|
||||||
|
"github.com/dustinpianalto/rpnparse"
|
||||||
)
|
)
|
||||||
|
|
||||||
func interleave(ctx disgoman.Context, args []string) {
|
func interleave(ctx disgoman.Context, args []string) {
|
||||||
@ -47,3 +50,35 @@ func deinterleave(ctx disgoman.Context, args []string) {
|
|||||||
ctx.Send(fmt.Sprintf("(%v, %v)", x, y))
|
ctx.Send(fmt.Sprintf("(%v, %v)", x, y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateRPNCommand(ctx disgoman.Context, args []string) {
|
||||||
|
rpn, err := rpnparse.GenerateRPN(args)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Send(rpn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRPNCommand(ctx disgoman.Context, args []string) {
|
||||||
|
res, err := rpnparse.ParseRPN(args)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Send(fmt.Sprintf("The result is: %v", res))
|
||||||
|
}
|
||||||
|
|
||||||
|
func solveCommand(ctx disgoman.Context, args []string) {
|
||||||
|
rpn, err := rpnparse.GenerateRPN(args)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := rpnparse.ParseRPN(strings.Split(rpn, " "))
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Send(fmt.Sprintf("The result is: %v", res))
|
||||||
|
}
|
||||||
@ -1,11 +1,12 @@
|
|||||||
package exts
|
package exts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
|
||||||
"github.com/dustinpianalto/disgoman"
|
"github.com/dustinpianalto/disgoman"
|
||||||
|
"github.com/dustinpianalto/goff/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Guild management commands
|
// Guild management commands
|
||||||
@ -288,3 +289,88 @@ func getPuzzleChannel(ctx disgoman.Context, _ []string) {
|
|||||||
_, _ = ctx.Send(fmt.Sprintf("The puzzle channel is currently %s", channel.Mention()))
|
_, _ = ctx.Send(fmt.Sprintf("The puzzle channel is currently %s", channel.Mention()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func puzzleRole(ctx disgoman.Context, args []string) {
|
||||||
|
var idString string
|
||||||
|
if len(args) > 0 {
|
||||||
|
idString = args[0]
|
||||||
|
if strings.HasPrefix(idString, "<@&") && strings.HasSuffix(idString, ">") {
|
||||||
|
idString = idString[3 : len(idString)-1]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
idString = ""
|
||||||
|
}
|
||||||
|
fmt.Println(idString)
|
||||||
|
if idString == "" {
|
||||||
|
_, err := utils.Database.Exec("UPDATE guilds SET puzzle_role=NULL WHERE id=$1;", ctx.Guild.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Error Updating Database",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, _ = ctx.Send("Puzzle Role Cleared.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
role, err := ctx.Session.State.Role(ctx.Guild.ID, idString)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Can't find that Role.",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = utils.Database.Exec("INSERT INTO roles (id, guild_id) VALUES ($1, $2) ON CONFLICT DO NOTHING", role.ID, ctx.Guild.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Error Updating Database",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = utils.Database.Exec("UPDATE guilds SET puzzle_role=$1 WHERE id=$2;", role.ID, ctx.Guild.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Error Updating Database",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, _ = ctx.Send("Puzzle Role Updated.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPuzzleRole(ctx disgoman.Context, _ []string) {
|
||||||
|
var roleID sql.NullString
|
||||||
|
row := utils.Database.QueryRow("SELECT puzzle_role FROM guilds where id=$1", ctx.Guild.ID)
|
||||||
|
err := row.Scan(&roleID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Error getting data from the database.",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !roleID.Valid {
|
||||||
|
_, _ = ctx.Send("The puzzle role is not set.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
role, err := ctx.Session.State.Role(ctx.Guild.ID, roleID.String)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "I got the role ID but it does not appear to be a valid role in this guild.",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, _ = ctx.Send(fmt.Sprintf("The puzzle role is currently %s", role.Mention()))
|
||||||
|
return
|
||||||
|
}
|
||||||
@ -204,4 +204,85 @@ func AddCommandHandlers(h *disgoman.CommandManager) {
|
|||||||
RequiredPermissions: disgoman.PermissionManageServer,
|
RequiredPermissions: disgoman.PermissionManageServer,
|
||||||
Invoke: getPuzzleChannel,
|
Invoke: getPuzzleChannel,
|
||||||
})
|
})
|
||||||
|
_ = h.AddCommand(&disgoman.Command{
|
||||||
|
Name: "set-puzzle-role",
|
||||||
|
Aliases: []string{"spr"},
|
||||||
|
Description: "Set the role to be pinged when there is a new puzzle",
|
||||||
|
OwnerOnly: false,
|
||||||
|
Hidden: false,
|
||||||
|
RequiredPermissions: disgoman.PermissionManageServer,
|
||||||
|
Invoke: puzzleRole,
|
||||||
|
})
|
||||||
|
_ = h.AddCommand(&disgoman.Command{
|
||||||
|
Name: "get-puzzle-role",
|
||||||
|
Aliases: []string{"gpr"},
|
||||||
|
Description: "Get the role that will be pinged when there is a new puzzle",
|
||||||
|
OwnerOnly: false,
|
||||||
|
Hidden: false,
|
||||||
|
RequiredPermissions: disgoman.PermissionManageServer,
|
||||||
|
Invoke: getPuzzleRole,
|
||||||
|
})
|
||||||
|
_ = h.AddCommand(&disgoman.Command{
|
||||||
|
Name: "RPN",
|
||||||
|
Aliases: []string{"rpn"},
|
||||||
|
Description: "Convert infix to rpn",
|
||||||
|
OwnerOnly: false,
|
||||||
|
Hidden: false,
|
||||||
|
RequiredPermissions: 0,
|
||||||
|
Invoke: generateRPNCommand,
|
||||||
|
})
|
||||||
|
_ = h.AddCommand(&disgoman.Command{
|
||||||
|
Name: "ParseRPN",
|
||||||
|
Aliases: []string{"PRPN", "prpn"},
|
||||||
|
Description: "Parse RPN string and return the result",
|
||||||
|
OwnerOnly: false,
|
||||||
|
Hidden: false,
|
||||||
|
RequiredPermissions: 0,
|
||||||
|
Invoke: parseRPNCommand,
|
||||||
|
})
|
||||||
|
_ = h.AddCommand(&disgoman.Command{
|
||||||
|
Name: "solve",
|
||||||
|
Aliases: []string{"math", "infix"},
|
||||||
|
Description: "Solve infix equation and return the result",
|
||||||
|
OwnerOnly: false,
|
||||||
|
Hidden: false,
|
||||||
|
RequiredPermissions: 0,
|
||||||
|
Invoke: solveCommand,
|
||||||
|
})
|
||||||
|
_ = h.AddCommand(&disgoman.Command{
|
||||||
|
Name: "make-role-self-assignable",
|
||||||
|
Aliases: []string{"makesar"},
|
||||||
|
Description: "Makes the passed in role self assignable by anyone",
|
||||||
|
OwnerOnly: false,
|
||||||
|
Hidden: false,
|
||||||
|
RequiredPermissions: disgoman.PermissionManageServer,
|
||||||
|
Invoke: makeRoleSelfAssignable,
|
||||||
|
})
|
||||||
|
_ = h.AddCommand(&disgoman.Command{
|
||||||
|
Name: "remove-self-assignable-role",
|
||||||
|
Aliases: []string{"removesar"},
|
||||||
|
Description: "Makes a role that was previously self assignable not so",
|
||||||
|
OwnerOnly: false,
|
||||||
|
Hidden: false,
|
||||||
|
RequiredPermissions: disgoman.PermissionManageServer,
|
||||||
|
Invoke: removeSelfAssignableRole,
|
||||||
|
})
|
||||||
|
_ = h.AddCommand(&disgoman.Command{
|
||||||
|
Name: "giverole",
|
||||||
|
Aliases: []string{"iwant", "givetome"},
|
||||||
|
Description: "Assigns a person the passed in role if it is self assignable",
|
||||||
|
OwnerOnly: false,
|
||||||
|
Hidden: false,
|
||||||
|
RequiredPermissions: 0,
|
||||||
|
Invoke: selfAssignRole,
|
||||||
|
})
|
||||||
|
_ = h.AddCommand(&disgoman.Command{
|
||||||
|
Name: "removerole",
|
||||||
|
Aliases: []string{"idon'twant"},
|
||||||
|
Description: "Removes a role from a person if the role is self assignable",
|
||||||
|
OwnerOnly: false,
|
||||||
|
Hidden: false,
|
||||||
|
RequiredPermissions: 0,
|
||||||
|
Invoke: unAssignRole,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
216
exts/roles.go
Normal file
216
exts/roles.go
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
package exts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/dustinpianalto/disgoman"
|
||||||
|
"github.com/dustinpianalto/goff/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeRoleSelfAssignable(ctx disgoman.Context, args []string) {
|
||||||
|
var roleString string
|
||||||
|
var roleID string
|
||||||
|
if len(args) > 0 {
|
||||||
|
roleString = strings.Join(args, " ")
|
||||||
|
if strings.HasPrefix(roleString, "<@&") && strings.HasSuffix(roleString, ">") {
|
||||||
|
roleID = roleString[3 : len(roleString)-1]
|
||||||
|
} else if _, err := strconv.Atoi(roleString); err == nil {
|
||||||
|
roleID = roleString
|
||||||
|
} else {
|
||||||
|
for _, role := range ctx.Guild.Roles {
|
||||||
|
if roleString == role.Name {
|
||||||
|
roleID = role.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(roleID)
|
||||||
|
var role *discordgo.Role
|
||||||
|
var err error
|
||||||
|
if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Can't find that Role.",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = utils.Database.Exec("INSERT INTO roles (id, guild_id, self_assignable) VALUES ($1, $2, true) ON CONFLICT (id) DO UPDATE SET self_assignable=true", role.ID, ctx.Guild.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Error Updating Database",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, _ = ctx.Send(fmt.Sprintf("%s is now self assignable", role.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeSelfAssignableRole(ctx disgoman.Context, args []string) {
|
||||||
|
var roleString string
|
||||||
|
var roleID string
|
||||||
|
if len(args) > 0 {
|
||||||
|
roleString = strings.Join(args, " ")
|
||||||
|
if strings.HasPrefix(roleString, "<@&") && strings.HasSuffix(roleString, ">") {
|
||||||
|
roleID = roleString[3 : len(roleString)-1]
|
||||||
|
} else if _, err := strconv.Atoi(roleString); err == nil {
|
||||||
|
roleID = roleString
|
||||||
|
} else {
|
||||||
|
for _, role := range ctx.Guild.Roles {
|
||||||
|
if roleString == role.Name {
|
||||||
|
roleID = role.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(roleID)
|
||||||
|
var err error
|
||||||
|
var role *discordgo.Role
|
||||||
|
if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Can't find that Role.",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = utils.Database.Exec("INSERT INTO roles (id, guild_id, self_assignable) VALUES ($1, $2, false) ON CONFLICT (id) DO UPDATE SET self_assignable=false", role.ID, ctx.Guild.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Error Updating Database",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, _ = ctx.Send(fmt.Sprintf("%s's self assignability has been removed.", role.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func selfAssignRole(ctx disgoman.Context, args []string) {
|
||||||
|
var roleString string
|
||||||
|
var roleID string
|
||||||
|
if len(args) > 0 {
|
||||||
|
roleString = strings.Join(args, " ")
|
||||||
|
if strings.HasPrefix(roleString, "<@&") && strings.HasSuffix(roleString, ">") {
|
||||||
|
roleID = roleString[3 : len(roleString)-1]
|
||||||
|
} else if _, err := strconv.Atoi(roleString); err == nil {
|
||||||
|
roleID = roleString
|
||||||
|
} else {
|
||||||
|
for _, role := range ctx.Guild.Roles {
|
||||||
|
if roleString == role.Name {
|
||||||
|
roleID = role.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(roleID)
|
||||||
|
var role *discordgo.Role
|
||||||
|
var err error
|
||||||
|
if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Can't find that Role.",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if memberHasRole(ctx.Member, role.ID) {
|
||||||
|
_, _ = ctx.Send(fmt.Sprintf("You already have the %s role silly...", role.Name))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var selfAssignable bool
|
||||||
|
err = utils.Database.QueryRow("SELECT self_assignable FROM roles where id=$1", role.ID).Scan(&selfAssignable)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Error Updating Database",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !selfAssignable {
|
||||||
|
_, _ = ctx.Send(fmt.Sprintf("You aren't allowed to assign yourself the %s role", role.Name))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ctx.Session.GuildMemberRoleAdd(ctx.Guild.ID, ctx.User.ID, role.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "There was a problem adding that role to you.",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, _ = ctx.Send(fmt.Sprintf("Congratulations! The %s role has been added to your... Ummm... Thing.", role.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func unAssignRole(ctx disgoman.Context, args []string) {
|
||||||
|
var roleString string
|
||||||
|
var roleID string
|
||||||
|
if len(args) > 0 {
|
||||||
|
roleString = strings.Join(args, " ")
|
||||||
|
if strings.HasPrefix(roleString, "<@&") && strings.HasSuffix(roleString, ">") {
|
||||||
|
roleID = roleString[3 : len(roleString)-1]
|
||||||
|
} else if _, err := strconv.Atoi(roleString); err == nil {
|
||||||
|
roleID = roleString
|
||||||
|
} else {
|
||||||
|
for _, role := range ctx.Guild.Roles {
|
||||||
|
if roleString == role.Name {
|
||||||
|
roleID = role.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(roleID)
|
||||||
|
var role *discordgo.Role
|
||||||
|
var err error
|
||||||
|
if role, err = ctx.Session.State.Role(ctx.Guild.ID, roleID); err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Can't find that Role.",
|
||||||
|
Error: 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
|
||||||
|
}
|
||||||
|
var selfAssignable bool
|
||||||
|
err = utils.Database.QueryRow("SELECT self_assignable FROM roles where id=$1", role.ID).Scan(&selfAssignable)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "Error Updating Database",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !selfAssignable {
|
||||||
|
_, _ = ctx.Send(fmt.Sprintf("You aren't allowed to remove the %s role from yourself", role.Name))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ctx.Session.GuildMemberRoleRemove(ctx.Guild.ID, ctx.User.ID, role.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
|
Context: ctx,
|
||||||
|
Message: "There was a problem removing that role from you.",
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, _ = ctx.Send(fmt.Sprintf("Sad to see you go... but the %s role has been removed.", role.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func memberHasRole(m *discordgo.Member, id string) bool {
|
||||||
|
for _, r := range m.Roles {
|
||||||
|
if r == id {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@ -6,33 +6,19 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
|
||||||
"github.com/dustinpianalto/disgoman"
|
"github.com/dustinpianalto/disgoman"
|
||||||
"github.com/kballard/go-shellquote"
|
"github.com/dustinpianalto/goff/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addTagCommand(ctx disgoman.Context, input []string) {
|
func addTagCommand(ctx disgoman.Context, input []string) {
|
||||||
if len(input) >= 1 {
|
if len(input) >= 1 {
|
||||||
args, err := shellquote.Split(strings.Join(input, " "))
|
|
||||||
if err != nil {
|
|
||||||
if strings.Contains(err.Error(), "Unterminated") {
|
|
||||||
args = strings.SplitN(strings.Join(args, " "), " ", 2)
|
|
||||||
} else {
|
|
||||||
ctx.ErrorChannel <- disgoman.CommandError{
|
|
||||||
Context: ctx,
|
|
||||||
Message: "",
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queryString := `SELECT tags.id, tags.tag, tags.content from tags
|
queryString := `SELECT tags.id, tags.tag, tags.content from tags
|
||||||
WHERE tags.guild_id = $1
|
WHERE tags.guild_id = $1
|
||||||
AND tags.tag = $2;`
|
AND tags.tag = $2;`
|
||||||
row := utils.Database.QueryRow(queryString, ctx.Guild.ID, args[0])
|
row := utils.Database.QueryRow(queryString, ctx.Guild.ID, input[0])
|
||||||
var dest string
|
var dest string
|
||||||
if err := row.Scan(&dest); err != nil {
|
if err := row.Scan(&dest); err != nil {
|
||||||
tag := args[0]
|
tag := input[0]
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
ctx.ErrorChannel <- disgoman.CommandError{
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
@ -41,7 +27,7 @@ func addTagCommand(ctx disgoman.Context, input []string) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(args) <= 1 {
|
if len(input) <= 1 {
|
||||||
ctx.ErrorChannel <- disgoman.CommandError{
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Message: "I got a name but no value",
|
Message: "I got a name but no value",
|
||||||
@ -49,7 +35,7 @@ func addTagCommand(ctx disgoman.Context, input []string) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
value := args[1]
|
value := strings.Join(input[1:], " ")
|
||||||
if value == "" {
|
if value == "" {
|
||||||
ctx.ErrorChannel <- disgoman.CommandError{
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
@ -61,7 +47,6 @@ func addTagCommand(ctx disgoman.Context, input []string) {
|
|||||||
queryString = `INSERT INTO tags (tag, content, creator, guild_id) VALUES ($1, $2, $3, $4);`
|
queryString = `INSERT INTO tags (tag, content, creator, guild_id) VALUES ($1, $2, $3, $4);`
|
||||||
_, err := utils.Database.Exec(queryString, tag, value, ctx.Message.Author.ID, ctx.Guild.ID)
|
_, err := utils.Database.Exec(queryString, tag, value, ctx.Message.Author.ID, ctx.Guild.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Send(err.Error())
|
|
||||||
ctx.ErrorChannel <- disgoman.CommandError{
|
ctx.ErrorChannel <- disgoman.CommandError{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Message: "",
|
Message: "",
|
||||||
@ -1,15 +1,16 @@
|
|||||||
package exts
|
package exts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/dustinpianalto/disgoman"
|
"github.com/dustinpianalto/disgoman"
|
||||||
|
"github.com/dustinpianalto/goff/utils"
|
||||||
"github.com/olebedev/when"
|
"github.com/olebedev/when"
|
||||||
"github.com/olebedev/when/rules/common"
|
"github.com/olebedev/when/rules/common"
|
||||||
"github.com/olebedev/when/rules/en"
|
"github.com/olebedev/when/rules/en"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func addReminderCommand(ctx disgoman.Context, args []string) {
|
func addReminderCommand(ctx disgoman.Context, args []string) {
|
||||||
@ -1,13 +1,14 @@
|
|||||||
package exts
|
package exts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
"github.com/dustinpianalto/disgoman"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/dustinpianalto/disgoman"
|
||||||
|
"github.com/dustinpianalto/goff/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func kickUserCommand(ctx disgoman.Context, args []string) {
|
func kickUserCommand(ctx disgoman.Context, args []string) {
|
||||||
@ -1,14 +1,15 @@
|
|||||||
package exts
|
package exts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
"github.com/dustinpianalto/disgoman"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/dustinpianalto/disgoman"
|
||||||
|
"github.com/dustinpianalto/goff/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func pingCommand(ctx disgoman.Context, _ []string) {
|
func pingCommand(ctx disgoman.Context, _ []string) {
|
||||||
7
go.mod
7
go.mod
@ -1,10 +1,11 @@
|
|||||||
module djpianalto.com/goff
|
module github.com/dustinpianalto/goff
|
||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bwmarrin/discordgo v0.20.3-0.20200525154655-ca64123b05de
|
github.com/bwmarrin/discordgo v0.22.0
|
||||||
github.com/dustinpianalto/disgoman v0.0.10
|
github.com/dustinpianalto/disgoman v0.0.12
|
||||||
|
github.com/dustinpianalto/rpnparse v1.0.1
|
||||||
github.com/emersion/go-imap v1.0.5
|
github.com/emersion/go-imap v1.0.5
|
||||||
github.com/emersion/go-message v0.12.0
|
github.com/emersion/go-message v0.12.0
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||||
|
|||||||
6
go.sum
6
go.sum
@ -4,11 +4,17 @@ github.com/bwmarrin/discordgo v0.20.2 h1:nA7jiTtqUA9lT93WL2jPjUp8ZTEInRujBdx1C9g
|
|||||||
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
||||||
github.com/bwmarrin/discordgo v0.20.3-0.20200525154655-ca64123b05de h1:0TOVVwGrmv0PA+/vuekQIRY9jJ9rcHYnicIaph3/4S4=
|
github.com/bwmarrin/discordgo v0.20.3-0.20200525154655-ca64123b05de h1:0TOVVwGrmv0PA+/vuekQIRY9jJ9rcHYnicIaph3/4S4=
|
||||||
github.com/bwmarrin/discordgo v0.20.3-0.20200525154655-ca64123b05de/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
|
github.com/bwmarrin/discordgo v0.20.3-0.20200525154655-ca64123b05de/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
|
||||||
|
github.com/bwmarrin/discordgo v0.22.0 h1:uBxY1HmlVCsW1IuaPjpCGT6A2DBwRn0nvOguQIxDdFM=
|
||||||
|
github.com/bwmarrin/discordgo v0.22.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dustinpianalto/disgoman v0.0.10 h1:UzmvMpOi4peF59tXGaNfVU+ePHs1hILa6gQbjxjWQ9g=
|
github.com/dustinpianalto/disgoman v0.0.10 h1:UzmvMpOi4peF59tXGaNfVU+ePHs1hILa6gQbjxjWQ9g=
|
||||||
github.com/dustinpianalto/disgoman v0.0.10/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g=
|
github.com/dustinpianalto/disgoman v0.0.10/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g=
|
||||||
|
github.com/dustinpianalto/disgoman v0.0.12 h1:dLptU2ZTUZJaLBOKeE6qjuL8gqdAr6ehHSOtfHmUpL8=
|
||||||
|
github.com/dustinpianalto/disgoman v0.0.12/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g=
|
||||||
|
github.com/dustinpianalto/rpnparse v1.0.1 h1:ZvH1/RIe5hh3RGSAXOgtngEDHNPTF+DMh88XFWpQjzY=
|
||||||
|
github.com/dustinpianalto/rpnparse v1.0.1/go.mod h1:SzFbQb+Eed5gYCtDu/SYEXXwdPtWkDg9oaL1xQtN1BY=
|
||||||
github.com/emersion/go-imap v1.0.5 h1:8xg/d2wo2BBP3AEP5AOaM/6i8887RGyVW2st/IVHWUw=
|
github.com/emersion/go-imap v1.0.5 h1:8xg/d2wo2BBP3AEP5AOaM/6i8887RGyVW2st/IVHWUw=
|
||||||
github.com/emersion/go-imap v1.0.5/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU=
|
github.com/emersion/go-imap v1.0.5/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU=
|
||||||
github.com/emersion/go-message v0.11.1/go.mod h1:C4jnca5HOTo4bGN9YdqNQM9sITuT3Y0K6bSUw9RklvY=
|
github.com/emersion/go-message v0.11.1/go.mod h1:C4jnca5HOTo4bGN9YdqNQM9sITuT3Y0K6bSUw9RklvY=
|
||||||
|
|||||||
@ -4,10 +4,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"djpianalto.com/goff/djpianalto.com/goff/events"
|
|
||||||
"djpianalto.com/goff/djpianalto.com/goff/exts"
|
|
||||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
|
||||||
"github.com/dustinpianalto/disgoman"
|
"github.com/dustinpianalto/disgoman"
|
||||||
|
"github.com/dustinpianalto/goff/events"
|
||||||
|
"github.com/dustinpianalto/goff/exts"
|
||||||
|
"github.com/dustinpianalto/goff/utils"
|
||||||
|
|
||||||
//"github.com/MikeModder/anpan"
|
//"github.com/MikeModder/anpan"
|
||||||
"os"
|
"os"
|
||||||
@ -34,6 +34,11 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
dg.State.MaxMessageCount = 100
|
dg.State.MaxMessageCount = 100
|
||||||
|
dg.StateEnabled = true
|
||||||
|
|
||||||
|
dg.Identify = discordgo.Identify{
|
||||||
|
Intents: discordgo.MakeIntent(discordgo.IntentsAll),
|
||||||
|
}
|
||||||
|
|
||||||
utils.ConnectDatabase(os.Getenv("DATABASE_URL"))
|
utils.ConnectDatabase(os.Getenv("DATABASE_URL"))
|
||||||
utils.InitializeDatabase()
|
utils.InitializeDatabase()
|
||||||
@ -16,6 +16,18 @@ var postfixes = []postfix{
|
|||||||
Name: "1_Update_X_Guild_Prefixes_to_add_ID",
|
Name: "1_Update_X_Guild_Prefixes_to_add_ID",
|
||||||
Invoke: updateXGuildPrefixesToAddID,
|
Invoke: updateXGuildPrefixesToAddID,
|
||||||
},
|
},
|
||||||
|
postfix{
|
||||||
|
Name: "1_Update_Tags_Content_Length",
|
||||||
|
Invoke: updateTagsContentLength,
|
||||||
|
},
|
||||||
|
postfix{
|
||||||
|
Name: "2_Add_Table_Roles",
|
||||||
|
Invoke: addTableRoles,
|
||||||
|
},
|
||||||
|
postfix{
|
||||||
|
Name: "3_Update_Guild_Add_Puzzle_Role",
|
||||||
|
Invoke: updateGuildsAddPuzzleRole,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunPostfixes() {
|
func RunPostfixes() {
|
||||||
@ -75,3 +87,58 @@ func updateXGuildPrefixesToAddID(revert bool) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateTagsContentLength(revert bool) error {
|
||||||
|
var queryString string
|
||||||
|
if !revert {
|
||||||
|
queryString = `ALTER TABLE tags
|
||||||
|
ALTER COLUMN content TYPE varchar(2000)`
|
||||||
|
} else {
|
||||||
|
queryString = `ALTER TABLE tags
|
||||||
|
ALTER COLUMN content TYPE varchar(1000)`
|
||||||
|
}
|
||||||
|
_, err := Database.Exec(queryString)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addTableRoles(revert bool) error {
|
||||||
|
var queryString string
|
||||||
|
if !revert {
|
||||||
|
queryString = `CREATE TABLE roles(
|
||||||
|
id varchar(30) primary key,
|
||||||
|
guild_id varchar(30) not null references guilds(id),
|
||||||
|
self_assignable bool not null default false,
|
||||||
|
admin bool not null default false,
|
||||||
|
moderator bool not null default false
|
||||||
|
)`
|
||||||
|
} else {
|
||||||
|
queryString = `DROP TABLE roles`
|
||||||
|
}
|
||||||
|
_, err := Database.Exec(queryString)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateGuildsAddPuzzleRole(revert bool) error {
|
||||||
|
var queryString string
|
||||||
|
if !revert {
|
||||||
|
queryString = `ALTER TABLE guilds
|
||||||
|
ADD COLUMN puzzle_role varchar(30) references roles(id)`
|
||||||
|
} else {
|
||||||
|
queryString = `ALTER TABLE guilds
|
||||||
|
DROP COLUMN puzzle_role`
|
||||||
|
}
|
||||||
|
_, err := Database.Exec(queryString)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -49,14 +49,14 @@ func ProcessPuzzleEmail(mr *mail.Reader, dg *discordgo.Session) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
var guilds []Guild
|
var guilds []Guild
|
||||||
queryString := `SELECT id, puzzle_channel from guilds`
|
queryString := `SELECT id, puzzle_channel, puzzle_role from guilds`
|
||||||
rows, err := Database.Query(queryString)
|
rows, err := Database.Query(queryString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var guild Guild
|
var guild Guild
|
||||||
err := rows.Scan(&guild.ID, &guild.PuzzleChannel)
|
err := rows.Scan(&guild.ID, &guild.PuzzleChannel, &guild.PuzzleRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
continue
|
continue
|
||||||
@ -74,8 +74,17 @@ func ProcessPuzzleEmail(mr *mail.Reader, dg *discordgo.Session) {
|
|||||||
if g.PuzzleChannel == "" {
|
if g.PuzzleChannel == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
msg := discordgo.MessageSend{
|
var msg discordgo.MessageSend
|
||||||
Embed: &e,
|
role, err := dg.State.Role(g.ID, g.PuzzleRole.String)
|
||||||
|
if err != nil {
|
||||||
|
msg = discordgo.MessageSend{
|
||||||
|
Embed: &e,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg = discordgo.MessageSend{
|
||||||
|
Content: role.Mention(),
|
||||||
|
Embed: &e,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m, err := dg.ChannelMessageSendComplex(g.PuzzleChannel, &msg)
|
m, err := dg.ChannelMessageSendComplex(g.PuzzleChannel, &msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
156
utils/rpn.go
Normal file
156
utils/rpn.go
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Operator struct {
|
||||||
|
Token string
|
||||||
|
Precedence int
|
||||||
|
Association string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Operator) HasHigherPrecedence(t Operator) bool {
|
||||||
|
return o.Precedence < t.Precedence // lower number is higher precedence
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Operator) HasEqualPrecedence(t Operator) bool {
|
||||||
|
return o.Precedence == t.Precedence
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Operator) IsLeftAssociative() bool {
|
||||||
|
return o.Association == "left"
|
||||||
|
}
|
||||||
|
|
||||||
|
var operators = map[string]Operator{
|
||||||
|
"+": Operator{
|
||||||
|
Token: "+",
|
||||||
|
Precedence: 4,
|
||||||
|
Association: "left",
|
||||||
|
},
|
||||||
|
"-": Operator{
|
||||||
|
Token: "-",
|
||||||
|
Precedence: 4,
|
||||||
|
Association: "left",
|
||||||
|
},
|
||||||
|
"*": Operator{
|
||||||
|
Token: "*",
|
||||||
|
Precedence: 3,
|
||||||
|
Association: "left",
|
||||||
|
},
|
||||||
|
"/": Operator{
|
||||||
|
Token: "/",
|
||||||
|
Precedence: 3,
|
||||||
|
Association: "left",
|
||||||
|
},
|
||||||
|
"%": Operator{
|
||||||
|
Token: "%",
|
||||||
|
Precedence: 3,
|
||||||
|
Association: "left",
|
||||||
|
},
|
||||||
|
"(": Operator{
|
||||||
|
Token: "(",
|
||||||
|
Precedence: 1,
|
||||||
|
Association: "left",
|
||||||
|
},
|
||||||
|
")": Operator{
|
||||||
|
Token: ")",
|
||||||
|
Precedence: 1,
|
||||||
|
Association: "left",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Stack []Operator
|
||||||
|
|
||||||
|
func (s *Stack) IsEmpty() bool {
|
||||||
|
return len(*s) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stack) Push(op Operator) {
|
||||||
|
*s = append(*s, op)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stack) Pop() (Operator, bool) {
|
||||||
|
if s.IsEmpty() {
|
||||||
|
return Operator{}, false
|
||||||
|
}
|
||||||
|
index := len(*s) - 1
|
||||||
|
element := (*s)[index]
|
||||||
|
*s = (*s)[:index]
|
||||||
|
return element, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stack) Top() Operator {
|
||||||
|
if s.IsEmpty() {
|
||||||
|
return Operator{}
|
||||||
|
}
|
||||||
|
return (*s)[len(*s)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateRPN(tokens []string) (string, error) {
|
||||||
|
output := ""
|
||||||
|
s := Stack{}
|
||||||
|
for _, token := range tokens {
|
||||||
|
err := processToken(token, &s, &output)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for !s.IsEmpty() {
|
||||||
|
ele, _ := s.Pop()
|
||||||
|
output += " " + ele.Token
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processToken(t string, s *Stack, o *string) error {
|
||||||
|
if _, err := strconv.Atoi(t); err == nil {
|
||||||
|
*o += " " + t
|
||||||
|
return nil
|
||||||
|
} else if op, ok := operators[t]; ok {
|
||||||
|
if op.Token == "(" {
|
||||||
|
s.Push(op)
|
||||||
|
} else if op.Token == ")" {
|
||||||
|
if s.IsEmpty() {
|
||||||
|
return fmt.Errorf("mismatched parentheses")
|
||||||
|
}
|
||||||
|
for s.Top().Token != "(" {
|
||||||
|
if ele, ok := s.Pop(); ok {
|
||||||
|
*o += " " + ele.Token
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("mismatched parentheses")
|
||||||
|
}
|
||||||
|
if s.IsEmpty() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.Pop() // Pop and discard the (
|
||||||
|
} else if !s.IsEmpty() {
|
||||||
|
for {
|
||||||
|
if (s.Top().HasHigherPrecedence(op) ||
|
||||||
|
(s.Top().HasEqualPrecedence(op) &&
|
||||||
|
op.IsLeftAssociative())) &&
|
||||||
|
s.Top().Token != "(" {
|
||||||
|
if ele, ok := s.Pop(); ok {
|
||||||
|
*o += " " + ele.Token
|
||||||
|
if s.IsEmpty() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s.Push(op)
|
||||||
|
} else {
|
||||||
|
s.Push(op)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("invalid character %s", t)
|
||||||
|
}
|
||||||
95
utils/rpnParser.go
Normal file
95
utils/rpnParser.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FStack []float64
|
||||||
|
|
||||||
|
func (s *FStack) IsEmpty() bool {
|
||||||
|
return len(*s) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FStack) Push(op float64) {
|
||||||
|
*s = append(*s, op)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FStack) Pop() (float64, bool) {
|
||||||
|
if s.IsEmpty() {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
index := len(*s) - 1
|
||||||
|
element := (*s)[index]
|
||||||
|
*s = (*s)[:index]
|
||||||
|
return element, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FStack) PopTwo() (float64, float64, bool) {
|
||||||
|
if s.IsEmpty() || len(*s) < 2 {
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
index := len(*s) - 1
|
||||||
|
b := (*s)[index]
|
||||||
|
a := (*s)[index-1]
|
||||||
|
*s = (*s)[:index-1]
|
||||||
|
return a, b, true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FStack) Top() float64 {
|
||||||
|
if s.IsEmpty() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return (*s)[len(*s)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseRPN(args []string) (float64, error) {
|
||||||
|
s := FStack{}
|
||||||
|
for _, token := range args {
|
||||||
|
switch token {
|
||||||
|
case "+":
|
||||||
|
if a, b, ok := s.PopTwo(); ok {
|
||||||
|
s.Push(a + b)
|
||||||
|
} else {
|
||||||
|
return 0, fmt.Errorf("not enough operands on stack for +: %v", s)
|
||||||
|
}
|
||||||
|
case "-":
|
||||||
|
if a, b, ok := s.PopTwo(); ok {
|
||||||
|
s.Push(a - b)
|
||||||
|
} else {
|
||||||
|
return 0, fmt.Errorf("not enough operands on stack for -: %v", s)
|
||||||
|
}
|
||||||
|
case "*":
|
||||||
|
if a, b, ok := s.PopTwo(); ok {
|
||||||
|
s.Push(a * b)
|
||||||
|
} else {
|
||||||
|
return 0, fmt.Errorf("not enough operands on stack for *: %v", s)
|
||||||
|
}
|
||||||
|
case "/":
|
||||||
|
if a, b, ok := s.PopTwo(); ok {
|
||||||
|
s.Push(a / b)
|
||||||
|
} else {
|
||||||
|
return 0, fmt.Errorf("not enough operands on stack for /: %v", s)
|
||||||
|
}
|
||||||
|
case "%":
|
||||||
|
if a, b, ok := s.PopTwo(); ok {
|
||||||
|
s.Push(math.Mod(a, b))
|
||||||
|
} else {
|
||||||
|
return 0, fmt.Errorf("not enough operands on stack for %: %v", s)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
f, err := strconv.ParseFloat(token, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
s.Push(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if res, ok := s.Pop(); ok {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
return 0, errors.New("no result")
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
import "database/sql"
|
||||||
|
|
||||||
type Guild struct {
|
type Guild struct {
|
||||||
ID string
|
ID string
|
||||||
WelcomeMessage string
|
WelcomeMessage string
|
||||||
@ -7,4 +9,5 @@ type Guild struct {
|
|||||||
LoggingChannel string
|
LoggingChannel string
|
||||||
WelcomeChannel string
|
WelcomeChannel string
|
||||||
PuzzleChannel string
|
PuzzleChannel string
|
||||||
|
PuzzleRole sql.NullString
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user