From f79007aad1fa90c1410e0dd47fc2a517c191b0cc Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Thu, 24 May 2018 02:45:59 +0200
Subject: [PATCH] Implement opt-in / opt-out functionality

---
 main.go | 161 +++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 112 insertions(+), 49 deletions(-)

diff --git a/main.go b/main.go
index 26b627f..944d492 100644
--- a/main.go
+++ b/main.go
@@ -1,17 +1,17 @@
 package main
 
 import (
+	"database/sql"
+	"encoding/hex"
+	"fmt"
+	_ "github.com/lib/pq"
 	"github.com/lrstanley/girc"
+	"golang.org/x/crypto/scrypt"
+	"log"
 	"os"
-	"fmt"
+	"strconv"
 	"strings"
-	"log"
 	"time"
-	_ "github.com/lib/pq"
-	"encoding/hex"
-	"database/sql"
-	"strconv"
-	"golang.org/x/crypto/scrypt"
 )
 
 type Config struct {
@@ -161,62 +161,125 @@ func main() {
 		}
 	})
 
-	client.Handlers.Add(girc.PRIVMSG, func(c *girc.Client, e girc.Event) {
-		if len(e.Params) == 1 {
-			channelName := e.Params[0]
+	client.Handlers.Add(girc.PRIVMSG, func(client *girc.Client, event girc.Event) {
+		if len(event.Params) == 1 {
+			channelName := event.Params[0]
 			if channelData, ok := channels[channelName]; ok {
-				now := time.Now().UTC()
+				logMessage(channelData, event, client, channelName, db)
+			} else if channelName == client.GetNick() {
+				handlePrivateMessage(channels, event, client, db)
+			}
+		}
+	})
 
-				name := hashName(channelData.Salt, e.Source.Name)
-				content := strings.TrimSpace(e.Trailing)
+	for {
+		if err := client.Connect(); err != nil {
+			log.Printf("error: %s", err)
 
-				channel := c.LookupChannel(channelName)
+			log.Println("reconnecting in 30 seconds...")
+			time.Sleep(30 * time.Second)
+		} else {
+			return
+		}
+	}
+}
 
-				var users []string
-				if channel != nil {
-					for _, user := range channel.UserList {
-						if strings.Contains(content, user) {
-							users = append(users, hashName(channelData.Salt, user))
-						}
+func handlePrivateMessage(channels map[string]IrcChannel, event girc.Event, client *girc.Client, db *sql.DB) {
+	split := strings.Split(event.Trailing, " ")
+	if len(split) >= 1 {
+		command := split[0]
+		parameters := split[1:]
+		if strings.EqualFold(command, "OPT-IN") {
+			if len(parameters) == 1 {
+				channelName := parameters[0]
+				if channelData, ok := channels[channelName]; ok {
+					nick := event.Source.Name
+					hash := hashName(channelData.Salt, nick)
+					_, err := db.Exec("INSERT INTO users (hash, nick) VALUES ($1, $2)", hash, nick)
+					if err != nil {
+						client.Cmd.Reply(event, "An error has occured, please try later again")
+						println(err.Error())
+					} else {
+						client.Cmd.Reply(event, "Opt-In successful")
 					}
+					return
 				}
-
-				for _, user := range users {
-					_, err := db.Exec("INSERT INTO \"references\" (time, source, target) VALUES ($1, $2, $3)", now, name, user)
+				client.Cmd.Reply(event, "Channel not found")
+			}
+			printUsageOptIn(client, event)
+			return
+		} else if strings.EqualFold(command, "OPT-OUT") {
+			if len(parameters) == 1 {
+				channelName := parameters[0]
+				if channelData, ok := channels[channelName]; ok {
+					nick := event.Source.Name
+					hash := hashName(channelData.Salt, nick)
+					_, err := db.Exec("DELETE FROM users WHERE hash = $1 AND nick = $2", hash, nick)
 					if err != nil {
+						client.Cmd.Reply(event, "An error has occured, please try later again")
 						println(err.Error())
+					} else {
+						client.Cmd.Reply(event, "Opt-Out successful")
 					}
+					return
 				}
-
-				message := IrcMessage{
-					Time:        now,
-					Channel:     channelData.Id,
-					Sender:      name,
-					Words:       len(strings.Split(content, " ")),
-					Characters:  len(content),
-					Question:    strings.HasSuffix(content, "?"),
-					Exclamation: strings.HasSuffix(content, "!"),
-					Caps:        content == strings.ToUpper(content),
-					Aggression:  false,
-					EmojiHappy:  strings.Contains(content, ":)"),
-					EmojiSad:    strings.Contains(content, ":("),
-				}
-				_, err := db.Exec("INSERT INTO messages (time, channel, sender, words, characters, question, exclamation, caps, aggression, emoji_happy, emoji_sad) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", message.Time, message.Channel, message.Sender, message.Words, message.Characters, message.Question, message.Exclamation, message.Caps, message.Aggression, message.EmojiHappy, message.EmojiSad)
-				if err != nil {
-					println(err.Error())
-				}
+				client.Cmd.Reply(event, "Channel not found")
 			}
+			printUsageOptOut(client, event)
+			return
 		}
-	})
+	}
+	printUsage(client, event)
+}
 
-	for {
-		if err := client.Connect(); err != nil {
-			log.Printf("error: %s", err)
+func printUsage(client *girc.Client, event girc.Event) {
+	client.Cmd.Reply(event, "Usage:")
+	client.Cmd.Reply(event, "OPT-IN [channel]")
+	client.Cmd.Reply(event, "OPT-OUT [channel]")
+}
 
-			log.Println("reconnecting in 30 seconds...")
-			time.Sleep(30 * time.Second)
-		} else {
-			return
+func printUsageOptIn(client *girc.Client, event girc.Event) {
+	client.Cmd.Reply(event, "Usage: OPT-IN [channel]")
+}
+
+func printUsageOptOut(client *girc.Client, event girc.Event) {
+	client.Cmd.Reply(event, "Usage: OPT-OUT [channel]")
+}
+
+func logMessage(channelData IrcChannel, event girc.Event, client *girc.Client, channelName string, db *sql.DB) {
+	now := time.Now().UTC()
+	name := hashName(channelData.Salt, event.Source.Name)
+	content := strings.TrimSpace(event.Trailing)
+	channel := client.LookupChannel(channelName)
+	var users []string
+	if channel != nil {
+		for _, user := range channel.UserList {
+			if strings.Contains(content, user) {
+				users = append(users, hashName(channelData.Salt, user))
+			}
+		}
+	}
+	for _, user := range users {
+		_, err := db.Exec("INSERT INTO \"references\" (time, source, target) VALUES ($1, $2, $3)", now, name, user)
+		if err != nil {
+			println(err.Error())
 		}
 	}
+	message := IrcMessage{
+		Time:        now,
+		Channel:     channelData.Id,
+		Sender:      name,
+		Words:       len(strings.Split(content, " ")),
+		Characters:  len(content),
+		Question:    strings.HasSuffix(content, "?"),
+		Exclamation: strings.HasSuffix(content, "!"),
+		Caps:        content == strings.ToUpper(content),
+		Aggression:  false,
+		EmojiHappy:  strings.Contains(content, ":)"),
+		EmojiSad:    strings.Contains(content, ":("),
+	}
+	_, err := db.Exec("INSERT INTO messages (time, channel, sender, words, characters, question, exclamation, caps, aggression, emoji_happy, emoji_sad) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", message.Time, message.Channel, message.Sender, message.Words, message.Characters, message.Question, message.Exclamation, message.Caps, message.Aggression, message.EmojiHappy, message.EmojiSad)
+	if err != nil {
+		println(err.Error())
+	}
 }
-- 
GitLab