<commit_before>package biasgame

import (
	"bytes"
	"fmt"
	"image"
	"image/png"
	"regexp"
	"sort"
	"strings"
	"time"

	"github.com/Seklfreak/Robyul2/cache"
	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/Seklfreak/Robyul2/models"
	"github.com/bwmarrin/discordgo"
	"github.com/globalsign/mgo/bson"
	"github.com/mgutz/str"
	"github.com/nfnt/resize"
	"github.com/sethgrid/pester"
)

const (
	CHECKMARK_EMOJI    = "✅"
	X_EMOJI            = "❌"
	QUESTIONMARK_EMOJI = "❓"

	MAX_IMAGE_SIZE = 2000 // 2000x2000px
	MIN_IMAGE_SIZE = 150  // 150x150px
)

var imageSuggestionChannlId string
var imageSuggestionChannel *discordgo.Channel
var suggestionQueue []*models.BiasGameSuggestionEntry
var suggestionEmbedMessageId string // id of the embed message where suggestions are accepted/denied
var exampleRoundPicId string
var suggestionQueueCountMessageId string

func initSuggestionChannel() {
	var err error

	imageSuggestionChannlId = helpers.GetConfig().Path("biasgame.suggestion_channel_id").Data().(string)
	imageSuggestionChannel, err = helpers.GetChannel(imageSuggestionChannlId)
	helpers.Relax(err)

	// when the bot starts, delete any past bot messages from the suggestion channel and make the embed
	var messagesToDelete []string
	messagesInChannel, _ := cache.GetSession().ChannelMessages(imageSuggestionChannlId, 100, "", "", "")
	for _, msg := range messagesInChannel {
		messagesToDelete = append(messagesToDelete, msg.ID)
	}

	cache.GetSession().ChannelMessagesBulkDelete(imageSuggestionChannlId, messagesToDelete)

	// make a message on how to edit suggestions
	helpMessage := "```Editable Fields: name, group, gender, notes\nCommand: " + helpers.GetPrefixForServer(imageSuggestionChannel.GuildID) + "biasgame-edit {field} new field value...\n\nPlease add a note when denying suggestions.```"
	helpers.SendMessage(imageSuggestionChannlId, helpMessage)

	// load unresolved suggestions and create the first embed
	loadUnresolvedSuggestions()
	updateSuggestionQueueCount()
	updateCurrentSuggestionEmbed()
}

// processImageSuggestion
func processImageSuggestion(msg *discordgo.Message, msgContent string) {
	defer helpers.Recover()

	channel, err := helpers.GetChannel(msg.ChannelID)
	helpers.Relax(err)

	// ToArgv can panic, need to catch that
	suggestionArgs := str.ToArgv(msgContent)[1:]
	var suggestedImageUrl string

	// validate suggestion arg amount.
	if len(msg.Attachments) == 1 {
		if len(suggestionArgs) != 3 {
			helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.biasgame.suggestion.invalid-suggestion",
				helpers.GetPrefixForServer(channel.GuildID), helpers.GetPrefixForServer(channel.GuildID)))
			return
		}
		suggestedImageUrl = msg.Attachments[0].URL
	} else {
		if len(suggestionArgs) != 4 {
			helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.biasgame.suggestion.invalid-suggestion",
				helpers.GetPrefixForServer(channel.GuildID), helpers.GetPrefixForServer(channel.GuildID)))
			return
		}
		suggestedImageUrl = suggestionArgs[3]
	}

	// set gender to lowercase and check if its valid
	suggestionArgs[0] = strings.ToLower(suggestionArgs[0])
	if suggestionArgs[0] != "girl" && suggestionArgs[0] != "boy" {
		helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.biasgame.suggestion.invalid-suggestion",
			helpers.GetPrefixForServer(channel.GuildID), helpers.GetPrefixForServer(channel.GuildID)))
		return
	}

	// validate url image
	resp, err := pester.Get(suggestedImageUrl)
	if err != nil {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.invalid-url"))
		return
	}
	defer resp.Body.Close()

	// make sure image is png or jpeg
	if resp.Header.Get("Content-type") != "image/png" && resp.Header.Get("Content-type") != "image/jpeg" {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.not-png-or-jpeg"))
		return
	}

	// attempt to decode the image, if we can't there may be something wrong with the image submitted
	suggestedImage, _, errr := image.Decode(resp.Body)
	if errr != nil {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.invalid-url"))
		return
	}

	// Check height and width are equal
	if suggestedImage.Bounds().Dy() != suggestedImage.Bounds().Dx() {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.image-not-square"))
		return
	}

	// Validate size of image
	if suggestedImage.Bounds().Dy() > MAX_IMAGE_SIZE || suggestedImage.Bounds().Dy() < MIN_IMAGE_SIZE {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.invalid-image-size"))
		return
	}

	// validate group and idol name have no double quotes or underscores
	if strings.ContainsAny(suggestionArgs[1]+suggestionArgs[2], "\"_") {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.invalid-group-or-idol"))
		return
	}

	sugImgHashString, err := helpers.GetImageHashString(suggestedImage)
	helpers.Relax(err)

	// compare the given image to all images currently available in the game
	for _, bias := range getAllBiases() {
		for _, curBImage := range bias.BiasImages {
			compareVal, err := helpers.ImageHashStringComparison(sugImgHashString, curBImage.HashString)
			if err != nil {
				bgLog().Errorf("Comparison error: %s", err.Error())
				continue
			}

			// if the difference is 3 or less let the user know the image already exists
			if compareVal <= 3 {
				helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.suggested-image-exists"))
				return
			}<commit_msg>[biasgame] adjusts exact match threshold 👀<commit_after>package biasgame

import (
	"bytes"
	"fmt"
	"image"
	"image/png"
	"regexp"
	"sort"
	"strings"
	"time"

	"github.com/Seklfreak/Robyul2/cache"
	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/Seklfreak/Robyul2/models"
	"github.com/bwmarrin/discordgo"
	"github.com/globalsign/mgo/bson"
	"github.com/mgutz/str"
	"github.com/nfnt/resize"
	"github.com/sethgrid/pester"
)

const (
	CHECKMARK_EMOJI    = "✅"
	X_EMOJI            = "❌"
	QUESTIONMARK_EMOJI = "❓"

	MAX_IMAGE_SIZE = 2000 // 2000x2000px
	MIN_IMAGE_SIZE = 150  // 150x150px
)

var imageSuggestionChannlId string
var imageSuggestionChannel *discordgo.Channel
var suggestionQueue []*models.BiasGameSuggestionEntry
var suggestionEmbedMessageId string // id of the embed message where suggestions are accepted/denied
var exampleRoundPicId string
var suggestionQueueCountMessageId string

func initSuggestionChannel() {
	var err error

	imageSuggestionChannlId = helpers.GetConfig().Path("biasgame.suggestion_channel_id").Data().(string)
	imageSuggestionChannel, err = helpers.GetChannel(imageSuggestionChannlId)
	helpers.Relax(err)

	// when the bot starts, delete any past bot messages from the suggestion channel and make the embed
	var messagesToDelete []string
	messagesInChannel, _ := cache.GetSession().ChannelMessages(imageSuggestionChannlId, 100, "", "", "")
	for _, msg := range messagesInChannel {
		messagesToDelete = append(messagesToDelete, msg.ID)
	}

	cache.GetSession().ChannelMessagesBulkDelete(imageSuggestionChannlId, messagesToDelete)

	// make a message on how to edit suggestions
	helpMessage := "```Editable Fields: name, group, gender, notes\nCommand: " + helpers.GetPrefixForServer(imageSuggestionChannel.GuildID) + "biasgame-edit {field} new field value...\n\nPlease add a note when denying suggestions.```"
	helpers.SendMessage(imageSuggestionChannlId, helpMessage)

	// load unresolved suggestions and create the first embed
	loadUnresolvedSuggestions()
	updateSuggestionQueueCount()
	updateCurrentSuggestionEmbed()
}

// processImageSuggestion
func processImageSuggestion(msg *discordgo.Message, msgContent string) {
	defer helpers.Recover()

	channel, err := helpers.GetChannel(msg.ChannelID)
	helpers.Relax(err)

	// ToArgv can panic, need to catch that
	suggestionArgs := str.ToArgv(msgContent)[1:]
	var suggestedImageUrl string

	// validate suggestion arg amount.
	if len(msg.Attachments) == 1 {
		if len(suggestionArgs) != 3 {
			helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.biasgame.suggestion.invalid-suggestion",
				helpers.GetPrefixForServer(channel.GuildID), helpers.GetPrefixForServer(channel.GuildID)))
			return
		}
		suggestedImageUrl = msg.Attachments[0].URL
	} else {
		if len(suggestionArgs) != 4 {
			helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.biasgame.suggestion.invalid-suggestion",
				helpers.GetPrefixForServer(channel.GuildID), helpers.GetPrefixForServer(channel.GuildID)))
			return
		}
		suggestedImageUrl = suggestionArgs[3]
	}

	// set gender to lowercase and check if its valid
	suggestionArgs[0] = strings.ToLower(suggestionArgs[0])
	if suggestionArgs[0] != "girl" && suggestionArgs[0] != "boy" {
		helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.biasgame.suggestion.invalid-suggestion",
			helpers.GetPrefixForServer(channel.GuildID), helpers.GetPrefixForServer(channel.GuildID)))
		return
	}

	// validate url image
	resp, err := pester.Get(suggestedImageUrl)
	if err != nil {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.invalid-url"))
		return
	}
	defer resp.Body.Close()

	// make sure image is png or jpeg
	if resp.Header.Get("Content-type") != "image/png" && resp.Header.Get("Content-type") != "image/jpeg" {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.not-png-or-jpeg"))
		return
	}

	// attempt to decode the image, if we can't there may be something wrong with the image submitted
	suggestedImage, _, errr := image.Decode(resp.Body)
	if errr != nil {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.invalid-url"))
		return
	}

	// Check height and width are equal
	if suggestedImage.Bounds().Dy() != suggestedImage.Bounds().Dx() {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.image-not-square"))
		return
	}

	// Validate size of image
	if suggestedImage.Bounds().Dy() > MAX_IMAGE_SIZE || suggestedImage.Bounds().Dy() < MIN_IMAGE_SIZE {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.invalid-image-size"))
		return
	}

	// validate group and idol name have no double quotes or underscores
	if strings.ContainsAny(suggestionArgs[1]+suggestionArgs[2], "\"_") {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.invalid-group-or-idol"))
		return
	}

	sugImgHashString, err := helpers.GetImageHashString(suggestedImage)
	helpers.Relax(err)

	// compare the given image to all images currently available in the game
	for _, bias := range getAllBiases() {
		for _, curBImage := range bias.BiasImages {
			compareVal, err := helpers.ImageHashStringComparison(sugImgHashString, curBImage.HashString)
			if err != nil {
				bgLog().Errorf("Comparison error: %s", err.Error())
				continue
			}

			// if the difference is 1 or less let the user know the image already exists
			if compareVal <= 1 {
				helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.biasgame.suggestion.suggested-image-exists"))
				return
			}
{'fraction_non_alphanumeric': 0.11722768703185633, 'fraction_numerical': 0.007400054146737659, 'mean_word_length': 5.062363238512035, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7235208', 'n_tokens_mistral': 3897, 'n_tokens_neox': 3595, 'n_words': 739}