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:
parent
e8b041fae8
commit
edefd3a1df
18 changed files with 119 additions and 2072 deletions
|
@ -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.
|
167
.archive/ban.py
167
.archive/ban.py
|
@ -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))
|
|
@ -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))
|
|
@ -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
|
|
@ -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))
|
|
@ -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 }}
|
352
.archive/ghub.py
352
.archive/ghub.py
|
@ -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))
|
|
@ -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()
|
|
@ -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))
|
265
.archive/kick.py
265
.archive/kick.py
|
@ -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))
|
|
@ -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"]
|
|
@ -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))
|
|
@ -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
|
|
@ -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))
|
|
@ -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)
|
|
@ -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))
|
162
.archive/warn.py
162
.archive/warn.py
|
@ -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
119
docs/cli.md
Normal 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
|
||||
```
|
Loading…
Reference in a new issue