-
Notifications
You must be signed in to change notification settings - Fork 2
Created a very basic structure for the bot #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
dc20820
chore(env): setup development and production python venvs
SobaSkee 06c5122
feat: add message trigger command for bot
SobaSkee 9e90d4f
Create readme.md (#3)
h1divp 4ba7ef1
chore: complete merge conflict and rebase
52e0feb
chore: rewrite readme
SobaSkee f5cf531
merge origin/master to this feature branch
SobaSkee 4373f58
Merge remote-tracking branch 'origin/master' into stanley/basic-bot-s…
SobaSkee 9a63798
feat: add regex to identify potential scam/spam messages in antiSpam cog
SobaSkee 16e6d9f
refactor: organize and break up functions, add detailed comments, add…
SobaSkee c8e50f1
Merge remote-tracking branch 'origin/master' into stanley/basic-bot-s…
SobaSkee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| .env | ||
| /core/apps/discord-bot/.venv* | ||
| /core/apps/discord-bot/.venv* | ||
| *.log |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,75 @@ | ||
| ### Discord Bot | ||
| for venv run source .venv/bin/activate if get error about pip commands not found | ||
| (hi alex) | ||
| # Discord Bot | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| Before you begin, make sure you have: | ||
|
|
||
| * **Python 3.8+** installed and on your PATH | ||
| * **Git** (optional if you clone the repo) | ||
|
|
||
| *All commands assume you are in the `core/apps/discord-bot/` directory.* | ||
|
|
||
| ## 1. Create a Virtual Environment | ||
|
|
||
| ```bash | ||
| python -m venv .venv | ||
| ``` | ||
|
|
||
| ## 2. Activate the Environment | ||
|
|
||
| ### macOS / Linux | ||
|
|
||
| ```bash | ||
| source .venv/bin/activate | ||
| ``` | ||
|
|
||
| ### Windows (PowerShell) | ||
|
|
||
| ```powershell | ||
| .\.venv\Scripts\Activate.ps1 | ||
| ``` | ||
|
|
||
| *(Your prompt should now be prefixed with `(.venv)`.)* | ||
|
|
||
| ## 3. Install Dependencies | ||
|
|
||
| ```bash | ||
| # Upgrade pip | ||
| python -m pip install --upgrade pip | ||
|
|
||
| # Install runtime dependencies | ||
| pip install -r requirements.txt | ||
| ``` | ||
|
|
||
| ## 4. Configure Environment Variables | ||
|
|
||
| Create a file named `.env` in this directory with the following content: | ||
|
|
||
| ``` | ||
| DISCORD_TOKEN=YOUR_DISCORD_BOT_TOKEN_HERE | ||
| ``` | ||
|
|
||
| ## 5. Run the Bot | ||
|
|
||
| With the venv active, start your bot: | ||
|
|
||
| ```bash | ||
| python main.py | ||
| ``` | ||
|
|
||
| You should see something like: | ||
|
|
||
| ``` | ||
| Bot: SwampHackr is ready to go! | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| > If you ever switch to a fresh terminal session, re-activate the venv before running any commands: | ||
| > | ||
| > ```bash | ||
| > source .venv/bin/activate # (macOS/Linux) | ||
| > # or | ||
| > .\.venv\Scripts\Activate.ps1 # (Windows) | ||
| > ``` | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| import discord | ||
| from discord.ext import commands | ||
| import re | ||
| from typing import List, Pattern, Set | ||
| from utils.messaging import send_channel_message, send_dm | ||
|
|
||
|
|
||
|
|
||
| # Regular expressions for detecting spam patterns | ||
| SPAM_PATTERNS: List[Pattern] = [ | ||
| # Pattern for detecting ticket sales | ||
| re.compile(r""" | ||
| (?i) | ||
| \bselling\b | ||
| .{0,60}? | ||
| (tickets?|passes?|spots?|seats?) | ||
| (.{0,20}?\bfor\b.{0,20}?\$?\d{2,5})? | ||
| """, re.VERBOSE), | ||
|
|
||
| # Pattern for detecting subleasing advertisements | ||
| re.compile(r""" | ||
| (?i) | ||
| \b(sublease|subleasing|sublet|lease)\b | ||
| (.{0,20}?\bfor\b.{0,20}?\$?\d{2,5})? | ||
| """, re.VERBOSE), | ||
|
|
||
| # Pattern for detecting "DM if interested" messages | ||
| re.compile(r""" | ||
| (?i) | ||
| dm\s+ | ||
| (me\s+)?(if\s+)?interested\b | ||
| """, re.VERBOSE), | ||
| ] | ||
|
|
||
|
|
||
| class AntiSpam(commands.Cog): | ||
| """A cog that detects and handles spam messages in Discord channels. | ||
|
|
||
| This cog monitors all messages in the server and automatically removes | ||
| messages that match predefined spam patterns. It also notifies users | ||
| when their messages are removed. | ||
| """ | ||
|
|
||
| def __init__(self, bot: commands.Bot) -> None: | ||
| """Initialize the AntiSpam cog | ||
|
|
||
| Args: | ||
| bot: Discord bot instance | ||
| """ | ||
| self.bot: commands.Bot = bot | ||
| self.ignore_channels: Set[int] = set() | ||
|
|
||
|
|
||
| def is_spam(self, message: discord.Message) -> bool: | ||
| """Check if a message matches any spam patterns | ||
|
|
||
| Args: | ||
| message: Discord message to check | ||
|
|
||
| Returns: | ||
| bool: True if the message is determined to be spam, False otherwise | ||
| """ | ||
| content: str = message.content | ||
|
|
||
| for pattern in SPAM_PATTERNS: | ||
| if pattern.search(content): | ||
| return True | ||
|
|
||
| # TODO: Implement additional spam detection methods: | ||
| # - Check for repeated messages | ||
| # - Detect excessive mentions | ||
| # - Check for suspicious links | ||
| # - Monitor message frequency | ||
|
|
||
| return False | ||
|
|
||
| async def handle_spam(self, message: discord.Message) -> None: | ||
| """Handle a detected spam message | ||
|
|
||
| This method: | ||
| 1. Deletes the spam message | ||
| 2. Sends a notification in the channel by calling send_channel_message | ||
| 3. Sends a DM to the user explaining why their message was removed by calling send_dm | ||
|
|
||
| Args: | ||
| message: The spam message to handle | ||
|
|
||
| Note: | ||
| If the bot lacks permissions to delete messages or send DMs, | ||
| the error will be logged but not raised. | ||
| """ | ||
| try: | ||
| await message.delete() | ||
| content: str = f"{message.author.mention} Your message has been deleted for potential scam/spam." | ||
| await send_channel_message(message.channel, content, delete_after=5) | ||
|
|
||
| content = ( | ||
| f"Your message was automatically deleted for potential scam/spam content:\n" | ||
| f"```{message.content}```\n" | ||
| f"If you believe this was a mistake, please contact server staff for review." | ||
| ) | ||
| await send_dm(message.author, content) | ||
| except discord.Forbidden: | ||
| print("Bot lacks permissions to delete messages") | ||
|
|
||
| @commands.Cog.listener() | ||
| async def on_message(self, message: discord.Message) -> None: | ||
| """Event listener for new messages | ||
|
|
||
| This method is called for every message sent in the server. | ||
| 1. Ignores messages from bots | ||
| 2. Ignores messages in ignored channels | ||
| 3. Calls is_spam function to determine if message is spam | ||
|
|
||
| Args: | ||
| message: The message that triggered the event | ||
| """ | ||
| if message.author.bot: | ||
| return | ||
|
|
||
| if message.channel.id in self.ignore_channels: | ||
| return | ||
|
|
||
| if self.is_spam(message): | ||
| await self.handle_spam(message) | ||
|
|
||
|
|
||
| async def setup(bot: commands.Bot) -> None: | ||
| """Add the AntiSpam cog to the bot | ||
|
|
||
| Args: | ||
| bot: Discord bot instance | ||
| """ | ||
| await bot.add_cog(AntiSpam(bot)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| from discord.ext import commands | ||
| from discord import app_commands | ||
| import discord | ||
| from typing import Optional, Literal | ||
|
|
||
|
|
||
| class General(commands.Cog): | ||
| """A cog containing general utility commands for the server | ||
|
|
||
| This cog includes commands for: | ||
| - Basic server interactions | ||
| - Role management | ||
| - Fun commands | ||
| """ | ||
|
|
||
| def __init__(self, bot: commands.Bot) -> None: | ||
| """Initialize the General cog | ||
|
|
||
| Args: | ||
| bot: Discord bot instance | ||
| """ | ||
| self.bot: commands.Bot = bot | ||
|
|
||
| @commands.command() | ||
| async def test(self, ctx: commands.Context) -> None: | ||
| """Send a test message | ||
|
|
||
| Args: | ||
| ctx: The command context | ||
| """ | ||
| await ctx.send("Testing") | ||
|
|
||
| @app_commands.command( | ||
| name="role", | ||
| description="Assign or remove a role from yourself" | ||
| ) | ||
| @app_commands.describe( | ||
| action="Whether to assign or remove the role", | ||
| role="The role to assign or remove" | ||
| ) | ||
| async def manage_role( | ||
| self, | ||
| interaction: discord.Interaction, | ||
| action: Literal["assign", "remove"], | ||
| role: discord.Role, | ||
| member: discord.Member | ||
| ) -> None: | ||
| """Manage roles for the user who triggered the command | ||
|
|
||
| Args: | ||
| interaction: The interaction that triggered this command | ||
| action: Whether to assign or remove the role | ||
| role: The role to assign or remove | ||
|
|
||
| Note: | ||
| This command will: | ||
| 1. Check if the user already has/doesn't have the role | ||
| 2. Assign or remove the role if conditions are met | ||
| 3. Send appropriate feedback messages | ||
| """ | ||
| staff_role = discord.utils.get(interaction.guild.roles, name="Staff") | ||
|
|
||
| if not staff_role or staff_role not in interaction.user.roles: | ||
| await interaction.response.send_message( | ||
| "You don't have permission to use this command.", | ||
| ephemeral=True | ||
| ) | ||
| return | ||
|
|
||
| member = await interaction.guild.fetch_member(member.id) | ||
|
|
||
|
|
||
| has_role = role in member.roles | ||
|
|
||
| if action == "assign": | ||
| if has_role: | ||
| await interaction.response.send_message( | ||
| f"{member.mention} already has the **{role.name}** role.", | ||
| ephemeral=True | ||
| ) | ||
| return | ||
|
|
||
| try: | ||
| await member.add_roles(role) | ||
| await interaction.response.send_message( | ||
| f"Assigned **{role.name}** to {member.mention}.", | ||
| ephemeral=True | ||
| ) | ||
| # Send a followup message that will be deleted after 5 seconds | ||
| await interaction.followup.send( | ||
| f"{interaction.user.mention} assigned **{role.name}** role to {member.mention}.", | ||
| delete_after=5 | ||
| ) | ||
| except discord.Forbidden: | ||
| await interaction.response.send_message( | ||
| "I don't have permission to assign roles!", | ||
| ephemeral=True | ||
| ) | ||
| elif action == "remove": | ||
| if not has_role: | ||
| await interaction.response.send_message( | ||
| f"{member.mention} does not have the **{role.name}** role.", | ||
| ephemeral=True | ||
| ) | ||
| return | ||
|
|
||
| try: | ||
| await member.remove_roles(role) | ||
| await interaction.response.send_message( | ||
| f"Removed **{role.name}** from {member.mention}.", | ||
| ephemeral=True | ||
| ) | ||
| # Send a followup message that will be deleted after 5 seconds | ||
| await interaction.followup.send( | ||
| f"{interaction.user.mention} removed **{role.name}** role from {member.mention}.", | ||
| delete_after=5 | ||
| ) | ||
| except discord.Forbidden: | ||
| await interaction.response.send_message( | ||
| "I don't have permission to remove roles!", | ||
| ephemeral=True | ||
| ) | ||
| else: | ||
| # This will not be reached but just wanted to show add and remove for commands | ||
| await interaction.response.send_message( | ||
| "Invalid action. Please use 'assign' or 'remove'.", | ||
| ephemeral=True | ||
| ) | ||
|
|
||
|
|
||
| async def setup(bot: commands.Bot) -> None: | ||
| """Add the General cog to the bot | ||
|
|
||
| Args: | ||
| bot: Discord bot instance | ||
| """ | ||
| await bot.add_cog(General(bot)) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything from the
antiSpam.pyfile comments apply here too.