1
Fork 0
mirror of https://github.com/allthingslinux/tux.git synced 2024-10-02 16:43:12 +00:00

chore(archive): remove old files and update docs

This commit is contained in:
kzndotsh 2024-08-04 12:31:27 -04:00
parent e8b041fae8
commit edefd3a1df
18 changed files with 119 additions and 2072 deletions

View file

@ -1,59 +0,0 @@
## Installation
`poetry install` # Install dependencies with Poetry.
`poetry shell` # Activate the virtual environment.
`poetry pre-commit install` # Install pre-commit hooks.
## Development
`poetry run python tux/main.py` # Run the application with Poetry.
`poetry run pytest` # Run all tests.
## Docker
`docker-compose up` # Run the application with Docker.
## Linting
`poetry run pre-commit run --all-files` # Run all pre-commit hooks.
`poetry run pre-commit run <hook_id>` # Run a specific pre-commit hook.
## Linting and Formatting
`poetry run ruff check` # Lint all files in the current directory.
`poetry run ruff check --fix` # Lint all files in the current directory, and fix any fixable errors.
`poetry run ruff check --watch` # Lint all files in the current directory, and re-lint on change.
`poetry run ruff check path/to/code/` # Lint all files in `path/to/code` (and any subdirectories).
`poetry run ruff format` # Format all files in the current directory.
`poetry run ruff format path/to/code/` # Lint all files in `path/to/code` (and any subdirectories).
`poetry run ruff format path/to/file.py` # Format a single file.
## Git
`git checkout -b <branch_name>` # Create a new branch.
`git checkout <branch_name>` # Switch to an existing branch.
`git pull` # Pull changes from the remote repository.
`git branch -d <branch_name>` # Delete a branch.
`git status` # Check the status of the repository.
`git diff` # Show changes between commits, commit and working tree, etc.
`git log` # Show commit logs.
`git remote -v` # Show remote repositories.
`git remote add origin <repository_url>` # Add a remote repository.
`git add .` # Add all files to the staging area.
`git commit -m "Your commit message"` # Commit changes with a message.
`git push` # Push changes to the remote repository.

View file

@ -1,167 +0,0 @@
import discord
from discord import app_commands
from discord.ext import commands
from loguru import logger
from prisma.models import Infractions
from tux.database.controllers import DatabaseController
from tux.utils.embeds import EmbedCreator
from tux.utils.enums import InfractionType
class Ban(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.db_controller = DatabaseController()
async def insert_infraction(
self,
user_id: int,
moderator_id: int,
infraction_type: InfractionType,
infraction_reason: str,
) -> Infractions | None:
"""
Inserts a new infraction into the database.
Parameters
----------
user_id : int
The ID of the user for whom the infraction is created.
moderator_id : int
The ID of the moderator who created the infraction.
infraction_type : InfractionType
The type of the infraction.
infraction_reason : str
The reason for the infraction.
Returns
-------
Infractions | None
The newly created infraction if successful, otherwise None.
"""
try:
return await self.db_controller.infractions.create_infraction(
user_id=user_id,
moderator_id=moderator_id,
infraction_type=infraction_type,
infraction_reason=infraction_reason,
)
except Exception as error:
logger.error(f"Failed to create infraction for user {user_id}. Error: {error}")
return None
async def get_or_create_user(self, member: discord.Member) -> None:
"""
Retrieves or creates a user in the database.
Parameters
----------
member : discord.Member
The member to retrieve or create in the database.
"""
user = await self.db_controller.users.get_user_by_id(member.id)
if not user:
await self.db_controller.users.create_user(
user_id=member.id,
name=member.name,
display_name=member.display_name,
mention=member.mention,
bot=member.bot,
created_at=member.created_at,
joined_at=member.joined_at,
)
async def get_or_create_moderator(self, interaction: discord.Interaction) -> None:
"""
Retrieves or creates a moderator in the database.
Parameters
----------
interaction : discord.Interaction
The interaction to retrieve or create the moderator from.
"""
moderator = await self.db_controller.users.get_user_by_id(interaction.user.id)
moderator_context = None
if interaction.guild:
moderator_context = interaction.guild.get_member(interaction.user.id)
if not moderator:
await self.db_controller.users.create_user(
user_id=interaction.user.id,
name=interaction.user.name,
display_name=interaction.user.display_name,
mention=interaction.user.mention,
bot=interaction.user.bot,
created_at=interaction.user.created_at,
joined_at=moderator_context.joined_at if moderator_context else None,
)
@app_commands.checks.has_any_role("Root", "Admin", "Sr. Mod", "Mod")
@app_commands.command(name="ban", description="Issues a ban to a member of the server.")
@app_commands.describe(member="The member to ban", reason="The reason for issuing the ban")
async def ban(
self, interaction: discord.Interaction, member: discord.Member, reason: str | None = None
) -> None:
"""
Issues a ban to a member of the server.
Parameters
----------
interaction : discord.Interaction
The interaction that triggered the command.
member : discord.Member
The member to ban.
reason : str | None, optional
The reason for issuing the ban, by default None.
"""
reason = reason or "No reason provided"
await self.get_or_create_user(member)
await self.get_or_create_moderator(interaction)
try:
await member.ban(reason=reason)
new_ban = await self.insert_infraction(
user_id=member.id,
moderator_id=interaction.user.id,
infraction_type=InfractionType.BAN,
infraction_reason=reason,
)
ban_id = new_ban.id if new_ban else "Unknown"
embed = EmbedCreator.create_infraction_embed(
title="",
description="",
interaction=interaction,
)
embed.add_field(name="Action", value="Ban", inline=True)
embed.add_field(name="Case ID", value=f"`{ban_id}`", inline=True)
embed.add_field(name="Reason", value=f"`{reason}`", inline=False)
embed.add_field(name="Moderator", value=f"{interaction.user.display_name}", inline=True)
logger.info(f"Ban issued to {member.display_name} ({member.id}) for: {reason}")
except Exception as error:
msg = f"Failed to issue ban to {member.display_name}."
embed = EmbedCreator.create_error_embed(
title="Ban Failed",
description=msg,
interaction=interaction,
)
logger.error(f"{msg} Error: {error}")
await interaction.response.send_message(embed=embed)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(Ban(bot))

View file

@ -1,27 +0,0 @@
import discord
from discord.ext import commands
from loguru import logger
class BotEventsCog(commands.Cog, name="Bot Events Handler"):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
@commands.Cog.listener()
async def on_ready(self) -> None:
logger.info(f"{self.bot.user} has connected to Discord!")
await self.bot.change_presence(
activity=discord.Activity(
type=discord.ActivityType.watching,
name="All Things Linux",
)
)
@commands.Cog.listener()
async def on_disconnect(self) -> None:
logger.warning("Bot has disconnected from Discord.")
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(BotEventsCog(bot))

View file

@ -1,44 +0,0 @@
from discord import Member, User
from discord.ext import commands
from discord.ext.commands import MissingPermissions
from tux.utils.tux_logger import TuxLogger
logger = TuxLogger(__name__)
class CommandCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
super().__init__()
def cog_check(self, ctx):
"""
This function is called before every command in the cog.
Args:
- ctx (commands.Context): The context of the command.
Returns
- bool: True if the user has the required permission, False otherwise.
"""
if not ctx.guild:
logger.warning("Command used outside of a guild.")
return False
if isinstance(ctx.author, Member):
author_roles = [role.id for role in ctx.author.roles]
command_name = ctx.command.name if ctx.command else ""
missing_permissions = self.bot.permissions.missing_permissions(
author_roles, command_name
)
logger.info(f"User '{ctx.author.name}' has attempted to use {command_name}.")
if missing_permissions is None:
logger.debug(f"User '{ctx.author.name}' has permission to use {command_name}.")
return True
else:
raise MissingPermissions(missing_permissions)
elif isinstance(ctx.author, User):
return False

View file

@ -1,63 +0,0 @@
import contextlib
import sys
import traceback
import discord
from discord.ext import commands
class ContextCommandErrorHandler(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
@commands.Cog.listener()
async def on_command_error(self, ctx: commands.Context[commands.Bot], error: Exception) -> None:
"""
Handles errors that occur during command execution.
Args:
ctx: The context in which the error occurred.
error: The exception that was raised.
Returns
None
Raises
None
"""
# If the command has its own error handler, or the cog has its own error handler, return
if hasattr(ctx.command, "on_error") or (
ctx.cog and ctx.cog._get_overridden_method(ctx.cog.cog_command_error) is not None
):
return
# Ignore these errors
ignored = (commands.CommandNotFound,)
# Get the original exception if it exists
error = getattr(error, "original", error)
# If the error is in the ignored tuple, return
if isinstance(error, ignored):
return
# If the command has been disabled, send a reply to the user
if isinstance(error, commands.DisabledCommand):
await ctx.send(f"{ctx.command} has been disabled.")
# Private message error
elif isinstance(error, commands.NoPrivateMessage):
with contextlib.suppress(discord.HTTPException):
await ctx.author.send(f"{ctx.command} can not be used in Private Messages.")
# elif isinstance(error, commands.BadArgument):
# if ctx.command and ctx.command.qualified_name == "tag list":
# await ctx.send("I could not find that member. Please try again.")
else:
traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)
async def setup(bot: commands.Bot):
await bot.add_cog(ContextCommandErrorHandler(bot))

View file

@ -1,58 +0,0 @@
name: 'Dependency Review'
# Trigger on pull requests and a scheduled weekly run
on:
schedule:
- cron: '0 0 * * 0' # Runs every week at midnight on Sunday
permissions:
contents: write
issues: write
pull-requests: write
jobs:
# Job for pull request event
dependency-review-pr:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v3
# Install Python
- name: Setup Python
uses: actions/setup-python@v5.0.0
with:
python-version: 3.11
# Install Poetry
- name: Poetry Install
uses: knowsuchagency/poetry-install@v2
# Run Poetry commands
- name: Update Python Poetry package
uses: dishapatel010/action-poetry-package-update@V2.0.1
# Export requirements.txt from pyproject.toml
- name: Export requirements.txt
uses: Divkix/poetry-export-requirements-action@v1.4.0
- name: Dependency Review
uses: actions/dependency-review-action@v3
with:
base-ref: ${{ github.event.pull_request.base.sha || 'main' }}
head-ref: ${{ github.event.pull_request.head.sha || github.ref }}
# Job for scheduled event
dependency-review-scheduled:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4
- name: Dependency Review
uses: actions/dependency-review-action@v3
with:
base-ref: 'main'
head-ref: ${{ github.ref }}

View file

@ -1,352 +0,0 @@
# import discord
# import github
# from discord import app_commands
# from discord.ext import commands
# from github import Auth, Github
# from loguru import logger
# from tux.utils.constants import Constants as CONST
# from tux.utils.embeds import EmbedCreator
# auth = Auth.Token(CONST.GITHUB_TOKEN)
# g = Github(auth=auth)
# class GitHub(commands.Cog):
# def __init__(self, bot: commands.Bot):
# self.bot = bot
# group_issues = app_commands.Group(name="issues", description="Mess with GitHub Issues.")
# group_pr = app_commands.Group(name="pr", description="Mess with GitHub Pull Requests.")
# @commands.has_any_role("Contributor", "Owner", "Admin")
# @group_issues.command(name="get", description="Get a certain github issue.")
# async def grab(
# self, interaction: discord.Interaction, issue: int, repo: str = CONST.GITHUB_REPO
# ) -> None:
# try:
# repository = g.get_repo(repo)
# sel_issue = repository.get_issue(number=issue)
# embed = EmbedCreator.create_success_embed(
# title="Issue Information",
# description=f"Issue #: {issue} | Repo: {repository.full_name}",
# interaction=interaction,
# )
# embed.add_field(name="Issue Title", value=sel_issue.title)
# embed.add_field(name="URL", value=sel_issue.url)
# except github.UnknownObjectException:
# logger.error(
# f"{interaction.user} failed to use the get command in {interaction.channel}."
# )
# embed = EmbedCreator.create_error_embed(
# title="Error",
# description="Issue not found. Please check the issue number and repository name.",
# )
# logger.info(f"{interaction.user} used the get command in {interaction.channel}.")
# await interaction.response.send_message(embed=embed)
# @commands.has_any_role("Contributor", "Owner", "Admin")
# @group_issues.command(name="add", description="Add an issue to GitHub.")
# async def add(
# self,
# interaction: discord.Interaction,
# title: str,
# repo: str = CONST.GITHUB_REPO,
# ) -> None:
# # Doing some basic concept of an error handler to ensure that a fake repo isn't put in. it HAS handling, it just
# # doesn't look very pretty, so I smashed it into an embed.
# try:
# repository = g.get_repo(repo)
# new_issue = repository.create_issue(title=title)
# embed = EmbedCreator.create_success_embed(
# title="Issue Created!",
# description=f"Issue #: {new_issue.number!s} | Repo: {repository.full_name}",
# interaction=interaction,
# )
# embed.add_field(name="Issue Title", value=new_issue.title)
# embed.add_field(name="URL", value=new_issue.url)
# except github.UnknownObjectException:
# logger.error(
# f"{interaction.user} failed to use the add command in {interaction.channel}."
# )
# embed = EmbedCreator.create_error_embed(
# title="Error", description="Repo or issue not found.", interaction=interaction
# )
# logger.info(f"{interaction.user} used the add command in {interaction.channel}.")
# await interaction.response.send_message(embed=embed)
# @commands.has_any_role("Contributor", "Owner", "Admin")
# @group_issues.command(name="comment", description="comment on an issue on GitHub.")
# async def cmt(
# self,
# interaction: discord.Interaction,
# comment: str,
# issue: int,
# repo: str = CONST.GITHUB_REPO,
# ) -> None:
# try:
# repository = g.get_repo(repo)
# sel_issue = repository.get_issue(number=issue)
# sel_issue.create_comment(comment)
# embed = EmbedCreator.create_success_embed(
# title="Comment Created!",
# description=f"Issue #: {sel_issue.number!s} | Repo: {repository.full_name}",
# interaction=interaction,
# )
# embed.add_field(name="Comment", value=comment)
# embed.add_field(name="URL", value=sel_issue.url)
# except github.UnknownObjectException:
# logger.error(
# f"{interaction.user} failed to use the comment command in {interaction.channel}."
# )
# embed = EmbedCreator.create_error_embed(
# title="Error", description="Repo or issue not found.", interaction=interaction
# )
# logger.info(f"{interaction.user} used the comment command in {interaction.channel}.")
# await interaction.response.send_message(embed=embed)
# # Pull request stuff starts here. make sure your socks are on tight.
# @commands.has_any_role("Contributor", "Owner", "Admin")
# @group_pr.command(name="create", description="Create a pull request.")
# async def create(
# self,
# interaction: discord.Interaction,
# base: str,
# compare: str,
# title: str,
# body: str,
# repo: str = CONST.GITHUB_REPO,
# ) -> None:
# try:
# repository = g.get_repo(repo)
# body += " This pull request was sent via Tux."
# pr = repository.create_pull(base=base, head=compare, title=title, body=body)
# embed = EmbedCreator.create_success_embed(
# title="Pull Request Created!",
# description=f"Number: {pr.number!s}| Repo:{repository.full_name}",
# interaction=interaction,
# )
# embed.add_field(name="Base", value=base)
# embed.add_field(name="Compare", value=compare)
# embed.add_field(name="Url", value=pr.url)
# embed.add_field(name="PR Title", value=pr.title)
# except github.UnknownObjectException:
# embed = EmbedCreator.create_error_embed(
# title="Error",
# description="Repo or pull request not found.",
# interaction=interaction,
# )
# logger.error(
# f"{interaction.user} failed to use the create command in {interaction.channel}."
# )
# # Something is telling me the formatting above isn't correct, but that can be sorted out on pull request.
# logger.info(f"{interaction.user} used the add command in {interaction.channel}.")
# await interaction.response.send_message(embed=embed)
# @commands.has_any_role("Contributor", "Owner", "Admin")
# @group_pr.command(name="get", description="Get a certain github P.R.")
# async def get(
# self,
# interaction: discord.Interaction,
# pr: int,
# repo: str = CONST.GITHUB_REPO,
# ) -> None:
# try:
# repository = g.get_repo(repo)
# sel_pr = repository.get_pull(number=pr)
# embed = EmbedCreator.create_success_embed(
# title="Issue Information",
# description=f"Issue #: {pr} | Repo: {repository.full_name}",
# interaction=interaction,
# )
# embed.add_field(name="PR Title", value=sel_pr.title)
# embed.add_field(name="URL", value=sel_pr.url)
# embed.add_field(name="Base", value=sel_pr.base)
# embed.add_field(name="Compare", value=sel_pr.head)
# except github.UnknownObjectException:
# logger.error(
# f"{interaction.user} failed to use the get command in {interaction.channel}."
# )
# embed = EmbedCreator.create_error_embed(
# title="Error",
# description="Repo or pull request not found.",
# interaction=interaction,
# )
# logger.error(
# f"{interaction.user} failed to use the create command in {interaction.channel}."
# )
# logger.info(f"{interaction.user} used the get command in {interaction.channel}.")
# await interaction.response.send_message(embed=embed)
# @commands.has_any_role("Contributor", "Owner", "Admin")
# @group_pr.command(name="comment", description="comment on a pull request on GitHub.")
# async def comment(
# self,
# interaction: discord.Interaction,
# comment: str,
# pr: int,
# repo: str = CONST.GITHUB_REPO,
# ) -> None:
# try:
# repository = g.get_repo(repo)
# sel_pr = repository.get_pull(number=pr)
# sel_pr.create_issue_comment(comment)
# embed = EmbedCreator.create_success_embed(
# title="Comment Created!",
# description=f"PR #: {sel_pr.number!s} | Repo: {repository.full_name}",
# interaction=interaction,
# )
# embed.add_field(name="Comment", value=comment)
# embed.add_field(name="URL", value=sel_pr.url)
# except github.UnknownObjectException:
# logger.error(
# f"{interaction.user} failed to use the comment command in {interaction.channel}."
# )
# embed = EmbedCreator.create_error_embed(
# title="Error",
# description="Repo or pull request not found.",
# interaction=interaction,
# )
# logger.info(f"{interaction.user} used the cmt command in {interaction.channel}.")
# await interaction.response.send_message(embed=embed)
# async def setup(bot: commands.Bot) -> None:
# await bot.add_cog(GitHub(bot))
import discord
import github
from discord import app_commands
from discord.ext import commands
from github import Auth, Github
from loguru import logger
from tux.utils.constants import Constants as CONST
from tux.utils.embeds import EmbedCreator
auth = Auth.Token(CONST.GITHUB_TOKEN)
g = Github(auth=auth)
class GitHub(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
group_issues = app_commands.Group(name="issues", description="Mess with GitHub Issues.")
group_pr = app_commands.Group(name="pr", description="Mess with GitHub Pull Requests.")
async def _get_repo(self, interaction: discord.Interaction, repo: str):
try:
return g.get_repo(repo)
except github.UnknownObjectException:
logger.error(f"{interaction.user} failed to get repository {repo} in {interaction.channel}.")
return None
async def _get_issue(self, interaction: discord.Interaction, repo: str, issue: int):
repository = await self._get_repo(interaction, repo)
if repository is None:
return None
try:
return repository.get_issue(number=issue)
except github.UnknownObjectException:
logger.error(f"{interaction.user} failed to get issue #{issue} in {interaction.channel}.")
return None
async def _create_error_embed(self, title, description, interaction) -> discord.Embed:
return EmbedCreator.create_error_embed(title=title, description=description, interaction=interaction)
@commands.has_any_role("Contributor", "Owner", "Admin")
@group_issues.command(name="get", description="Get a certain github issue.")
async def grab(self, interaction: discord.Interaction, issue: int, repo: str = CONST.GITHUB_REPO) -> None:
issue = await self._get_issue(interaction, repo, issue)
if issue is None:
embed = await self._create_error_embed("Error", "Issue not found. Please check the issue number and repository name.", interaction)
else:
embed = EmbedCreator.create_success_embed(title="Issue Information", description=f"Issue #: {issue} | Repo: {repository.full_name}", interaction=interaction)
embed.add_field(name="Issue Title", value=issue.title)
embed.add_field(name="URL", value=issue.url)
logger.info(f"{interaction.user} used the get command in {interaction.channel}.")
await interaction.response.send_message(embed=embed)
@commands.has_any_role("Contributor", "Owner", "Admin")
@group_issues.command(name="add", description="Add an issue to GitHub.")
async def add(self,interaction: discord.Interaction,title: str,repo: str = CONST.GITHUB_REPO,) -> None:
repository = await self._get_repo(interaction, repo)
if repository is None: return
new_issue = repository.create_issue(title=title)
embed = EmbedCreator.create_success_embed(title="Issue Created!", description=f"Issue #: {new_issue.number!s} | Repo: {repository.full_name}", interaction=interaction)
embed.add_field(name="Issue Title", value=new_issue.title)
embed.add_field(name="URL", value=new_issue.url)
logger.info(f"{interaction.user} used the add command in {interaction.channel}.")
await interaction.response.send_message(embed=embed)
@commands.has_any_role("Contributor", "Owner", "Admin")
@group_issues.command(name="comment", description="Comment on an issue on GitHub.")
async def cmt(self,interaction: discord.Interaction,comment: str,issue: int,repo: str = CONST.GITHUB_REPO,) -> None:
issue = await self._get_issue(interaction, repo, issue)
if issue is None:
embed = await self._create_error_embed("Error", "Issue not found. Please check the issue number and repository name.", interaction)
else:
issue.create_comment(comment)
embed = EmbedCreator.create_success_embed(title="Comment Created!", description=f"Issue #: {issue.number!s} | Repo: {repository.full_name}", interaction=interaction)
embed.add_field(name="Comment", value=comment)
embed.add_field(name="URL", value=issue.url)
logger.info(f"{interaction.user} used the comment command in {interaction.channel}.")
await interaction.response.send_message(embed=embed)
@commands.has_any_role("Contributor", "Owner", "Admin")
@group_pr.command(name="create", description="Create a pull request.")
async def create(self,interaction: discord.Interaction,base: str,compare: str,title: str,body: str,repo: str = CONST.GITHUB_REPO,) -> None:
repository = await self._get_repo(interaction, repo)
if repository is None:
embed = await self._create_error_embed("Error", "Repo not found.", interaction)
else:
body += " This pull request was sent via Tux."
pr = repository.create_pull(base=base, head=compare, title=title, body=body)
embed = EmbedCreator.create_success_embed(title="Pull Request Created!", description=f"Number: {pr.number!s}| Repo:{repository.full_name}", interaction=interaction)
embed.add_field(name="Base", value=base)
embed.add_field(name="Compare", value=compare)
embed.add_field(name="Url", value=pr.url)
embed.add_field(name="PR Title", value=pr.title)
logger.info(f"{interaction.user} used the add command in {interaction.channel}.")
await interaction.response.send_message(embed=embed)
@commands.has_any_role("Contributor", "Owner", "Admin")
@group_pr.command(name="get", description="Get a certain github P.R.")
async def get(self,interaction: discord.Interaction,pr: int,repo: str = CONST.GITHUB_REPO,) -> None:
.....
@commands.has_any_role("Contributor", "Owner", "Admin")
@group_pr.command(name="comment", description="Comment on a pull request on GitHub.")
async def comment(self,interaction: discord.Interaction,comment: str,pr: int,repo: str = CONST.GITHUB_REPO,) -> None:
.....
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(GitHub(bot))

View file

@ -1,74 +0,0 @@
import traceback
from prisma import Prisma
class PrismaExt(Prisma):
async def connect_client(self) -> None:
await self.connect()
async def where_first(self, table: str, column: str, item: str) -> object:
try:
table_obj = getattr(self, table)
data = await table_obj.find_first(
where={column: item},
)
return data
except Exception:
traceback.print_exc()
async def where_unique(self, table: str, column: str, item: str) -> object:
try:
table_obj = getattr(self, table)
data = await table_obj.find_unique(
where={column: item},
)
return data
except Exception:
traceback.print_exc()
async def where_many(self, table: str, column: str, item: str) -> object:
"""
You specify the column that you are looking for an use item name
"""
try:
table_obj = getattr(self, table)
data = await table_obj.find_many(
where={column: item},
)
return data
except Exception:
traceback.print_exc()
async def db_data(self, obj_name: str) -> list:
"""
Returns all items in a table object
"""
try:
obj = getattr(self, obj_name)
items = await obj.find_many()
return items
except Exception:
traceback.print_exc()
async def sql_executer(self, query: str) -> list:
try:
val = await self.query_raw(query)
return val
except Exception:
traceback.print_exc()

View file

@ -1,38 +0,0 @@
import datetime
import os
import discord
from discord.ext import commands
from loguru import logger
class KaizenPingCounter(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.ping_counter = 0
log_path = "logs/kaizen_ping_counter.log"
os.makedirs(os.path.dirname(log_path), exist_ok=True)
logger.add(log_path, rotation="00:00")
self.last_reset_time = datetime.datetime.now()
@commands.Cog.listener()
async def on_message(self, message: discord.Message) -> None:
if message.author.bot:
return
kaizen = self.bot.get_user(1046905234200469504)
now = datetime.datetime.now()
if now - self.last_reset_time > datetime.timedelta(hours=24):
self.last_reset_time = now
logger.info(f"Kaizen received {self.ping_counter} pings during the last 24 hours.")
self.ping_counter = 0
if kaizen in message.mentions:
self.ping_counter += 1
await message.reply(f"Kaizen has been pinged {self.ping_counter} times.")
logger.info(f"Kaizen has been pinged {self.ping_counter} times.")
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(KaizenPingCounter(bot))

View file

@ -1,265 +0,0 @@
# import discord
# from discord import app_commands
# from discord.ext import commands
# from loguru import logger
# from prisma.models import Infractions
# from tux.database.controllers import DatabaseController
# from tux.utils.embeds import EmbedCreator
# from tux.utils.enums import InfractionType
# class Kick(commands.Cog):
# def __init__(self, bot: commands.Bot) -> None:
# self.bot = bot
# self.db_controller = DatabaseController().infractions
# async def insert_infraction(
# self,
# user_id: int,
# moderator_id: int,
# infraction_type: InfractionType,
# infraction_reason: str,
# ) -> Infractions | None:
# """
# Inserts an infraction into the database.
# Args:
# user_id: The user ID who is being infracted.
# moderator_id: The moderator ID who is creating the infraction.
# infraction_type: The type of infraction.
# infraction_reason: The reason for the infraction.
# Returns
# An instance of Infractions if successful, None otherwise.
# """
# try:
# return await self.db_controller.create_infraction(
# user_id=user_id,
# moderator_id=moderator_id,
# infraction_type=infraction_type,
# infraction_reason=infraction_reason,
# )
# except Exception as error:
# logger.error(f"Failed to create infraction for user {user_id}. Error: {error}")
# return None
# @app_commands.checks.has_any_role("Admin", "Sr. Mod", "Mod", "Jr. Mod")
# @app_commands.command(name="kick", description="Kicks a member from the server.")
# @app_commands.describe(member="Which member to kick", reason="Reason for kick")
# async def kick(
# self, interaction: discord.Interaction, member: discord.Member, reason: str | None = None
# ) -> None:
# """
# Kicks a member from the server.
# Args:
# interaction: The interaction context for this command.
# member: The Discord member to be kicked.
# reason: The reason for kicking the member.
# """
# reason = reason or "No reason provided"
# try:
# new_kick = await self.insert_infraction(
# user_id=member.id,
# moderator_id=interaction.user.id,
# infraction_type=InfractionType.KICK,
# infraction_reason=reason,
# )
# embed = EmbedCreator.create_infraction_embed(
# title="",
# description="",
# interaction=interaction,
# )
# embed.add_field(
# name="Case ID", value=f"`{new_kick.id if new_kick else 'Unknown'}`", inline=True
# )
# embed.add_field(name="Action", value="Kick", inline=True)
# embed.add_field(name="Reason", value=f"`{reason}`", inline=False)
# embed.add_field(name="By", value=f"{interaction.user.mention}", inline=True)
# embed.add_field(name="To", value=f"{member.mention}", inline=True)
# logger.info(f"Kicked {member.display_name} ({member.id}): {reason}")
# except Exception as error:
# msg = f"Failed to kick {member.display_name} ({member.id})."
# embed = EmbedCreator.create_error_embed(
# title="Kick Failed", description=msg, interaction=interaction
# )
# logger.error(f"{msg} Error: {error}")
# await interaction.response.send_message(embed=embed)
# async def setup(bot: commands.Bot) -> None:
# await bot.add_cog(Kick(bot))
import discord
from discord import app_commands
from discord.ext import commands
from loguru import logger
from prisma.models import Infractions
from tux.database.controllers import DatabaseController
from tux.utils.embeds import EmbedCreator
from tux.utils.enums import InfractionType
class Kick(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.db_controller = DatabaseController()
async def insert_infraction(
self,
user_id: int,
moderator_id: int,
infraction_type: InfractionType,
infraction_reason: str,
) -> Infractions | None:
"""
Inserts an infraction into the database.
Parameters
----------
user_id : int
The user ID who is being infracted.
moderator_id : int
The moderator ID who is creating the infraction.
infraction_type : InfractionType
The type of infraction.
infraction_reason : str
The reason for the infraction.
Returns
-------
Infractions | None
The newly created infraction if successful, None otherwise.
"""
try:
return await self.db_controller.infractions.create_infraction(
user_id=user_id,
moderator_id=moderator_id,
infraction_type=infraction_type,
infraction_reason=infraction_reason,
)
except Exception as error:
logger.error(f"Failed to create infraction for user {user_id}. Error: {error}")
return None
async def get_or_create_user(self, member: discord.Member) -> None:
"""
Retrieves or creates a user in the database.
Parameters
----------
member : discord.Member
The member to retrieve or create in the database.
"""
user = await self.db_controller.users.get_user_by_id(member.id)
if not user:
await self.db_controller.users.create_user(
user_id=member.id,
name=member.name,
display_name=member.display_name,
mention=member.mention,
bot=member.bot,
created_at=member.created_at,
joined_at=member.joined_at,
)
async def get_or_create_moderator(self, interaction: discord.Interaction) -> None:
"""
Retrieves or creates a moderator in the database.
Parameters
----------
interaction : discord.Interaction
The interaction to retrieve or create in the database.
"""
moderator = await self.db_controller.users.get_user_by_id(interaction.user.id)
moderator_context = None
if interaction.guild:
moderator_context = interaction.guild.get_member(interaction.user.id)
if not moderator:
await self.db_controller.users.create_user(
user_id=interaction.user.id,
name=interaction.user.name,
display_name=interaction.user.display_name,
mention=interaction.user.mention,
bot=interaction.user.bot,
created_at=interaction.user.created_at,
joined_at=moderator_context.joined_at if moderator_context else None,
)
@app_commands.checks.has_any_role("Root", "Admin", "Sr. Mod", "Mod")
@app_commands.command(name="kick", description="Issues a kick to a member of the server.")
@app_commands.describe(member="The member to kick", reason="The reason for issuing the kick")
async def kick(
self, interaction: discord.Interaction, member: discord.Member, reason: str | None = None
) -> None:
"""
Issues a kick to a member of the server.
Parameters
----------
interaction : discord.Interaction
The interaction context for this command.
member : discord.Member
The Discord member to be kicked.
reason : str | None, optional
The reason for kicking the member, by default None.
"""
reason = reason or "No reason provided"
await self.get_or_create_user(member)
await self.get_or_create_moderator(interaction)
try:
new_kick = await self.insert_infraction(
user_id=member.id,
moderator_id=interaction.user.id,
infraction_type=InfractionType.BAN,
infraction_reason=reason,
)
kick_id = new_kick.id if new_kick else "Unknown"
embed = EmbedCreator.create_infraction_embed(
title="",
description="",
interaction=interaction,
)
embed.add_field(name="Action", value="Kick", inline=True)
embed.add_field(name="Case ID", value=f"`{kick_id}`", inline=True)
embed.add_field(name="Reason", value=f"`{reason}`", inline=False)
embed.add_field(name="Moderator", value=f"{interaction.user.display_name}", inline=True)
logger.info(f"Kick issued to {member.display_name} ({member.id}) for: {reason}")
except Exception as error:
msg = f"Failed to issue kick to {member.display_name}."
embed = EmbedCreator.create_error_embed(
title="Kick Failed",
description=msg,
interaction=interaction,
)
logger.error(f"{msg} Error: {error}")
await interaction.response.send_message(embed=embed)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(Kick(bot))

View file

@ -1,114 +0,0 @@
import configparser
import logging
from discord.ext import commands
from tux.utils.tux_logger import TuxLogger
logger = TuxLogger(__name__)
class PermissionNotFoundError(Exception):
pass
class Permissions:
def __init__(self, debug: bool = False):
config = configparser.ConfigParser()
config.read("config/settings.ini")
self.feature_permissions_section = config["Feature_Permissions"]
self.permissions_section = config["Permissions"]
if debug:
logger.setLevel(logging.DEBUG)
def _get_command_permissions_group(self, command):
"""
Retrieve the permission group associated with a command.
Args:
command (str): The command to get the permission group for.
Returns
str: The permission group for the command.
Raises
commands.CommandNotFound: If the command is not found in the configuration.
"""
command_permissions_group = self.feature_permissions_section.get(command, None)
if command_permissions_group is None:
raise commands.CommandNotFound(command)
return command_permissions_group
def _get_command_permissions(self, command_permissions_group):
"""
Retrieve the permissions associated with a permission group.
Args:
command_permissions_group (str): The permission group to get permissions for.
Returns
str | None: The permissions for the group or None if it's the "Everyone" group.
Raises
PermissionNotFoundError: If permissions for the group are not found in the configuration.
"""
if command_permissions_group == "Everyone":
return None
command_permissions = self.permissions_section.get(command_permissions_group, None)
if command_permissions is None:
raise PermissionNotFoundError(
f"Permissions for group '{command_permissions_group}' not found in the configuration."
)
return command_permissions
def _get_required_permissions(self, command_permissions):
"""
Retrieve the required permissions from a string.
Args:
command_permissions (str): The comma-separated string of required permissions.
Returns
List[str]: The list of required permissions.
"""
return [role.strip() for role in command_permissions.split(",")]
def missing_permissions(self, roles, command) -> list[str] | None:
"""
Check for missing permissions for a command and roles.
Args:
roles (List[str]): The list of roles to check against required permissions.
command (str): The command to check for permissions.
Returns
List[str] | None: List of missing permissions or None if all are present.
"""
command_permissions_group = self._get_command_permissions_group(command)
command_permissions = self._get_command_permissions(command_permissions_group)
if command_permissions is None:
return None
required_permissions = self._get_required_permissions(command_permissions)
shared_permissions = [role for role in required_permissions if int(role) in roles]
return [command_permissions_group] if not shared_permissions else None
def reload_ini_file(self, file_path):
"""
Reload the INI file.
Args:
file_path (str): The path to the INI file.
Returns
ConfigParser: The reloaded configuration.
"""
config = configparser.ConfigParser()
config.read(file_path)
self.feature_permissions_section = config["Feature_Permissions"]
self.permissions_section = config["Permissions"]

View file

@ -1,51 +0,0 @@
import discord
from discord import app_commands
from discord.ext import commands
class Roles(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
role = app_commands.Group(name="roles", description="Role commands.")
@app_commands.checks.has_any_role("Admin")
@role.command(name="create", description="Creates a role in the guild.")
async def create(self, interaction: discord.Interaction, name: str) -> None:
"""
Creates a role in the guild.
Parameters
----------
interaction : discord.Interaction
The interaction object.
name : str
The name of the role to create.
"""
if interaction.guild is not None:
role = await interaction.guild.create_role(name=name)
await interaction.response.send_message(f"Created role {role.name}.")
@app_commands.checks.has_any_role("Admin")
@role.command(name="delete", description="Deletes a role in the guild.")
async def delete(self, interaction: discord.Interaction, role: discord.Role) -> None:
"""
Deletes a role in the guild.
Parameters
----------
interaction : discord.Interaction
The interaction object.
role : discord.Role
The role to delete.
"""
await role.delete()
await interaction.response.send_message(f"Deleted role {role.name}.")
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(Roles(bot))

View file

@ -1,30 +0,0 @@
;;;;;;;;;;;;;;;;;;;; Just an example ini file we could abstract from.
[Permissions]
Owner = 1172248516370894869
Admin = 1172248516370894869,1182064847052091484
Mod = 1172248516370894869,1182064847052091484,1172333934051336264
Jr_Mod = 1172248516370894869,1182064847052091484,1172333934051336264,1172643385425793156
[Feature_Permissions]
; Admin
load = Admin
unload = Admin
sync = Admin
clear = Admin
reload = Admin
; Moderation
ban = Mod
kick = Jr_Mod
; Utility
; Support
; Fun/Community
ping = Everyone
server = Everyone
rolecount = Everyone
help = Everyone
; Misc

View file

@ -1,196 +0,0 @@
import datetime
import discord
from discord import app_commands
from discord.ext import commands
from loguru import logger
from pytz import UTC
from prisma.models import Infractions
from tux.database.controllers import DatabaseController
from tux.utils.embeds import EmbedCreator
from tux.utils.enums import InfractionType
class Timeout(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.db_controller = DatabaseController()
async def insert_infraction(
self,
user_id: int,
moderator_id: int,
infraction_type: InfractionType,
infraction_reason: str,
expires_at: datetime.datetime | None = None,
) -> Infractions | None:
"""
Inserts an infraction into the database.
Parameters
----------
user_id : int
The ID of the user to issue the infraction to.
moderator_id : int
The ID of the moderator issuing the infraction.
infraction_type : InfractionType
The type of infraction to issue.
infraction_reason : str
The reason for issuing the infraction.
expires_at : datetime.datetime | None, optional
The expiration date for the infraction, by default None.
Returns
-------
Infractions | None
The infraction that was created, or None if an error occurred.
"""
return await self.db_controller.infractions.create_infraction(
user_id=user_id,
moderator_id=moderator_id,
infraction_type=infraction_type,
infraction_reason=infraction_reason,
expires_at=expires_at,
)
async def get_or_create_user(self, member: discord.Member) -> None:
"""
Retrieves a user from the database or creates a new user if not found.
Parameters
----------
member : discord.Member
The member to retrieve or create in the database.
"""
user = await self.db_controller.users.get_user_by_id(member.id)
if not user:
await self.db_controller.users.create_user(
user_id=member.id,
name=member.name,
display_name=member.display_name,
mention=member.mention,
bot=member.bot,
created_at=member.created_at,
joined_at=member.joined_at,
)
async def get_or_create_moderator(self, interaction: discord.Interaction) -> None:
"""
Retrieves a moderator from the database or creates a new moderator if not found.
Parameters
----------
interaction : discord.Interaction
The interaction to retrieve or create in the database.
"""
moderator = await self.db_controller.users.get_user_by_id(interaction.user.id)
moderator_context = None
if interaction.guild:
moderator_context = interaction.guild.get_member(interaction.user.id)
if not moderator:
await self.db_controller.users.create_user(
user_id=interaction.user.id,
name=interaction.user.name,
display_name=interaction.user.display_name,
mention=interaction.user.mention,
bot=interaction.user.bot,
created_at=interaction.user.created_at,
joined_at=moderator_context.joined_at if moderator_context else None,
)
@app_commands.checks.has_any_role("Root", "Admin", "Sr. Mod", "Mod")
@app_commands.command(name="timeout", description="Issues a timeout to a member of the server.")
@app_commands.describe(
member="The member to timeout",
reason="The reason for issuing the timeout",
days="Number of days for the timeout",
hours="Number of hours for the timeout",
minutes="Number of minutes for the timeout",
seconds="Number of seconds for the timeout",
)
async def timeout(
self,
interaction: discord.Interaction,
member: discord.Member,
reason: str | None = None,
days: int = 0,
hours: int = 0,
minutes: int = 0,
seconds: int = 0,
) -> None:
"""
Issues a timeout to a member of the server.
Parameters
----------
interaction : discord.Interaction
The interaction that triggered the command.
member : discord.Member
The member to issue the timeout to.
reason : str | None, optional
The reason for issuing the timeout, by default None
days : int, optional
The number of days for the timeout, by default 0
hours : int, optional
The number of hours for the timeout, by default 0
minutes : int, optional
The number of minutes for the timeout, by default 0
seconds : int, optional
The number of seconds for the timeout, by default 0
"""
reason = reason or "No reason provided"
duration = datetime.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
await self.get_or_create_user(member)
await self.get_or_create_moderator(interaction)
try:
await member.timeout(duration, reason=reason)
new_timeout = await self.insert_infraction(
user_id=member.id,
moderator_id=interaction.user.id,
infraction_type=InfractionType.TIMEOUT,
infraction_reason=reason,
expires_at=datetime.datetime.now(UTC) + duration,
)
timeout_id = new_timeout.id if new_timeout else "Unknown"
embed = EmbedCreator.create_infraction_embed(
title="",
description="",
interaction=interaction,
)
embed.add_field(name="Action", value="Timeout", inline=True)
embed.add_field(name="Case ID", value=f"`{timeout_id}`", inline=True)
embed.add_field(name="Reason", value=f"`{reason}`", inline=False)
embed.add_field(name="Moderator", value=f"{interaction.user.display_name}", inline=True)
embed.add_field(name="Member", value=f"{member.display_name}", inline=True)
logger.info(f"Timeout issued to {member.display_name} ({member.id}) for: {reason}")
except Exception as error:
msg = f"Failed to issue timeout to {member.display_name}."
embed = EmbedCreator.create_error_embed(
title="Timeout Failed",
description=msg,
interaction=interaction,
)
logger.error(f"{msg} Error: {error}")
await interaction.response.send_message(embed=embed)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(Timeout(bot))

View file

@ -1,179 +0,0 @@
# utils/tux_logger.py
"""
# TuxLogger Documentation
## Usage Instructions
Hey contributor, Ty here! To use the logger in your cog files, please follow these steps:
1. Import the logger by adding the following line at the top of your main bot file:
```python
from your_module_name import logger
```
2. Once imported, you can use the logger to log messages in your code. For example:
```python
logger.info("This is an information message.")
logger.warning("This is a warning message.")
logger.error("This is an error message.")
logger.debug("This is a debug message.")
```
### Logger setup
```python
async def setup(bot,
project_logging_level=logging.DEBUG,
discord_logging_level=logging.WARNING):
```
1. bot: The Discord bot instance.
1. project_logging_level: The logging level for the project (default is DEBUG).
1. discord_logging_level: The logging level for the Discord library (default is WARNING).
I love you all and thank you for contributing <3
""" # noqa E501
import logging
import os
import colorlog
import discord
from discord.ext import commands
class TuxLogger(logging.Logger):
LOG_DIR = "logs"
def __init__(self, name: str, project_logging_level: int = logging.INFO):
super().__init__(name, level=project_logging_level)
self.setup_logging()
def setup_logging(self):
"""
Setup logging configuration.
"""
log_format = "%(asctime)s [%(log_color)s%(levelname)s%(reset)s] [%(name)s]: %(" "message)s"
os.makedirs(self.LOG_DIR, exist_ok=True)
# Stream handler with color formatting
handler = colorlog.StreamHandler()
handler.setFormatter(colorlog.ColoredFormatter(log_format))
# File handler for general logs
file_name = os.path.join(self.LOG_DIR, "bot.log")
file_handler = self._create_file_handler(file_name)
self.addHandler(handler)
self.addHandler(file_handler)
def _create_file_handler(self, filename: str) -> logging.FileHandler:
"""
Create a file handler.
Args:
filename (str): Filename for the log file.
Returns
logging.FileHandler: A file handler object.
"""
file_handler = logging.FileHandler(filename, mode="a")
file_handler.setFormatter(
logging.Formatter("%(asctime)s [%(levelname)s] [%(name)s]: %(message)s")
)
return file_handler
def _log_to_file(self, level: int, message: str, caller_module: str):
"""
Log to a file.
Args:
level (int): Level of the log.
message (str): Log message.
caller_module (str): Module where the log was triggered.
"""
file_name = os.path.join(self.LOG_DIR, f"{caller_module}.log")
file_handler = self._create_file_handler(file_name)
self.addHandler(file_handler)
self.log(level, message)
self.removeHandler(file_handler)
def debug(self, message, filename="unknown"):
self._log_to_file(logging.DEBUG, message, filename)
def info(self, message, filename="unknown"):
self._log_to_file(logging.INFO, message, filename)
def warning(self, message, filename="unknown"):
self._log_to_file(logging.WARNING, message, filename)
def error(self, message, filename="unknown"):
self._log_to_file(logging.ERROR, message, filename)
def critical(self, message, filename="unknown"):
self._log_to_file(logging.CRITICAL, message, filename)
def audit(
self,
bot: commands.Bot,
title: str,
description: str,
color: int | discord.Colour = 0x7289DA,
fields: list[tuple[str, str, bool]] | None = None,
thumbnail_url: str | None = None,
image_url: str | None = None,
author_name: str | None = None,
author_url: str | None = None,
author_icon_url: str | None = None,
footer_text: str | None = None,
footer_icon_url: str | None = None,
):
audit_log_channel_id = 1191472088695980083
channel = bot.get_channel(audit_log_channel_id)
if not isinstance(channel, discord.TextChannel):
self.error(f"Failed to send audit message: Channel '{channel}' is not a text channel.")
return
embed = discord.Embed(title=title, description=description, color=color)
# Add fields to embed
if fields:
for name, value, inline in fields:
embed.add_field(name=name, value=value, inline=inline)
# Set thumbnail and image
if thumbnail_url:
embed.set_thumbnail(url=thumbnail_url)
if image_url:
embed.set_image(url=image_url)
# Set author details
if author_name:
embed.set_author(name=author_name, url=author_url, icon_url=author_icon_url)
# Set footer details
if footer_text:
embed.set_footer(text=footer_text, icon_url=footer_icon_url)
bot.loop.create_task(channel.send(embed=embed))
class LoggingCog(commands.Cog):
def __init__(self, bot, discord_logging_level=logging.WARNING):
self.bot = bot
discord_logger = logging.getLogger("discord")
discord_logger.setLevel(discord_logging_level)
logger = TuxLogger(__name__)
async def setup(bot, project_logging_level=logging.DEBUG, discord_logging_level=logging.WARNING):
global logger
log_cog = LoggingCog(bot, discord_logging_level)
logger.setLevel(project_logging_level)
await bot.add_cog(log_cog)

View file

@ -1,193 +0,0 @@
import discord
from discord import app_commands
from discord.ext import commands
from loguru import logger
from prisma.models import Infractions
from tux.database.controllers import DatabaseController
from tux.utils.embeds import EmbedCreator
from tux.utils.enums import InfractionType
class Unban(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.db_controller = DatabaseController()
async def insert_infraction(
self,
user_id: int,
moderator_id: int,
infraction_type: InfractionType,
infraction_reason: str,
) -> Infractions | None:
"""
Inserts an infraction into the database.
Parameters
----------
user_id : int
The ID of the user to issue the infraction to.
moderator_id : int
The ID of the moderator issuing the infraction.
infraction_type : InfractionType
The type of infraction to issue.
infraction_reason : str
The reason for issuing the infraction.
Returns
-------
Infractions | None
The infraction that was created, or None if an error occurred.
"""
return await self.db_controller.infractions.create_infraction(
user_id=user_id,
moderator_id=moderator_id,
infraction_type=infraction_type,
infraction_reason=infraction_reason,
)
async def get_or_create_user(self, member: discord.User) -> None:
"""
Retrieves a user from the database or creates a new user if not found.
Parameters
----------
member : discord.User
The user to retrieve or create in the database.
"""
user = await self.db_controller.users.get_user_by_id(member.id)
if not user:
await self.db_controller.users.create_user(
user_id=member.id,
name=member.name,
display_name=member.display_name,
mention=member.mention,
bot=member.bot,
created_at=member.created_at,
joined_at=None,
)
async def get_or_create_moderator(self, interaction: discord.Interaction) -> None:
"""
Retrieves a moderator from the database or creates a new moderator if not found.
Parameters
----------
interaction : discord.Interaction
The interaction that triggered the command.
"""
moderator = await self.db_controller.users.get_user_by_id(interaction.user.id)
moderator_context = None
if interaction.guild:
moderator_context = interaction.guild.get_member(interaction.user.id)
if not moderator:
await self.db_controller.users.create_user(
user_id=interaction.user.id,
name=interaction.user.name,
display_name=interaction.user.display_name,
mention=interaction.user.mention,
bot=interaction.user.bot,
created_at=interaction.user.created_at,
joined_at=moderator_context.joined_at if moderator_context else None,
)
@app_commands.checks.has_any_role("Admin", "Sr. Mod", "Mod", "Jr. Mod")
@app_commands.command(name="unban", description="Unbans a member from the server.")
@app_commands.describe(
username_or_id="The username of the member to unban", reason="Reason for unban"
)
async def unban(
self, interaction: discord.Interaction, username_or_id: str, reason: str | None = None
) -> None:
"""
Unbans a member from the server.
Parameters
----------
interaction : discord.Interaction
The interaction that triggered the command.
username_or_id : str
The username or ID of the member to unban.
reason : str | None, optional
The reason for unbanning the member, by default None
Raises
-------
ValueError
If the user is not found in the ban list.
"""
if interaction.guild is None:
return
# Get the list of banned users in the guild
banned_users = [ban.user async for ban in interaction.guild.bans()]
try:
# If the username_or_id is an integer, search for the user by ID
user_id = int(username_or_id)
user_to_unban = discord.utils.get(banned_users, id=user_id)
except ValueError:
# If the username_or_id is not an integer, search for the user by username
user_to_unban = discord.utils.find(lambda u: u.name == username_or_id, banned_users)
if user_to_unban is None:
await interaction.response.send_message(
"User not found in the ban list. Please provide a valid user ID or username."
)
return
try:
await interaction.guild.unban(user_to_unban, reason=reason)
await self.get_or_create_user(user_to_unban)
await self.get_or_create_moderator(interaction)
new_unban = await self.insert_infraction(
user_id=user_to_unban.id,
moderator_id=interaction.user.id,
infraction_type=InfractionType.UNBAN,
infraction_reason=reason or "No reason provided",
)
unban_id = new_unban.id if new_unban else "Unknown"
embed = EmbedCreator.create_success_embed(
title="Unban",
description=f"Successfully unbanned {user_to_unban.display_name}.",
interaction=interaction,
)
embed.add_field(name="Action", value="Unban", inline=False)
embed.add_field(name="Case ID", value=unban_id, inline=False)
embed.add_field(name="Reason", value=reason or "No reason provided", inline=False)
embed.add_field(name="Moderator", value=interaction.user.mention, inline=False)
embed.add_field(name="User", value=user_to_unban.mention, inline=False)
await interaction.response.send_message(embed=embed)
logger.info(f"User {user_to_unban.display_name} has been unbanned.")
except Exception as error:
msg = f"Failed to unban user {user_to_unban.display_name}."
embed = EmbedCreator.create_error_embed(
title="Unban",
description=msg,
interaction=interaction,
)
logger.error(f"{msg} Error: {error}")
await interaction.response.send_message(embed=embed)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(Unban(bot))

View file

@ -1,162 +0,0 @@
import discord
from discord import app_commands
from discord.ext import commands
from loguru import logger
from prisma.models import Infractions
from tux.database.controllers import DatabaseController
from tux.utils.embeds import EmbedCreator
from tux.utils.enums import InfractionType
class Warn(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.db_controller = DatabaseController()
async def insert_infraction(
self,
user_id: int,
moderator_id: int,
infraction_type: InfractionType,
infraction_reason: str,
) -> Infractions | None:
"""
Inserts an infraction into the database.
Parameters
----------
user_id : int
The ID of the user to issue the infraction to.
moderator_id : int
The ID of the moderator issuing the infraction.
infraction_type : InfractionType
The type of infraction to issue.
infraction_reason : str
The reason for issuing the infraction.
Returns
-------
Infractions | None
The infraction that was created, or None if an error occurred.
"""
return await self.db_controller.infractions.create_infraction(
user_id=user_id,
moderator_id=moderator_id,
infraction_type=infraction_type,
infraction_reason=infraction_reason,
)
async def get_or_create_user(self, member: discord.Member) -> None:
"""
Retrieves a user from the database or creates a new user if not found.
Parameters
----------
member : discord.Member
The member to retrieve or create in the database.
"""
user = await self.db_controller.users.get_user_by_id(member.id)
if not user:
await self.db_controller.users.create_user(
user_id=member.id,
name=member.name,
display_name=member.display_name,
mention=member.mention,
bot=member.bot,
created_at=member.created_at,
joined_at=member.joined_at,
)
async def get_or_create_moderator(self, interaction: discord.Interaction) -> None:
"""
Retrieves a moderator from the database or creates a new moderator if not found.
Parameters
----------
interaction : discord.Interaction
The interaction that triggered the command.
"""
moderator = await self.db_controller.users.get_user_by_id(interaction.user.id)
moderator_context = None
if interaction.guild:
moderator_context = interaction.guild.get_member(interaction.user.id)
if not moderator:
await self.db_controller.users.create_user(
user_id=interaction.user.id,
name=interaction.user.name,
display_name=interaction.user.display_name,
mention=interaction.user.mention,
bot=interaction.user.bot,
created_at=interaction.user.created_at,
joined_at=moderator_context.joined_at if moderator_context else None,
)
@app_commands.checks.has_any_role("Admin", "Sr. Mod", "Mod", "Jr. Mod")
@app_commands.command(name="warn", description="Issues a warning to a member of the server.")
@app_commands.describe(member="The member to warn", reason="The reason for issuing the warning")
async def warn(
self, interaction: discord.Interaction, member: discord.Member, reason: str | None = None
) -> None:
"""
Issues a warning to a member of the server.
Parameters
----------
interaction : discord.Interaction
The interaction that triggered the command.
member : discord.Member
The member to warn.
reason : str | None, optional
The reason for issuing the warning.
"""
reason = reason or "No reason provided"
await self.get_or_create_user(member)
await self.get_or_create_moderator(interaction)
try:
new_warn = await self.insert_infraction(
user_id=member.id,
moderator_id=interaction.user.id,
infraction_type=InfractionType.WARN,
infraction_reason=reason,
)
warn_id = new_warn.id if new_warn else "Unknown"
embed = EmbedCreator.create_infraction_embed(
title="",
description="",
interaction=interaction,
)
embed.add_field(name="Action", value="Warn", inline=True)
embed.add_field(name="Case ID", value=f"`{warn_id}`", inline=True)
embed.add_field(name="Reason", value=f"`{reason}`", inline=False)
embed.add_field(name="Moderator", value=f"{interaction.user.display_name}", inline=True)
logger.info(f"Warning issued to {member.display_name} ({member.id}) for: {reason}")
except Exception as error:
msg = f"Failed to issue warning to {member.display_name}."
embed = EmbedCreator.create_error_embed(
title="Warning Failed",
description=msg,
interaction=interaction,
)
logger.error(f"{msg} Error: {error}")
await interaction.response.send_message(embed=embed)
async def setup(bot: commands.Bot) -> None:
"""Asynchronously adds the Warn cog to the bot."""
await bot.add_cog(Warn(bot))

119
docs/cli.md Normal file
View file

@ -0,0 +1,119 @@
# Project Documentation
This document outlines the essential commands and workflows needed for the installation, development, and management of this project. Each section provides relevant commands and instructions for specific tasks.
## Table of Contents
- [Project Documentation](#project-documentation)
- [Table of Contents](#table-of-contents)
- [Installation](#installation)
- [Development](#development)
- [Docker](#docker)
- [Linting](#linting)
- [Linting and Formatting](#linting-and-formatting)
- [Git](#git)
## Installation
To install necessary dependencies and set up the environment, use the following commands:
```sh
# Install dependencies with Poetry.
poetry install
# Activate the virtual environment.
poetry shell
# Install pre-commit hooks.
poetry pre-commit install
```
## Development
For running the application and executing tests, use these commands:
```sh
# Run the application with Poetry.
poetry run python tux/main.py
```
## Docker
To run the application using Docker, use the following command:
```sh
# Run the application with Docker.
docker compose up --build -d
```
## Linting
Utilize these commands to run all pre-commit hooks or specific ones:
```sh
# Run all pre-commit hooks.
poetry run pre-commit run --all-files
# Run a specific pre-commit hook.
poetry run pre-commit run <hook_id>
```
## Linting and Formatting
Commands for linting and formatting files are as follows:
```sh
# Lint all files in the current directory.
poetry run ruff check
# Lint all files in the current directory and fix any fixable errors.
poetry run ruff check --fix
# Lint all files in the current directory and re-lint on changes.
poetry run ruff check --watch
# Format all files in the current directory.
poetry run ruff format .
```
## Git
Common Git commands for repository management are listed below:
```sh
# Create a new branch.
git checkout -b <branch_name>
# Switch to an existing branch.
git checkout <branch_name>
# Pull changes from the remote repository.
git pull
# Delete a branch.
git branch -d <branch_name>
# Check the status of the repository.
git status
# Show changes between commits, commit and working tree, etc.
git diff
# Show commit logs.
git log
# Show remote repositories.
git remote -v
# Add a remote repository.
git remote add origin <repository_url>
# Add all files to the staging area.
git add .
# Commit changes with a message.
git commit -m "Your commit message"
# Push changes to the remote repository.
git push
```