commit
85bcb31d56
@ -0,0 +1,132 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
imap "github.com/emersion/go-imap"
|
||||||
|
"github.com/emersion/go-imap/client"
|
||||||
|
"github.com/emersion/go-message/mail"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ()
|
||||||
|
|
||||||
|
var (
|
||||||
|
emailUsername = os.Getenv("GOFF_EMAIL_USERNAME")
|
||||||
|
emailPassword = os.Getenv("GOFF_EMAIL_PASSWORD")
|
||||||
|
puzzleAddress = mail.Address{
|
||||||
|
Name: "Daily Coding Problem",
|
||||||
|
Address: "founders@dailycodingproblem.com",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var EmailClient client.Client
|
||||||
|
|
||||||
|
func RecieveEmail(dg *discordgo.Session) {
|
||||||
|
for {
|
||||||
|
log.Println("Connecting to Email server.")
|
||||||
|
|
||||||
|
EmailClient, err := client.DialTLS("mail.djpianalto.com:993", nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = EmailClient.Login(emailUsername, emailPassword); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("Connected to Email server.")
|
||||||
|
|
||||||
|
mbox, err := EmailClient.Select("INBOX", false)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if mbox.Messages == 0 {
|
||||||
|
log.Println("No Messages in Mailbox")
|
||||||
|
}
|
||||||
|
|
||||||
|
criteria := imap.NewSearchCriteria()
|
||||||
|
criteria.WithoutFlags = []string{"\\Seen"}
|
||||||
|
uids, err := EmailClient.Search(criteria)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
if len(uids) > 0 {
|
||||||
|
seqset := new(imap.SeqSet)
|
||||||
|
seqset.AddNum(uids...)
|
||||||
|
section := &imap.BodySectionName{}
|
||||||
|
items := []imap.FetchItem{section.FetchItem()}
|
||||||
|
messages := make(chan *imap.Message, 10)
|
||||||
|
go func() {
|
||||||
|
if err = EmailClient.Fetch(seqset, items, messages); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
for msg := range messages {
|
||||||
|
if msg == nil {
|
||||||
|
log.Println("No New Messages")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r := msg.GetBody(section)
|
||||||
|
if r == nil {
|
||||||
|
log.Println("Server didn't send a message body")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
wg.Add(1)
|
||||||
|
go processEmail(r, dg, &wg)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
EmailClient.Logout()
|
||||||
|
time.Sleep(300 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func processEmail(r io.Reader, dg *discordgo.Session, wg *sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
mr, err := mail.CreateReader(r)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
header := mr.Header
|
||||||
|
from, err := header.AddressList("From")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
subject, err := header.Subject()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println(from)
|
||||||
|
log.Println(subject)
|
||||||
|
if addressIn(from, puzzleAddress) &&
|
||||||
|
strings.Contains(subject, "Daily Coding Problem:") {
|
||||||
|
log.Println("Processing Puzzle")
|
||||||
|
ProcessPuzzleEmail(mr, dg)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func addressIn(s []*mail.Address, a mail.Address) bool {
|
||||||
|
for _, item := range s {
|
||||||
|
if item.String() == a.String() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import "log"
|
||||||
|
|
||||||
|
type postfix struct {
|
||||||
|
Name string
|
||||||
|
Invoke func(bool) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var postfixes = []postfix{
|
||||||
|
postfix{
|
||||||
|
Name: "1_Update_Guild_for_Puzzle",
|
||||||
|
Invoke: updateGuildForPuzzle,
|
||||||
|
},
|
||||||
|
postfix{
|
||||||
|
Name: "1_Update_X_Guild_Prefixes_to_add_ID",
|
||||||
|
Invoke: updateXGuildPrefixesToAddID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunPostfixes() {
|
||||||
|
for _, postfix := range postfixes {
|
||||||
|
queryString := "SELECT * from postfixes where name = $1"
|
||||||
|
rows, err := Database.Query(queryString, postfix.Name)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rows.Next() {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
err := postfix.Invoke(false)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = Database.Exec("INSERT INTO postfixes (name) VALUES ($1)", postfix.Name)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateGuildForPuzzle(revert bool) error {
|
||||||
|
var queryString string
|
||||||
|
if !revert {
|
||||||
|
queryString = `ALTER TABLE guilds
|
||||||
|
ADD COLUMN puzzle_channel varchar(30) not null default ''`
|
||||||
|
} else {
|
||||||
|
queryString = `ALTER TABLE guilds
|
||||||
|
DROP COLUMN puzzleChat`
|
||||||
|
}
|
||||||
|
_, err := Database.Exec(queryString)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateXGuildPrefixesToAddID(revert bool) error {
|
||||||
|
var queryString string
|
||||||
|
if !revert {
|
||||||
|
queryString = `ALTER TABLE x_guilds_prefixes
|
||||||
|
ADD COLUMN id serial primary key`
|
||||||
|
} else {
|
||||||
|
queryString = `ALTER TABLE x_guilds_prefixes
|
||||||
|
DROP COLUMN id`
|
||||||
|
}
|
||||||
|
_, err := Database.Exec(queryString)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/emersion/go-message/mail"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ProcessPuzzleEmail(mr *mail.Reader, dg *discordgo.Session) {
|
||||||
|
var body []byte
|
||||||
|
for {
|
||||||
|
p, err := mr.NextPart()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch h := p.Header.(type) {
|
||||||
|
case *mail.InlineHeader:
|
||||||
|
// This is the message's text (can be plain-text or HTML)
|
||||||
|
if t, _, _ := h.ContentType(); t == "text/plain" {
|
||||||
|
body, _ = ioutil.ReadAll(p.Body)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(body) > 0 {
|
||||||
|
s := string(body)
|
||||||
|
puzzle := strings.Split(s, "----------")[0]
|
||||||
|
date, err := mr.Header.Date()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e := discordgo.MessageEmbed{
|
||||||
|
Title: "Daily Coding Problem",
|
||||||
|
URL: "https://dailycodingproblem.com/",
|
||||||
|
Description: "```" + puzzle + "```",
|
||||||
|
Timestamp: date.Format(time.RFC3339),
|
||||||
|
Footer: &discordgo.MessageEmbedFooter{
|
||||||
|
Text: "Daily Coding Problem",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var guilds []Guild
|
||||||
|
queryString := `SELECT id, puzzle_channel from guilds`
|
||||||
|
rows, err := Database.Query(queryString)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
var guild Guild
|
||||||
|
err := rows.Scan(&guild.ID, &guild.PuzzleChannel)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
guilds = append(guilds, guild)
|
||||||
|
}
|
||||||
|
var puzzleID int64
|
||||||
|
queryString = "INSERT INTO puzzles (text, time) VALUES ($1, $2) RETURNING id"
|
||||||
|
err = Database.QueryRow(queryString, puzzle, date).Scan(&puzzleID)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, g := range guilds {
|
||||||
|
if g.PuzzleChannel == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msg := discordgo.MessageSend{
|
||||||
|
Embed: &e,
|
||||||
|
}
|
||||||
|
m, err := dg.ChannelMessageSendComplex(g.PuzzleChannel, &msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
queryString = "INSERT INTO x_guilds_puzzles (guild_id, puzzle_id, message_id) VALUES ($1, $2, $3)"
|
||||||
|
_, err = Database.Exec(queryString, g.ID, puzzleID, m.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
type Guild struct {
|
||||||
|
ID string
|
||||||
|
WelcomeMessage string
|
||||||
|
GoodbyeMessage string
|
||||||
|
LoggingChannel string
|
||||||
|
WelcomeChannel string
|
||||||
|
PuzzleChannel string
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
# goff-db:
|
||||||
|
# image: postgres
|
||||||
|
# ports:
|
||||||
|
# - "5432:5432"
|
||||||
|
# volumes:
|
||||||
|
# - "${PWD}/postgres.conf:/etc/postgresql/postgresql.conf"
|
||||||
|
# - "goff-db:/var/lib/postgresql/data:rw"
|
||||||
|
# env_file: ${PWD}/.env
|
||||||
|
|
||||||
|
goff:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: "${PWD}/Dockerfile"
|
||||||
|
env_file: ${PWD}/.env
|
||||||
|
# logging:
|
||||||
|
# driver: awslogs
|
||||||
|
# options:
|
||||||
|
# awslogs-region: us-east-1
|
||||||
|
# awslogs-group: "/docker/goff/production"
|
||||||
|
# depends_on:
|
||||||
|
# - goff-db
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable
|
||||||
|
# links:
|
||||||
|
# - goff-db:goff.db
|
||||||
|
|
||||||
|
#volumes:
|
||||||
|
# goff-db:
|
||||||
|
# external: true
|
||||||
Loading…
Reference in new issue