diff --git a/POLICY.md b/POLICY.md
index 392df10..12c862b 100644
--- a/POLICY.md
+++ b/POLICY.md
@@ -7,14 +7,10 @@ Without storing some aspects of your user data, the bot would not be able to run
We collect the following:
-* User IDs
+* User IDs and Guild IDs
Required for functionality of the blacklist command.
-* Guild/Channel ID pairs
-
- Required for the functionality of the announcements and announcements command.
-
* Messages
Messages are not stored, but they are used for the main functionality of cheeseBot.
diff --git a/src/bot.rb b/src/bot.rb
index 4a2f0b7..988815e 100644
--- a/src/bot.rb
+++ b/src/bot.rb
@@ -16,18 +16,31 @@
require 'discordrb'
require 'securerandom'
+require_relative 'events/message_check'
class CheeseBot
def initialize
+ puts "Initializing bot..."
@bot = Discordrb::Bot.new(
token: ENV['BOT_TOKEN'],
- intents: [:servers, :server_messages]
+ intents: [:servers, :server_messages],
)
-
+
+ puts "Registering the Message Checker..."
+ MessageCheck.register(@bot)
+
+ puts "Initializing database..."
+ Database.setup
+
+ puts "Loading commands..."
load_commands
+
+ puts "Starting bot..."
start_bot
end
+
+
def run
@bot.run
end
diff --git a/src/commands/not_cheese_related/blacklist.rb b/src/commands/not_cheese_related/blacklist.rb
new file mode 100644
index 0000000..06717d6
--- /dev/null
+++ b/src/commands/not_cheese_related/blacklist.rb
@@ -0,0 +1,60 @@
+# cheeseBot
+# Copyright (C) 2026 Eri (csxkdv/nxkdv) nxkdv@thenight.club
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+require_relative '../../modules/database'
+
+module Commands
+ module Blacklist
+ extend self
+
+ def register(bot)
+ cmd_key = :blacklist
+ cmd_desc = "Blacklist yourself from the trigger DMs (using the command again will whitelist you.)"
+
+ bot.register_application_command(cmd_key, cmd_desc, server_id: ENV['SERVER_ID'])
+
+ bot.application_command(cmd_key) do |event|
+ added = Database.toggle_user_blacklist(event.user.id)
+
+ if added
+ event.respond(content: "You have been added to the blacklist. You will no longer receive DMs.")
+ else
+ event.respond(content: "You have been removed from the blacklist. You will now receive DMs.")
+ end
+ end
+
+ cmd_key_server = :server_blacklist
+ cmd_desc_server = "Blacklist the server from the trigger DMs (using the command again will whitelist the server.)"
+
+ bot.register_application_command(cmd_key_server, cmd_desc_server, server_id: ENV['SERVER_ID'])
+
+ bot.application_command(cmd_key_server) do |event|
+ unless event.user.permission?(:administrator)
+ event.respond(content: "You're not an admin. You can't use this command.", ephemeral: true)
+ next
+ end
+
+ added = Database.toggle_server_blacklist(event.server.id)
+
+ if added
+ event.respond(content: "Server has been added to the blacklist. This server will no longer receive DMs.")
+ else
+ event.respond(content: "Server has been removed from the blacklist. This server will now receive DMs.")
+ end
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/src/events/message_check.rb b/src/events/message_check.rb
new file mode 100644
index 0000000..ca5f148
--- /dev/null
+++ b/src/events/message_check.rb
@@ -0,0 +1,50 @@
+# cheeseBot
+# Copyright (C) 2026 Eri (csxkdv/nxkdv) nxkdv@thenight.club
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+require_relative '../modules/cheese_checker'
+require_relative '../modules/database'
+
+module MessageCheck
+ def self.register(bot)
+ bot.message do |event|
+ next if event.user.bot_account || event.server.nil?
+
+ cheese_content = CheeseChecker.check_content(event.content)
+ next unless cheese_content
+
+ event.message.react("🧀")
+
+ next if Database.server_blacklisted?(event.server.id)
+ next if Database.user_blacklisted?(event.user.id)
+
+ begin
+ event.user.pm.send_embed do |embed|
+ embed.title = "Cheese Detected!"
+ embed.description = cheese_content
+
+ embed.color = rand(0xFFFFFF)
+ embed.timestamp = Time.now
+
+ embed.footer = Discordrb::Webhooks::EmbedFooter.new(
+ text: "Use /blacklist to not receive DMs anymore"
+ )
+ end
+ rescue Discordrb::Errors::NoPermission
+ puts "Could not DM user #{event.user.username} (#{event.user.id})"
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/src/lists/cheese_words.rb b/src/lists/cheese_words.rb
new file mode 100644
index 0000000..fbbd474
--- /dev/null
+++ b/src/lists/cheese_words.rb
@@ -0,0 +1,86 @@
+module Lists
+ CHEESE_WORDS = [
+ "abertam",
+ "abondance",
+ "acapella",
+ "accasciato",
+ "ackawi",
+ "acorn",
+ "adelost",
+ "backstein",
+ "bergader",
+ "bonifaz",
+ "brie",
+ "burrata",
+ "butterkäse",
+ "cambozola",
+ "camembert",
+ "caseus",
+ "casgiu",
+ "cheddar",
+ "cheese",
+ "chiiz",
+ "chisi",
+ "chizi",
+ "colby",
+ "cottage",
+ "cuku",
+ "cáis",
+ "djathë",
+ "edelpilzkäse",
+ "farmaajo",
+ "feta",
+ "formaggio",
+ "formatge",
+ "fromage",
+ "fromazy",
+ "fromaĝo",
+ "fwomaj",
+ "gazta",
+ "gorgonzola",
+ "gouda",
+ "halloumi",
+ "handkäse",
+ "harzer",
+ "hirtenkäse",
+ "hohenheim",
+ "juust",
+ "juusto",
+ "kaas",
+ "kashkaval",
+ "keju",
+ "keso",
+ "kochkäse",
+ "käse",
+ "limburger",
+ "milbenkäse",
+ "mozzarella",
+ "nieheimer",
+ "obatzda",
+ "ostur",
+ "paneer",
+ "parmesan",
+ "pendir",
+ "penêr",
+ "pepperjack",
+ "provolone",
+ "quark",
+ "queijo",
+ "queixo",
+ "queso",
+ "raclette",
+ "rauchkäse",
+ "ricotta",
+ "roquefort",
+ "sajt",
+ "sires",
+ "sisi",
+ "spundekäs",
+ "swiss",
+ "sūris",
+ "tsiis",
+ "ziegel",
+ "チーズ",
+ "\N{CHEESE WEDGE}"
+ ].freeze
+end
\ No newline at end of file
diff --git a/src/modules/cheese_checker.rb b/src/modules/cheese_checker.rb
new file mode 100644
index 0000000..1366b72
--- /dev/null
+++ b/src/modules/cheese_checker.rb
@@ -0,0 +1,38 @@
+# cheeseBot
+# Copyright (C) 2026 Eri (csxkdv/nxkdv) nxkdv@thenight.club
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+require_relative '../lists/cheese_words'
+
+module CheeseChecker
+ WORDS_LIST = Lists::CHEESE_WORDS
+ PUNCTUATION = "!\"£$%^&*()[]{}'@#~;:,<.>/?-+\\|`¬"
+
+ NO_CHEESE = /[\s#{Regexp.escape(PUNCTUATION)}]*/
+
+ pattern_strings = WORDS_LIST.map do |word|
+ Regexp.escape(word).chars.map { |char| char + NO_CHEESE.source }.join
+ end
+
+ CHEESE_REGEX = /((?:#{pattern_strings.join('|')}))/im
+
+ def self.check_content(content)
+ changed_content = content.gsub(CHEESE_REGEX, "**\\1**")
+
+ return nil if changed_content == content
+
+ changed_content
+ end
+end
\ No newline at end of file
diff --git a/src/modules/database.rb b/src/modules/database.rb
new file mode 100644
index 0000000..98b464b
--- /dev/null
+++ b/src/modules/database.rb
@@ -0,0 +1,118 @@
+# cheeseBot
+# Copyright (C) 2026 Eri (csxkdv/nxkdv) nxkdv@thenight.club
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+require 'pg'
+
+module Database
+ DB_NAME = ENV['DB_NAME']
+ DB_USER = ENV['DB_USER']
+ DB_HOST = ENV['DB_HOST']
+ DB_PASSWORD = ENV['DB_PASSWORD']
+
+ def self.setup
+ create_database_if_not_exists
+ create_tables
+ end
+
+ def self.connect(db_name = DB_NAME)
+ PG.connect(
+ dbname: db_name,
+ user: DB_USER,
+ host: DB_HOST,
+ password: DB_PASSWORD
+ )
+ rescue PG::Error => e
+ puts "Database connection error: #{e.message}"
+ exit
+ end
+
+ def self.user_blacklisted?(user_id)
+ exists?("blacklist", user_id)
+ end
+
+ def self.server_blacklisted?(server_id)
+ exists?("server_blacklist", server_id)
+ end
+
+ def self.toggle_user_blacklist(user_id)
+ toggle("blacklist", user_id)
+ end
+
+ def self.toggle_server_blacklist(server_id)
+ toggle("server_blacklist", server_id)
+ end
+
+ private
+
+ def self.exists?(table, id)
+ conn = connect
+ result = conn.exec_params("SELECT 1 FROM #{table} WHERE id = $1", [id])
+ conn.close
+ !result.ntuples.zero?
+ end
+
+ def self.toggle(table, id)
+ conn = connect
+
+ if exists?(table, id)
+ conn.exec_params("DELETE FROM #{table} WHERE id = $1", [id])
+ conn.close
+ return false
+ else
+ conn.exec_params("INSERT INTO #{table} (id) VALUES ($1)", [id])
+ conn.close
+ return true
+ end
+ end
+
+ def self.create_database_if_not_exists
+ begin
+ conn = connect('postgres')
+ rescue PG::Error
+ puts "Could not connect to 'postgres' system database. Please create '#{DB_NAME}' manually."
+ return
+ end
+
+ result = conn.exec_params("SELECT 1 FROM pg_database WHERE datname = $1", [DB_NAME])
+
+ if result.ntuples.zero?
+ puts "Database '#{DB_NAME}' not found. Creating it..."
+ conn.exec("CREATE DATABASE \"#{DB_NAME}\"")
+ puts "Database '#{DB_NAME}' created successfully!"
+ end
+ conn.close
+ end
+
+ def self.create_tables
+ conn = connect
+
+ conn.exec(<<~SQL)
+ CREATE TABLE IF NOT EXISTS blacklist (
+ id BIGINT PRIMARY KEY
+ );
+ SQL
+
+ conn.exec(<<~SQL)
+ CREATE TABLE IF NOT EXISTS server_blacklist (
+ id BIGINT PRIMARY KEY
+ );
+ SQL
+
+ puts "Tables verified."
+ conn.close
+ end
+end
+
\ No newline at end of file