<commit_before>package notifications

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/Seklfreak/Robyul2/models"
	"github.com/bwmarrin/discordgo"
	"github.com/globalsign/mgo/bson"
)

// _noti list
func handleList(session *discordgo.Session, msg *discordgo.Message) {
	guild, err := helpers.GetGuild(msg.GuildID)
	helpers.Relax(err)

	var entryBucket []models.NotificationsEntry
	err = helpers.MDbIter(helpers.MdbCollection(models.NotificationsTable).Find(bson.M{
		"userid":  msg.Author.ID,
		"guildid": bson.M{"$in": []string{msg.GuildID, "global"}},
	}).Sort("-triggered")).All(&entryBucket)
	helpers.Relax(err)

	if entryBucket == nil || len(entryBucket) <= 0 {
		helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.notifications.keyword-list-no-keywords-error", msg.Author.ID))
		return
	}

	resultMessage := fmt.Sprintf("Enabled keywords for the server: `%s`:\n", guild.Name)
	for _, entry := range entryBucket {
		resultMessage += fmt.Sprintf("`%s` (triggered `%d` times)", entry.Keyword, entry.Triggered)

		if len(entry.IgnoredGuildIDs) > 0 {
			resultMessage += " [Ignored in these Guild(s): "
			for _, ignoredGuildID := range entry.IgnoredGuildIDs {
				guild, err := helpers.GetGuildWithoutApi(ignoredGuildID)
				if err != nil {
					resultMessage += "N/A"
				} else {
					resultMessage += "`" + guild.Name + "`"
				}
				resultMessage += ", "
			}
			resultMessage = strings.TrimRight(resultMessage, ", ")
			resultMessage += "]"
		}

		if len(entry.IgnoredChannelIDs) > 0 {
			resultMessage += " [Ignored in these Channel(s): "
			for _, ignoredChannelID := range entry.IgnoredChannelIDs {
				resultMessage += "<#" + ignoredChannelID + ">, "
			}
			resultMessage = strings.TrimRight(resultMessage, ", ")
			resultMessage += "]"
		}

		if entry.GuildID == "global" {
			resultMessage += " [Global Keyword] :globe_with_meridians:"
		}

		resultMessage += "\n"
	}
	resultMessage += fmt.Sprintf("Found **%d** Keywords in total.", len(entryBucket))

	dmChannel, err := session.UserChannelCreate(msg.Author.ID)
	helpers.Relax(err)

	_, err = helpers.SendMessage(msg.ChannelID, helpers.GetTextF("bot.check-your-dms", msg.Author.ID))
	helpers.RelaxMessage(err, msg.ChannelID, msg.ID)

	_, err = helpers.SendMessage(dmChannel.ID, resultMessage)
	helpers.RelaxMessage(err, msg.ChannelID, msg.ID)
}

// _noti ignore <keyword(s)> [<#channel or channel id>]
func handleIgnore(session *discordgo.Session, content string, msg *discordgo.Message, args []string) {
	if len(args) < 2 {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("bot.arguments.too-few"))
		return
	}

	session.ChannelTyping(msg.ChannelID)

	var targetChannelID string
	targetChannel, err := helpers.GetChannelFromMention(msg, args[len(args)-1])
	if err == nil {
		targetChannelID = targetChannel.ID
	}

	// trim commands
	keywords := strings.TrimSpace(strings.Replace(content, args[0], "", 1))
	if targetChannelID != "" {
		// trim target channel ID
		keywords = strings.TrimSpace(
			keywords[0:strings.LastIndex(keywords, args[len(args)-1])],
		)
	}

	added, err := ignoreKeywordInGuildOrChannel(msg.Author.ID, keywords, msg.GuildID, targetChannelID)
	if err != nil {
		switch err {
		case KeywordsNotFoundError:
			helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.notifications.keyword-ignore-not-found-error"))
			return
		}
		helpers.Relax(err)
	}

	var message string
	if added {
		if targetChannelID == "" {
			message = helpers.GetText("plugins.notifications.keyword-ignore-guild-added")
		} else {
			message = helpers.GetTextF("plugins.notifications.keyword-ignore-channel-added", targetChannel.Mention())
		}
	} else {
		if targetChannelID == "" {
			message = helpers.GetText("plugins.notifications.keyword-ignore-guild-removed")
		} else {
			message = helpers.GetTextF("plugins.notifications.keyword-ignore-channel-removed", targetChannel.Mention())
		}
	}

	_, err = helpers.SendMessage(msg.ChannelID, message)
	helpers.RelaxMessage(err, msg.ChannelID, msg.ID)
}

func ignoreKeywordInGuildOrChannel(userID, keywords, guildID, channelID string) (bool, error) {
	var added bool
	var entryBucket models.NotificationsEntry

	findArgs := bson.M{"userid": userID,
		"keyword": bson.M{"$regex": bson.RegEx{Pattern: "^" + regexp.QuoteMeta(keywords) + "$", Options: "i"}}}
	if channelID == "" {
		findArgs["guildid"] = "global"
	}

	err := helpers.MdbOne(
		helpers.MdbCollection(models.NotificationsTable).Find(findArgs),
		&entryBucket,
	)
	if err != nil {
		if helpers.IsMdbNotFound(err) {
			return added, KeywordsNotFoundError
		}
		return added, err
	}

	if channelID == "" {
		// ignore Guild
		ignoredGuildIDsWithout := make([]string, 0)
		for _, alreadyIgnoredGuildID := range entryBucket.IgnoredGuildIDs {
			if alreadyIgnoredGuildID != guildID {
				ignoredGuildIDsWithout = append(ignoredGuildIDsWithout, alreadyIgnoredGuildID)
			}
		}

		if len(ignoredGuildIDsWithout) != len(entryBucket.IgnoredGuildIDs) {
			entryBucket.IgnoredGuildIDs = ignoredGuildIDsWithout
			added = false<commit_msg>[notifications] fixes glitch when ignoring channels 🙈<commit_after>package notifications

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/Seklfreak/Robyul2/models"
	"github.com/bwmarrin/discordgo"
	"github.com/globalsign/mgo/bson"
)

// _noti list
func handleList(session *discordgo.Session, msg *discordgo.Message) {
	guild, err := helpers.GetGuild(msg.GuildID)
	helpers.Relax(err)

	var entryBucket []models.NotificationsEntry
	err = helpers.MDbIter(helpers.MdbCollection(models.NotificationsTable).Find(bson.M{
		"userid":  msg.Author.ID,
		"guildid": bson.M{"$in": []string{msg.GuildID, "global"}},
	}).Sort("-triggered")).All(&entryBucket)
	helpers.Relax(err)

	if entryBucket == nil || len(entryBucket) <= 0 {
		helpers.SendMessage(msg.ChannelID, helpers.GetTextF("plugins.notifications.keyword-list-no-keywords-error", msg.Author.ID))
		return
	}

	resultMessage := fmt.Sprintf("Enabled keywords for the server: `%s`:\n", guild.Name)
	for _, entry := range entryBucket {
		resultMessage += fmt.Sprintf("`%s` (triggered `%d` times)", entry.Keyword, entry.Triggered)

		if len(entry.IgnoredGuildIDs) > 0 {
			resultMessage += " [Ignored in these Guild(s): "
			for _, ignoredGuildID := range entry.IgnoredGuildIDs {
				guild, err := helpers.GetGuildWithoutApi(ignoredGuildID)
				if err != nil {
					resultMessage += "N/A"
				} else {
					resultMessage += "`" + guild.Name + "`"
				}
				resultMessage += ", "
			}
			resultMessage = strings.TrimRight(resultMessage, ", ")
			resultMessage += "]"
		}

		if len(entry.IgnoredChannelIDs) > 0 {
			resultMessage += " [Ignored in these Channel(s): "
			for _, ignoredChannelID := range entry.IgnoredChannelIDs {
				resultMessage += "<#" + ignoredChannelID + ">, "
			}
			resultMessage = strings.TrimRight(resultMessage, ", ")
			resultMessage += "]"
		}

		if entry.GuildID == "global" {
			resultMessage += " [Global Keyword] :globe_with_meridians:"
		}

		resultMessage += "\n"
	}
	resultMessage += fmt.Sprintf("Found **%d** Keywords in total.", len(entryBucket))

	dmChannel, err := session.UserChannelCreate(msg.Author.ID)
	helpers.Relax(err)

	_, err = helpers.SendMessage(msg.ChannelID, helpers.GetTextF("bot.check-your-dms", msg.Author.ID))
	helpers.RelaxMessage(err, msg.ChannelID, msg.ID)

	_, err = helpers.SendMessage(dmChannel.ID, resultMessage)
	helpers.RelaxMessage(err, msg.ChannelID, msg.ID)
}

// _noti ignore <keyword(s)> [<#channel or channel id>]
func handleIgnore(session *discordgo.Session, content string, msg *discordgo.Message, args []string) {
	if len(args) < 2 {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("bot.arguments.too-few"))
		return
	}

	session.ChannelTyping(msg.ChannelID)

	var targetChannelID string
	targetChannel, err := helpers.GetChannelFromMention(msg, args[len(args)-1])
	if err == nil {
		targetChannelID = targetChannel.ID
	}

	// trim commands
	keywords := strings.TrimSpace(strings.Replace(content, args[0], "", 1))
	if targetChannelID != "" {
		// trim target channel ID
		keywords = strings.TrimSpace(
			keywords[0:strings.LastIndex(keywords, args[len(args)-1])],
		)
	}

	added, err := ignoreKeywordInGuildOrChannel(msg.Author.ID, keywords, msg.GuildID, targetChannelID)
	if err != nil {
		switch err {
		case KeywordsNotFoundError:
			helpers.SendMessage(msg.ChannelID, helpers.GetText("plugins.notifications.keyword-ignore-not-found-error"))
			return
		}
		helpers.Relax(err)
	}

	var message string
	if added {
		if targetChannelID == "" {
			message = helpers.GetText("plugins.notifications.keyword-ignore-guild-added")
		} else {
			message = helpers.GetTextF("plugins.notifications.keyword-ignore-channel-added", targetChannel.Mention())
		}
	} else {
		if targetChannelID == "" {
			message = helpers.GetText("plugins.notifications.keyword-ignore-guild-removed")
		} else {
			message = helpers.GetTextF("plugins.notifications.keyword-ignore-channel-removed", targetChannel.Mention())
		}
	}

	_, err = helpers.SendMessage(msg.ChannelID, message)
	helpers.RelaxMessage(err, msg.ChannelID, msg.ID)
}

func ignoreKeywordInGuildOrChannel(userID, keywords, guildID, channelID string) (bool, error) {
	var added bool
	var entryBucket models.NotificationsEntry

	findArgs := bson.M{"userid": userID,
		"keyword": bson.M{"$regex": bson.RegEx{Pattern: "^" + regexp.QuoteMeta(keywords) + "$", Options: "i"}}}
	if channelID == "" {
		// ignore guild? look for global keywords
		findArgs["guildid"] = "global"
	} else {
		// ignore channels? look for global keywords, or keywords on this guild
		findArgs["$or"] = []bson.M{{"guildid": "global"}, {"guildid": guildID}}
	}

	err := helpers.MdbOne(
		helpers.MdbCollection(models.NotificationsTable).Find(findArgs),
		&entryBucket,
	)
	if err != nil {
		if helpers.IsMdbNotFound(err) {
			return added, KeywordsNotFoundError
		}
		return added, err
	}

	if channelID == "" {
		// ignore Guild
		ignoredGuildIDsWithout := make([]string, 0)
		for _, alreadyIgnoredGuildID := range entryBucket.IgnoredGuildIDs {
			if alreadyIgnoredGuildID != guildID {
				ignoredGuildIDsWithout = append(ignoredGuildIDsWithout, alreadyIgnoredGuildID)
			}
		}

		if len(ignoredGuildIDsWithout) != len(entryBucket.IgnoredGuildIDs) {
			entryBucket.IgnoredGuildIDs = ignoredGuildIDsWithout
			added = false
{'fraction_non_alphanumeric': 0.14459694567948966, 'fraction_numerical': 0.002319737096462401, 'mean_word_length': 4.589951377633711, 'pattern_counts': {'":': 14, '<': 13, '<?xml version=': 0, '>': 13, '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': '238196', 'n_tokens_mistral': 3848, 'n_tokens_neox': 3537, 'n_words': 630}