First commit
This commit is contained in:
		
						commit
						26097ea9d1
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| discordtoken.txt | ||||
							
								
								
									
										13
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| # syntax=docker/dockerfile:1 | ||||
| FROM golang:1.16.4 AS builder | ||||
| WORKDIR /go/src/quenten.nl/pepebot/ | ||||
|    | ||||
| COPY . ./ | ||||
| RUN go mod download | ||||
| RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app ./discord | ||||
| 
 | ||||
| FROM alpine:latest   | ||||
| RUN apk --no-cache add ca-certificates | ||||
| WORKDIR /root/ | ||||
| COPY --from=builder /go/src/quenten.nl/pepebot/app . | ||||
| CMD ["./app"]   | ||||
							
								
								
									
										1
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| Substitute the environment variables in the docker-compose.yml file for your own | ||||
							
								
								
									
										149
									
								
								discord/admin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								discord/admin.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,149 @@ | ||||
| package main | ||||
| 
 | ||||
| import "github.com/bwmarrin/discordgo" | ||||
| 
 | ||||
| func (app *application) addWord(s *discordgo.Session, m *discordgo.MessageCreate, splitCommand []string) { | ||||
| 	/* Check if admin */ | ||||
| 	r, err := app.checkIfAdmin(s, m) | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if !r { | ||||
| 		return | ||||
| 	} | ||||
| 	/* [0] = trigger, [1] is addword, [2] is the word! */ | ||||
| 	err = app.contextLength(splitCommand) | ||||
| 	if err != nil { | ||||
| 		s.ChannelMessageSend(m.ChannelID, "Please provide a word to add") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = app.badwords.InsertNewWord(splitCommand[2], m.GuildID) | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		s.ChannelMessageSend(m.ChannelID, err.Error()) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	app.updateAllBadWords() | ||||
| } | ||||
| 
 | ||||
| func (app *application) removeWord(s *discordgo.Session, m *discordgo.MessageCreate, splitCommand []string) { | ||||
| 	/* Check if admin */ | ||||
| 	r, err := app.checkIfAdmin(s, m) | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if !r { | ||||
| 		return | ||||
| 	} | ||||
| 	/* [0] = trigger, [1] is removeword, [2] is the word! */ | ||||
| 	err = app.contextLength(splitCommand) | ||||
| 	if err != nil { | ||||
| 		s.ChannelMessageSend(m.ChannelID, "Please provide a word to remove") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	err = app.badwords.RemoveWord(splitCommand[2], m.GuildID) | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		s.ChannelMessageSend(m.ChannelID, err.Error()) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	app.updateAllBadWords() | ||||
| } | ||||
| 
 | ||||
| func (app *application) addAdmin(s *discordgo.Session, m *discordgo.MessageCreate, splitCommand []string) { | ||||
| 	/* Check if admin */ | ||||
| 	r, err := app.checkIfAdmin(s, m) | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if !r { | ||||
| 		return | ||||
| 	} | ||||
| 	/* [0] = trigger, [1] is addadmin, [2] is the id! */ | ||||
| 	err = app.contextLength(splitCommand) | ||||
| 	if err != nil { | ||||
| 		s.ChannelMessageSend(m.ChannelID, "Please provide a role id") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	allRoles, err := s.GuildRoles(m.GuildID) | ||||
| 	if err != nil { | ||||
| 		app.unknownError(err, s, true, m.ChannelID) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var found bool = false | ||||
| 	var counter int = 0 | ||||
| 	for i := 0; i < len(allRoles); i++ { | ||||
| 		if allRoles[i].ID == splitCommand[2] { | ||||
| 			found = true | ||||
| 			counter = i | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if !found { | ||||
| 		s.ChannelMessageSend(m.ChannelID, "This role id does not exist") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = app.adminroles.AddAdminRole(allRoles[counter].Name, allRoles[counter].ID, m.GuildID) | ||||
| 	if err != nil { | ||||
| 		app.unknownError(err, s, true, m.ChannelID) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func (app *application) removeAdmin(s *discordgo.Session, m *discordgo.MessageCreate, splitCommand []string) { | ||||
| 	/* Check if admin */ | ||||
| 	r, err := app.checkIfAdmin(s, m) | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if !r { | ||||
| 		return | ||||
| 	} | ||||
| 	/* [0] = trigger, [1] is removeadmin, [2] is the id! */ | ||||
| 	err = app.contextLength(splitCommand) | ||||
| 	if err != nil { | ||||
| 		s.ChannelMessageSend(m.ChannelID, "Please provide a role id") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	allRoles, err := s.GuildRoles(m.GuildID) | ||||
| 	if err != nil { | ||||
| 		app.unknownError(err, s, true, m.ChannelID) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var found bool = false | ||||
| 	var counter int = 0 | ||||
| 	for i := 0; i < len(allRoles); i++ { | ||||
| 		if allRoles[i].ID == splitCommand[2] { | ||||
| 			found = true | ||||
| 			counter = i | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if !found { | ||||
| 		s.ChannelMessageSend(m.ChannelID, "This role id does not exist") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	err = app.adminroles.RemoveAdminRole(allRoles[counter].Name, allRoles[counter].ID, m.GuildID) | ||||
| 	if err != nil { | ||||
| 		app.unknownError(err, s, true, m.ChannelID) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										55
									
								
								discord/discord.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								discord/discord.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/bwmarrin/discordgo" | ||||
| ) | ||||
| 
 | ||||
| func (app *application) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { | ||||
| 	if m.Author.Bot { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	/* Checking if the message starts with the trigger specified in application struct  | ||||
| 	if it does then we start the switch statement to trigger the appropriate function | ||||
| 	if it does not then we check if it contains a triggerword from the database */ | ||||
| 	if strings.HasPrefix(m.Content, app.trigger) { | ||||
| 		splitCommand := strings.Split(strings.TrimSpace(m.Content), " ") | ||||
| 
 | ||||
| 		/* If the whole message on it's own is just "!pepe" aka the triggerword, then send a pepe and stop */ | ||||
| 		if strings.TrimSpace(m.Content) == app.trigger { | ||||
| 			app.sendPepe(s, m) | ||||
| 			return | ||||
| 		} | ||||
| 		/* This switches on the first word in the message | ||||
| 		it could be anything starting with !pepe */ | ||||
| 		if len(splitCommand) > 1 { | ||||
| 			switch splitCommand[1] { | ||||
| 			/* --- Funny commands --- */ | ||||
| 			case "cringe": | ||||
| 				app.sendCringe(s, m) | ||||
| 			case "gif": | ||||
| 				app.sendNigelGif(s, m) | ||||
| 			/* --- Bot commands for words --- */ | ||||
| 			/* --- Bot commands, but only admins --- */ | ||||
| 			case "addword": | ||||
| 				app.addWord(s, m, splitCommand) | ||||
| 			case "removeword": | ||||
| 				app.removeWord(s, m, splitCommand) | ||||
| 			case "addadmin": | ||||
| 				app.addAdmin(s, m, splitCommand) | ||||
| 			case "removeadmin": | ||||
| 				app.removeAdmin(s, m, splitCommand) | ||||
| 			} | ||||
| 			 | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* If the trigger wasn't the prefix of the message, we need to check all the words for a trigger */ | ||||
| 		app.findTrigger(s, m) | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
| 	 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										1
									
								
								discord/general.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								discord/general.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| package main | ||||
							
								
								
									
										64
									
								
								discord/helper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								discord/helper.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"runtime/debug" | ||||
| 
 | ||||
| 	"github.com/bwmarrin/discordgo" | ||||
| 	_ "github.com/go-sql-driver/mysql" | ||||
| ) | ||||
| 
 | ||||
| /* --------		DB Helper functions		-------- */ | ||||
| 
 | ||||
| func openDB(dsn string) (*sql.DB, error){ | ||||
| 	db, err := sql.Open("mysql", dsn) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if orr := db.Ping(); orr != nil { | ||||
| 		return nil, orr | ||||
| 	} | ||||
| 
 | ||||
| 	return db, nil | ||||
| } | ||||
| 
 | ||||
| func (app *application) updateAllBadWords() (error) { | ||||
| 	var err error | ||||
| 	app.allBadWords, err = app.badwords.AllWords() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| /* --------		Error Helper functions		-------- */ | ||||
| 
 | ||||
| func (app *application) unknownError(err error, s *discordgo.Session, notifyDiscord bool, channelID string) { | ||||
| 	trace := fmt.Sprintf("%s\n%s", err.Error(), debug.Stack()) | ||||
|     app.errorLog.Output(2, trace) | ||||
| 
 | ||||
| 	if notifyDiscord { | ||||
| 		msg := fmt.Sprintf("An unknown error occured, error message attached below. Stack trace is in the server logs.\n%s", err.Error()) | ||||
| 		s.ChannelMessageSend(channelID, msg) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* --------		Discord Helper functions		-------- */ | ||||
| 
 | ||||
| func (app *application) readAuthToken() (string, error) { | ||||
| 	file, err := os.Open("./discordtoken.txt") | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	token, err := io.ReadAll(file) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	return string(token), nil | ||||
| } | ||||
							
								
								
									
										79
									
								
								discord/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								discord/main.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"os/signal" | ||||
| 	"syscall" | ||||
| 
 | ||||
| 	"github.com/bwmarrin/discordgo" | ||||
| 	"quenten.nl/pepebot/models/mysql" | ||||
| ) | ||||
| 
 | ||||
| /* Application struct contains the logging objects. | ||||
| It also has many methods for the different functions of the bot. | ||||
| These methods are mostly located in discord.go */ | ||||
| type application struct { | ||||
| 	errorLog *log.Logger | ||||
| 	infoLog  *log.Logger | ||||
| 	badwords *mysql.BadwordModel | ||||
| 	adminroles *mysql.AdminRolesModel | ||||
| 	trigger string | ||||
| 	allBadWords map[string][]string | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	dbUser := os.Getenv("DB_USER") | ||||
| 	dbPass := os.Getenv("DB_PASS") | ||||
| 	discordToken := os.Getenv("DISCORD_TOKEN") | ||||
| 	dsn := fmt.Sprintf("%s:%s@tcp(db:3306)/badwords?parseTime=true", dbUser, dbPass) | ||||
| 	infoLog := log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime) | ||||
| 	errorLog := log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile) | ||||
| 
 | ||||
| 	db, err := openDB(dsn) | ||||
| 	if err != nil { | ||||
| 		errorLog.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	app := &application{ | ||||
| 		infoLog: infoLog, | ||||
| 		errorLog: errorLog, | ||||
| 		badwords: &mysql.BadwordModel{DB: db}, | ||||
| 		adminroles: &mysql.AdminRolesModel{DB: db}, | ||||
| 		trigger: "!pepe", | ||||
| 	} | ||||
| 
 | ||||
| 	app.allBadWords, err = app.badwords.AllWords() | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	/* token, err := app.readAuthToken() | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Fatal(err) | ||||
| 	} */ | ||||
| 
 | ||||
| 	discord, err := discordgo.New("Bot " + discordToken) | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	discord.AddHandler(app.messageCreate) | ||||
| 
 | ||||
| 	discord.Identify.Intents = discordgo.IntentsGuildMessages | ||||
| 
 | ||||
| 	err = discord.Open() | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Fatal(err) | ||||
| 	} | ||||
| 	defer discord.Close() | ||||
| 
 | ||||
| 	fmt.Println("Bot is now running.  Press CTRL-C to exit.") | ||||
| 	sc := make(chan os.Signal, 1) | ||||
| 	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) | ||||
| 	<-sc | ||||
| 
 | ||||
| 	// Cleanly close down the Discord session.
 | ||||
| 	discord.Close() | ||||
| } | ||||
							
								
								
									
										215
									
								
								discord/simple.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								discord/simple.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,215 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"math/rand" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/bwmarrin/discordgo" | ||||
| ) | ||||
| 
 | ||||
| func (app *application) sendPepe(s *discordgo.Session, m *discordgo.MessageCreate) { | ||||
| 	resp, err := http.Get("http://bbwroller.com/random") | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		return | ||||
| 	} | ||||
| 	body, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		return | ||||
| 	} | ||||
| 	rep, err := regexp.Compile("/static.*\\.jpg") | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		return | ||||
| 	} | ||||
| 	pepes := rep.FindAllString(string(body), 200) | ||||
| 	if pepes == nil { | ||||
| 		app.errorLog.Printf("No pepes were found\n") | ||||
| 		return | ||||
| 	} | ||||
| 	randomIndex := rand.Intn(35) | ||||
| 	url := "https://bbwroller.com" | ||||
| 	url += pepes[randomIndex] | ||||
| 
 | ||||
| 	_, err = s.ChannelMessageSend(m.ChannelID, url) | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (app *application) sendCringe(s *discordgo.Session, m *discordgo.MessageCreate) { | ||||
| 	_, err := s.ChannelMessageSend(m.ChannelID, "https://cdn.nicecock.eu/cringe.webm") | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (app *application) sendNigelGif(s *discordgo.Session, m *discordgo.MessageCreate) { | ||||
| 	msg := "<@77516941199159296> kun je die gif verwijderen van die pickup truck die naar de camera rijdt want bij mij zorg ie voor dat discord opnieuw opstart. ik weet niet of iemand anders dit heeft maar als iemand weet hoe dit komt en een andere oplossing weet hoor ik het graag." | ||||
| 	_, err := s.ChannelMessageSend(m.ChannelID, msg) | ||||
| 	if err != nil { | ||||
| 		app.errorLog.Print(err) | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (app *application) findTrigger(s *discordgo.Session, m *discordgo.MessageCreate) { | ||||
| 	/* Finding for every word in the allBadWords map of string slices | ||||
| 	Check if the message contains that word | ||||
| 	if it doesn't continue, | ||||
| 	if it does then get the word from the database, update the new time, format a message and send it */ | ||||
| 	for i := 0; i < len(app.allBadWords[m.GuildID]); i++{ | ||||
| 		if strings.Contains(strings.ToLower(m.Content), strings.ToLower(app.allBadWords[m.GuildID][i])) { | ||||
| 			/* Found the bad word */ | ||||
| 			word, err := app.badwords.GetWord(strings.ToLower(app.allBadWords[m.GuildID][i]), m.GuildID) | ||||
| 			if err != nil { | ||||
| 				app.errorLog.Print(err) | ||||
| 				s.ChannelMessageSend(m.ChannelID, err.Error()) | ||||
| 			} | ||||
| 			format := formatTimeCheck(word.LastSaid) | ||||
| 			_, err = app.badwords.UpdateLastSaid(word.Word, word.ServerID) | ||||
| 			if err != nil { | ||||
| 				app.errorLog.Print(err) | ||||
| 				return | ||||
| 			} | ||||
| 			user := m.Author.Mention() | ||||
| 			eyesEmoji := ":eyes:" | ||||
| 			message := fmt.Sprintf("%s mentioned the forbidden word '%s'. They broke a streak of %s...\nYou better watch out, I am always watching %s", user, word.Word, format, eyesEmoji) | ||||
| 			_ ,err = s.ChannelMessageSend(m.ChannelID, message)  | ||||
| 			if err != nil { | ||||
| 				app.errorLog.Print(err) | ||||
| 				return | ||||
| 			} | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func formatTimeCheck(last time.Time) string{ | ||||
| 	now := time.Now() | ||||
| 	sinceLast := now.Sub(last) | ||||
| 	var realSeconds uint64 = uint64(sinceLast.Seconds()) | ||||
| 	var seconds, minutes, hours, days uint64 | ||||
| 	realBackup := realSeconds | ||||
| 	days = realSeconds / ( 24 * 3600 ) | ||||
| 	realSeconds -= days * ( 24 * 3600 ) | ||||
| 	hours = realSeconds / 3600 | ||||
| 	realSeconds -= hours * 3600 | ||||
| 	minutes = realSeconds / 60 | ||||
| 	realSeconds -= minutes * 60 | ||||
| 	seconds = realSeconds | ||||
| 	if realBackup < 60{ | ||||
| 		if seconds == 1{ | ||||
| 			return fmt.Sprintf("%d second", seconds) | ||||
| 		} | ||||
| 		return fmt.Sprintf("%d seconds", seconds) | ||||
| 	}else if realBackup > 60 && realBackup < 3600 { | ||||
| 		if seconds == 1 && minutes == 1{ | ||||
| 			return fmt.Sprintf("%d minute and %d second", minutes, seconds) | ||||
| 		}else if minutes == 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d minute and %d seconds", minutes, seconds) | ||||
| 		}else if minutes != 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d minutes and %d second", minutes, seconds) | ||||
| 		} | ||||
| 		return fmt.Sprintf("%d minutes and %d seconds", minutes, seconds) | ||||
| 	}else if realBackup > 60 && realBackup < ( 24 * 3600 ){ | ||||
| 		if hours == 1 && minutes == 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d hour, %d minute and %d second", hours, minutes, seconds) | ||||
| 		}else if hours == 1 && minutes == 1 && seconds != 1 { | ||||
| 			return fmt.Sprintf("%d hour, %d minute and %d seconds", hours, minutes, seconds) | ||||
| 		}else if hours == 1 && minutes != 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d hour, %d minutes and %d second", hours, minutes, seconds) | ||||
| 		}else if hours == 1 && minutes != 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d hour, %d minutes and %d seconds", hours, minutes, seconds) | ||||
| 		}else if hours != 1 && minutes == 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d hours, %d minute and %d second", hours, minutes, seconds) | ||||
| 		}else if hours != 1 && minutes == 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d hours, %d minute and %d seconds", hours, minutes, seconds) | ||||
| 		}else if hours != 1 && minutes != 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d hours, %d minutes and %d second", hours, minutes, seconds) | ||||
| 		}else if hours != 1 && minutes != 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d hours, %d minutes and %d seconds", hours, minutes, seconds) | ||||
| 		} | ||||
| 		return fmt.Sprintf("%d hours, %d minutes and %d seconds", hours, minutes, seconds) | ||||
| 	}else if realBackup > ( 24 * 3600 ){ | ||||
| 		if days != 1 && hours != 1 && minutes != 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d days, %d hours, %d minutes and %d seconds", days, hours, minutes, seconds) | ||||
| 		}else if days != 1 && hours != 1 && minutes != 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d days, %d hours, %d minutes and %d second", days, hours, minutes, seconds) | ||||
| 		}else if days != 1 && hours != 1 && minutes == 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d days, %d hours, %d minute and %d seconds", days, hours, minutes, seconds) | ||||
| 		}else if days != 1 && hours != 1 && minutes == 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d days, %d hours, %d minute and %d second", days, hours, minutes, seconds) | ||||
| 		}else if days != 1 && hours == 1 && minutes != 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d days, %d hour, %d minutes and %d seconds", days, hours, minutes, seconds) | ||||
| 		}else if days != 1 && hours == 1 && minutes != 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d days, %d hour, %d minutes and %d second", days, hours, minutes, seconds) | ||||
| 		}else if days != 1 && hours == 1 && minutes == 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d days, %d hour, %d minute and %d seconds", days, hours, minutes, seconds) | ||||
| 		}else if days != 1 && hours == 1 && minutes == 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d days, %d hour, %d minute and %d second", days, hours, minutes, seconds) | ||||
| 		}else if days == 1 && hours != 1 && minutes != 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d day, %d hours, %d minutes and %d seconds", days, hours, minutes, seconds) | ||||
| 		}else if days == 1 && hours != 1 && minutes != 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d day, %d hours, %d minutes and %d second", days, hours, minutes, seconds) | ||||
| 		}else if days == 1 && hours != 1 && minutes == 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d day, %d hours, %d minute and %d seconds", days, hours, minutes, seconds) | ||||
| 		}else if days == 1 && hours != 1 && minutes == 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d day, %d hours, %d minute and %d second", days, hours, minutes, seconds) | ||||
| 		}else if days == 1 && hours == 1 && minutes != 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d day, %d hour, %d minutes and %d seconds", days, hours, minutes, seconds) | ||||
| 		}else if days == 1 && hours == 1 && minutes != 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d day, %d hour, %d minutes and %d second", days, hours, minutes, seconds) | ||||
| 		}else if days == 1 && hours == 1 && minutes == 1 && seconds != 1{ | ||||
| 			return fmt.Sprintf("%d day, %d hour, %d minute and %d seconds", days, hours, minutes, seconds) | ||||
| 		}else if days == 1 && hours == 1 && minutes == 1 && seconds == 1{ | ||||
| 			return fmt.Sprintf("%d day, %d hour, %d minute and %d second", days, hours, minutes, seconds) | ||||
| 		} | ||||
| 		return fmt.Sprintf("%d days, %d hours, %d minutes and %d seconds", days, hours, minutes, seconds) | ||||
| 	} | ||||
| 	return "error" | ||||
| } | ||||
| 
 | ||||
| func (app *application) checkIfAdmin(s *discordgo.Session, m *discordgo.MessageCreate) (bool, error) { | ||||
| 	authorMemberInfo, err := s.GuildMember(m.GuildID, m.Author.ID) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 
 | ||||
| 	roleIDs, err := app.adminroles.GetAdminRoleIDs() | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 
 | ||||
| 	for i := 0; i < len(authorMemberInfo.Roles); i++ { | ||||
| 		for j := 0; j < len(roleIDs); j++ { | ||||
| 			if authorMemberInfo.Roles[i] == roleIDs[j] { | ||||
| 				return true, nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	app.infoLog.Printf("The user %s tried to perform an admin command without an admin role, purge them", m.Author) | ||||
| 	_, err = s.ChannelMessageSend(m.ChannelID, "You aren't authorized to perform this function, this incident has been reported.") | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 
 | ||||
| 	return false, nil | ||||
| } | ||||
| 
 | ||||
| func (app *application) contextLength(splitCommand []string) (error) { | ||||
| 	if !(len(splitCommand) > 2) { | ||||
| 		app.errorLog.Printf("The command's context was not enough.\n") | ||||
| 		return errors.New("not enough context") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										27
									
								
								docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| version: "3.7" | ||||
| 
 | ||||
| services: | ||||
|     app: | ||||
|         container_name: pepebot_server | ||||
|         build: . | ||||
|         restart: always | ||||
|         depends_on: | ||||
|             - db | ||||
|         environment: | ||||
|             - DB_USER= | ||||
|             - DB_PASS= | ||||
|             - DISCORD_TOKEN= | ||||
|     db: | ||||
|         container_name: pepebot_database | ||||
|         image: mysql:8.0 | ||||
|         restart: always | ||||
|         environment: | ||||
|             MYSQL_ROOT_PASSWORD: | ||||
|             MYSQL_DATABASE: | ||||
|             MYSQL_USER: | ||||
|             MYSQL_PASSWORD: | ||||
|         volumes: | ||||
|             - pepe_db_data:/var/lib/mysql | ||||
| 
 | ||||
| volumes: | ||||
|     pepe_db_data: {} | ||||
							
								
								
									
										8
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| module quenten.nl/pepebot | ||||
| 
 | ||||
| go 1.16 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/bwmarrin/discordgo v0.23.2 | ||||
| 	github.com/go-sql-driver/mysql v1.6.0 | ||||
| ) | ||||
							
								
								
									
										8
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| github.com/bwmarrin/discordgo v0.23.2 h1:BzrtTktixGHIu9Tt7dEE6diysEF9HWnXeHuoJEt2fH4= | ||||
| github.com/bwmarrin/discordgo v0.23.2/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M= | ||||
| github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= | ||||
| github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= | ||||
| github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= | ||||
| github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | ||||
| 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= | ||||
							
								
								
									
										23
									
								
								models/models.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								models/models.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| package models | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| var ErrNoRecord = errors.New("models: no matching record found") | ||||
| 
 | ||||
| type Badword struct { | ||||
| 	ID       int | ||||
| 	Word     string | ||||
| 	ServerID string | ||||
| 	LastSaid time.Time | ||||
| } | ||||
| 
 | ||||
| type AdminRoles struct { | ||||
| 	ID int | ||||
| 	RoleName string | ||||
| 	RoleID string | ||||
| 	GuildID string | ||||
| } | ||||
							
								
								
									
										99
									
								
								models/mysql/adminroles.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								models/mysql/adminroles.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | ||||
| package mysql | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"errors" | ||||
| 
 | ||||
| 	"quenten.nl/pepebot/models" | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| type AdminRolesModel struct { | ||||
| 	DB *sql.DB | ||||
| } | ||||
| 
 | ||||
| func (m *AdminRolesModel) GetAdmins() ([]*models.AdminRoles, error) { | ||||
| 	stmt := `SELECT id, rolename, roleid, guildid FROM adminroles` | ||||
| 
 | ||||
| 	rows, err := m.DB.Query(stmt) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer rows.Close() | ||||
| 
 | ||||
| 	tmp := []*models.AdminRoles{} | ||||
| 
 | ||||
| 	for rows.Next() { | ||||
| 		t := &models.AdminRoles{} | ||||
| 		err = rows.Scan(&t.ID, &t.RoleName, &t.RoleID, &t.GuildID) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		tmp = append(tmp, t) | ||||
| 	} | ||||
| 
 | ||||
| 	if err = rows.Err(); err != nil{ | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return tmp, nil | ||||
| } | ||||
| 
 | ||||
| func (m *AdminRolesModel) GetAdminRoleIDs() ([]string, error) { | ||||
| 	admins, err := m.GetAdmins() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	 | ||||
| 	roleIDs := make([]string, 0) | ||||
| 	for i := 0; i < len(admins); i++ { | ||||
| 		roleIDs = append(roleIDs, admins[i].RoleID) | ||||
| 	} | ||||
| 
 | ||||
| 	return roleIDs, nil | ||||
| } | ||||
| 
 | ||||
| func (m *AdminRolesModel) AddAdminRole(roleName string, roleID string, guildID string) (int, error) { | ||||
| 	stmt := `INSERT INTO adminroles (rolename, roleid, guildid) VALUES (?, ?, ?)` | ||||
| 
 | ||||
| 	result, err := m.DB.Exec(stmt, roleName, roleID, guildID) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	 | ||||
| 	id, err := result.LastInsertId() | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	return int(id), nil | ||||
| } | ||||
| 
 | ||||
| func (m *AdminRolesModel) RemoveAdminRole(roleName string, roleID string, guildID string) (error) { | ||||
| 	stmt := `SELECT id FROM adminroles WHERE rolename = ? AND roleid = ? AND guildid = ?` | ||||
| 
 | ||||
| 	row := m.DB.QueryRow(stmt, roleName, roleID, guildID) | ||||
| 
 | ||||
| 	var id int | ||||
| 	err := row.Scan(&id) | ||||
| 	if err != nil { | ||||
| 		if errors.Is(err, sql.ErrNoRows){ | ||||
| 			return models.ErrNoRecord | ||||
| 		}else{ | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	stmt = `DELETE FROM adminroles WHERE id = ?` | ||||
| 	result, err := m.DB.Exec(stmt, id) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if r, _ := result.RowsAffected(); r == 0 || r > 1 { | ||||
| 		return errors.New("either zero or more than one rows were affected") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										147
									
								
								models/mysql/badword.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								models/mysql/badword.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,147 @@ | ||||
| package mysql | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"errors" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"quenten.nl/pepebot/models" | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| type BadwordModel struct { | ||||
| 	DB *sql.DB | ||||
| } | ||||
| 
 | ||||
| func (m *BadwordModel) GetWord(word string, serverID string) (*models.Badword, error) { | ||||
| 	stmt := `SELECT id, word, serverid, lastsaid FROM badwords | ||||
| 	WHERE word = ? AND serverid = ?` | ||||
| 
 | ||||
| 	row := m.DB.QueryRow(stmt, word, serverID) | ||||
| 
 | ||||
| 	bw := &models.Badword{} | ||||
| 
 | ||||
| 	err := row.Scan(&bw.ID, &bw.Word, &bw.ServerID, &bw.LastSaid) | ||||
| 	if err != nil { | ||||
| 		if errors.Is(err, sql.ErrNoRows){ | ||||
| 			return nil, models.ErrNoRecord | ||||
| 		}else{ | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return bw, nil | ||||
| } | ||||
| 
 | ||||
| func (m *BadwordModel) AllWords() (map[string][]string, error) { | ||||
| 	stmt := `SELECT word, serverid FROM badwords` | ||||
| 
 | ||||
| 	rows, err := m.DB.Query(stmt) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer rows.Close() | ||||
| 	 | ||||
| 	type tmp struct{ | ||||
| 		word string | ||||
| 		serverid string | ||||
| 	} | ||||
| 	tmp2 := []*tmp{} | ||||
| 
 | ||||
| 	for rows.Next() { | ||||
| 		t := &tmp{} | ||||
| 		err = rows.Scan(&t.word, &t.serverid) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		tmp2 = append(tmp2, t) | ||||
| 	} | ||||
| 
 | ||||
| 	if err = rows.Err(); err != nil{ | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	finaltmp := make(map[string][]string) | ||||
| 	for i := 0; i < len(tmp2); i++ { | ||||
| 		 | ||||
| 		finaltmp[tmp2[i].serverid] = append(finaltmp[tmp2[i].serverid], tmp2[i].word) | ||||
| 	} | ||||
| 
 | ||||
| 	return finaltmp, nil | ||||
| } | ||||
| 
 | ||||
| func (m *BadwordModel) InsertNewWord(word string, serverid string) (int, error) { | ||||
| 	stmt := `INSERT INTO badwords (word, serverid, lastsaid) | ||||
| 	VALUES (?, ?, UTC_TIMESTAMP())` | ||||
| 
 | ||||
| 	id1, err := strconv.Atoi(serverid) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	result, err := m.DB.Exec(stmt, word, id1) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	id, err := result.LastInsertId() | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	return int(id), nil | ||||
| } | ||||
| 
 | ||||
| func (m *BadwordModel) RemoveWord(word string, serverid string) (error) { | ||||
| 	allwords, err := m.AllWords() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	found := false | ||||
| 	for i := 0; i < len(allwords[serverid]); i++ { | ||||
| 		if allwords[serverid][i] == word { | ||||
| 			found = true | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	if !found { | ||||
| 		return errors.New("that word doesn't exist") | ||||
| 	}  | ||||
| 
 | ||||
| 	stmt := `DELETE FROM badwords WHERE word = ? AND serverid = ?` | ||||
| 
 | ||||
| 	result, err := m.DB.Exec(stmt, word, serverid) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if r, _ := result.RowsAffected(); r == 0 || r > 1 { | ||||
| 		return errors.New("an unknown error occured") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (m *BadwordModel) UpdateLastSaid(word string, serverid string) (int, error) { | ||||
| 	stmt := `SELECT id FROM badwords WHERE | ||||
| 	word = ? AND serverid = ?` | ||||
| 
 | ||||
| 	row := m.DB.QueryRow(stmt, word, serverid) | ||||
| 	 | ||||
| 	id := 0 | ||||
| 	row.Scan(&id) | ||||
| 
 | ||||
| 	stmt = `UPDATE badwords SET lastsaid = UTC_TIMESTAMP() WHERE id = ?` | ||||
| 
 | ||||
| 	result, err := m.DB.Exec(stmt, id) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	id2, err := result.LastInsertId() | ||||
| 	if err != nil { | ||||
| 		return 0, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return int(id2), nil | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user