1
Fork 0
mirror of https://github.com/wlinator/luminara.git synced 2024-10-02 18:23:12 +00:00

Merge pull request #35 from wlinator/optimization

Optimization
This commit is contained in:
wlinator 2024-08-18 12:59:45 +02:00
commit 994959618e
61 changed files with 1028 additions and 990 deletions

View file

@ -17,8 +17,7 @@ jobs:
packages: write
steps:
-
name: Docker meta
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
@ -31,25 +30,21 @@ jobs:
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
-
name: Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Login to Docker Hub
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Login to GHCR
- name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Build and push
- name: Build and push
uses: docker/build-push-action@v6
with:
push: ${{ github.event_name != 'pull_request' }}

View file

@ -16,7 +16,7 @@ repos:
hooks:
# Run the linter.
- id: ruff
args: [--fix]
args: [ --fix ]
# Run the formatter.
- id: ruff-format

View file

@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within

View file

@ -1,6 +1,7 @@
# Contributing to Luminara
Thank you for your interest in contributing to Lumi! We welcome contributions from the community to help improve and expand the bot's functionality. Please follow these guidelines when contributing:
Thank you for your interest in contributing to Lumi! We welcome contributions from the community to help improve and
expand the bot's functionality. Please follow these guidelines when contributing:
## Getting Started
@ -10,35 +11,39 @@ Thank you for your interest in contributing to Lumi! We welcome contributions fr
3. **Set Up Development Environment:**
* **Docker:** To run the bot, use this command to run your newly edited code:
* **Docker:** To run the bot, use this command to run your newly edited code:
```bash
docker compose -f docker-compose.dev.yml up --build
```
```bash
docker compose -f docker-compose.dev.yml up --build
```
* **Poetry:** While developing, it is recommended to install & configure poetry locally:
* **Poetry:** While developing, it is recommended to install & configure poetry locally:
```bash
poetry install
poetry shell
poetry pre-commit install
```
```bash
poetry install
poetry shell
poetry pre-commit install
```
## Making Changes
1. **Create a Branch:** Create a new branch for your changes.
2. **Code Style:** Adhere to the existing code style and formatting conventions.
3. **Strict Typing:** Always use strict typing (e.g., `str`, `int`, `List[str]`) for better code quality and maintainability.
4. **Pre-Commit Checks:** Before committing, run pre-commit checks to ensure your code passes linting and formatting standards.
3. **Strict Typing:** Always use strict typing (e.g., `str`, `int`, `List[str]`) for better code quality and
maintainability.
4. **Pre-Commit Checks:** Before committing, run pre-commit checks to ensure your code passes linting and formatting
standards.
5. **Clear Commit Messages:** Write clear and concise commit messages that describe the changes you made.
## Submitting Changes
1. **Create a Pull Request:** Create a pull request (PR) from your branch to the `main` branch of the original repository.
1. **Create a Pull Request:** Create a pull request (PR) from your branch to the `main` branch of the original
repository.
2. **Review:** Your PR will be reviewed by the Sourcery & Lumi maintainers. Address any feedback or requested changes.
3. **Merge:** Once approved, your PR will be merged into the main branch.
## Additional Notes
* **Documentation:** If you add new functionality or change existing behavior, update or add the docstrings accordingly.
Thank you for your contributions!

View file

@ -9,10 +9,10 @@ import Client
import config.parser
import services.config_service
import services.help_service
from lib.constants import CONST
from services.blacklist_service import BlacklistUserService
from lib.exceptions.LumiExceptions import Blacklisted
from db.database import run_migrations
from lib.constants import CONST
from lib.exceptions.LumiExceptions import Blacklisted
from services.blacklist_service import BlacklistUserService
# Remove the default logger configuration
logger.remove()

View file

@ -2,14 +2,15 @@
![Lumi art](https://git.wlinator.org/assets/img/logo.png)
## Self-Hosting
Self-hosting refers to running Luminara on your own server or computer, rather than using the publicly hosted version. This approach offers the ability to manage your own instance of the bot and give it a custom name and avatar.
Self-hosting refers to running Luminara on your own server or computer, rather than using the publicly hosted version.
This approach offers the ability to manage your own instance of the bot and give it a custom name and avatar.
### Requirements
Before you begin, make sure you have the following installed on your system:
- [Docker](https://docs.docker.com/get-docker/)
- [Docker Compose](https://docs.docker.com/compose/install/)
@ -25,7 +26,8 @@ Additionally, you'll need to create a Discord bot application and obtain a token
### Running Luminara:
1. Copy the contents from [`docker-compose.prod.yml`](docker-compose.prod.yml) to a new file named `docker-compose.yml` in an empty directory.
1. Copy the contents from [`docker-compose.prod.yml`](docker-compose.prod.yml) to a new file named `docker-compose.yml`
in an empty directory.
2. Copy the contents from [`.env.example`](.env.example) to a new file named `.env` in the same directory.

View file

@ -5,9 +5,9 @@
Versions currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 2.x | :white_check_mark: |
| 1.x | :x: |
|---------|--------------------|
| 2.x | :white_check_mark: |
| 1.x | :x: |
| < 1.0 | :x: |
## Reporting a Vulnerability

View file

@ -1,10 +1,11 @@
import mysql.connector
from loguru import logger
from mysql.connector import pooling
import os
import pathlib
import re
import mysql.connector
from loguru import logger
from mysql.connector import pooling
from lib.constants import CONST

View file

@ -1,4 +1,5 @@
import contextlib
from discord import Message
from discord.ext.commands import Cog
from loguru import logger
@ -76,7 +77,7 @@ class ReactionListener(Cog):
:param message: The message to process.
"""
if not message.author.bot and not BlacklistUserService.is_user_blacklisted(
message.author.id,
message.author.id,
):
await ReactionHandler(self.client, message).run_checks()

View file

@ -103,9 +103,9 @@ class XPHandler:
if role := self.guild.get_role(role_id):
with contextlib.suppress(
discord.Forbidden,
discord.NotFound,
discord.HTTPException,
discord.Forbidden,
discord.NotFound,
discord.HTTPException,
):
if isinstance(self.author, discord.Member):
await self.author.add_roles(role, reason=reason)
@ -114,16 +114,16 @@ class XPHandler:
if replace and isinstance(self.author, discord.Member):
if role := self.guild.get_role(previous or role_id):
with contextlib.suppress(
discord.Forbidden,
discord.NotFound,
discord.HTTPException,
discord.Forbidden,
discord.NotFound,
discord.HTTPException,
):
await self.author.remove_roles(role, reason=reason)
async def get_level_channel(
self,
message: discord.Message,
guild_config: GuildConfig,
self,
message: discord.Message,
guild_config: GuildConfig,
) -> Optional[discord.TextChannel]:
"""
Retrieves the level up notification channel for the guild.
@ -147,9 +147,9 @@ class XPHandler:
@staticmethod
async def get_level_message(
guild_config: GuildConfig,
level_config: XpService,
author: discord.Member,
guild_config: GuildConfig,
level_config: XpService,
author: discord.Member,
) -> Optional[str]:
"""
Retrieves the level up message for the user.

View file

@ -8,22 +8,22 @@ from lib.constants import CONST
class EmbedBuilder:
@staticmethod
def create_embed(
ctx,
title=None,
author_text=None,
author_icon_url=None,
author_url=None,
description=None,
color=None,
footer_text=None,
footer_icon_url=None,
show_name=True,
image_url=None,
thumbnail_url=None,
timestamp=None,
hide_author=False,
hide_author_icon=False,
hide_timestamp=False,
ctx,
title=None,
author_text=None,
author_icon_url=None,
author_url=None,
description=None,
color=None,
footer_text=None,
footer_icon_url=None,
show_name=True,
image_url=None,
thumbnail_url=None,
timestamp=None,
hide_author=False,
hide_author_icon=False,
hide_timestamp=False,
):
if not hide_author:
if not author_text:
@ -63,20 +63,20 @@ class EmbedBuilder:
@staticmethod
def create_error_embed(
ctx,
title=None,
author_text=None,
author_icon_url=None,
author_url=None,
description=None,
footer_text=None,
show_name=True,
image_url=None,
thumbnail_url=None,
timestamp=None,
hide_author=False,
hide_author_icon=False,
hide_timestamp=False,
ctx,
title=None,
author_text=None,
author_icon_url=None,
author_url=None,
description=None,
footer_text=None,
show_name=True,
image_url=None,
thumbnail_url=None,
timestamp=None,
hide_author=False,
hide_author_icon=False,
hide_timestamp=False,
):
return EmbedBuilder.create_embed(
ctx,
@ -99,20 +99,20 @@ class EmbedBuilder:
@staticmethod
def create_success_embed(
ctx,
title=None,
author_text=None,
author_icon_url=None,
author_url=None,
description=None,
footer_text=None,
show_name=True,
image_url=None,
thumbnail_url=None,
timestamp=None,
hide_author=False,
hide_author_icon=False,
hide_timestamp=False,
ctx,
title=None,
author_text=None,
author_icon_url=None,
author_url=None,
description=None,
footer_text=None,
show_name=True,
image_url=None,
thumbnail_url=None,
timestamp=None,
hide_author=False,
hide_author_icon=False,
hide_timestamp=False,
):
return EmbedBuilder.create_embed(
ctx,
@ -135,20 +135,20 @@ class EmbedBuilder:
@staticmethod
def create_info_embed(
ctx,
title=None,
author_text=None,
author_icon_url=None,
author_url=None,
description=None,
footer_text=None,
show_name=True,
image_url=None,
thumbnail_url=None,
timestamp=None,
hide_author=False,
hide_author_icon=False,
hide_timestamp=False,
ctx,
title=None,
author_text=None,
author_icon_url=None,
author_url=None,
description=None,
footer_text=None,
show_name=True,
image_url=None,
thumbnail_url=None,
timestamp=None,
hide_author=False,
hide_author_icon=False,
hide_timestamp=False,
):
return EmbedBuilder.create_embed(
ctx,
@ -171,20 +171,20 @@ class EmbedBuilder:
@staticmethod
def create_warning_embed(
ctx,
title=None,
author_text=None,
author_icon_url=None,
author_url=None,
description=None,
footer_text=None,
show_name=True,
image_url=None,
thumbnail_url=None,
timestamp=None,
hide_author=False,
hide_author_icon=False,
hide_timestamp=False,
ctx,
title=None,
author_text=None,
author_icon_url=None,
author_url=None,
description=None,
footer_text=None,
show_name=True,
image_url=None,
thumbnail_url=None,
timestamp=None,
hide_author=False,
hide_author_icon=False,
hide_timestamp=False,
):
return EmbedBuilder.create_embed(
ctx,

View file

@ -1,4 +1,5 @@
from discord.ext import commands
from lib.constants import CONST

View file

@ -3,9 +3,9 @@ import textwrap
import discord
from discord.ext import commands
from pytimeparse import parse
from lib.exceptions.LumiExceptions import LumiException
from lib.constants import CONST
from lib.constants import CONST
from lib.exceptions.LumiExceptions import LumiException
from services.config_service import GuildConfig

View file

@ -51,9 +51,9 @@ class IntroductionFinishButtons(View):
@discord.ui.button(label="Post it!", style=discord.ButtonStyle.green)
async def short_button_callback(
self,
button: discord.ui.Button,
interaction: discord.Interaction,
self,
button: discord.ui.Button,
interaction: discord.Interaction,
) -> None:
await interaction.response.edit_message(view=None)
self.clickedConfirm = True
@ -61,9 +61,9 @@ class IntroductionFinishButtons(View):
@discord.ui.button(label="Stop", style=discord.ButtonStyle.red)
async def extended_button_callback(
self,
button: discord.ui.Button,
interaction: discord.Interaction,
self,
button: discord.ui.Button,
interaction: discord.Interaction,
) -> None:
await interaction.response.edit_message(view=None)
self.stop()

View file

@ -30,7 +30,7 @@ class ReactionHandler:
content = message.content.lower()
if (
content.startswith("Lumi ") or content.startswith("Lumi, ")
content.startswith("Lumi ") or content.startswith("Lumi, ")
) and content.endswith("?"):
response = random.choice(self.eightball)
await message.reply(content=response)

View file

@ -1,4 +1,5 @@
import discord
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from services.currency_service import Currency

View file

@ -1,15 +1,16 @@
from typing import Optional
import discord
from lib.constants import CONST
from services.blacklist_service import BlacklistUserService
from lib.embed_builder import EmbedBuilder
from services.blacklist_service import BlacklistUserService
async def blacklist_user(
ctx,
user: discord.User,
reason: Optional[str] = None,
ctx,
user: discord.User,
reason: Optional[str] = None,
) -> None:
blacklist_service = BlacklistUserService(user.id)
blacklist_service.add_to_blacklist(reason)

View file

@ -1,10 +1,10 @@
import mysql.connector
from db import database
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from lib.formatter import shorten
from db import database
async def select_cmd(ctx, query: str):
if query.lower().startswith("select "):

View file

@ -1,7 +1,8 @@
import discord
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from lib.exceptions.LumiExceptions import LumiException
from lib.constants import CONST
async def sync_commands(client, ctx):

View file

@ -1,9 +1,10 @@
import datetime
import pytz
import discord
import pytz
from discord.commands import SlashCommandGroup
from discord.ext import commands, tasks
from lib import checks
from lib.constants import CONST
from modules.birthdays import birthday, daily_check

View file

@ -4,8 +4,8 @@ import datetime
import discord
from discord.ext import commands
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from services.birthday_service import Birthday

View file

@ -1,10 +1,12 @@
import asyncio
import random
from loguru import logger
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from services.birthday_service import Birthday
from services.config_service import GuildConfig
from lib.embed_builder import EmbedBuilder
async def daily_birthday_check(client):

View file

@ -1,7 +1,8 @@
import discord
from discord.ext.commands import guild_only
from discord.commands import SlashCommandGroup
from discord.ext import bridge, commands
from discord.ext.commands import guild_only
from modules.config import (
c_birthday,
c_boost,
@ -38,11 +39,11 @@ class Config(commands.Cog):
@guild_only()
@commands.has_permissions(manage_roles=True)
async def xp_reward_command_add(
self,
ctx,
level: int,
role: discord.Role,
persistent: bool = False,
self,
ctx,
level: int,
role: discord.Role,
persistent: bool = False,
):
await xp_reward.add_reward(ctx, level, role.id, persistent)

View file

@ -1,6 +1,7 @@
import discord
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from services.config_service import GuildConfig

View file

@ -1,9 +1,10 @@
import discord
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from services.config_service import GuildConfig
from lib.exceptions.LumiExceptions import LumiException
import lib.formatter
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from lib.exceptions.LumiExceptions import LumiException
from services.config_service import GuildConfig
async def set_boost_channel(ctx, channel: discord.TextChannel):
@ -103,9 +104,9 @@ async def set_boost_image(ctx, image_url: str | None):
async def create_boost_embed(
member: discord.Member,
template: str | None = None,
image_url: str | None = None,
member: discord.Member,
template: str | None = None,
image_url: str | None = None,
):
embed = discord.Embed(
color=discord.Color.nitro_pink(),

View file

@ -77,8 +77,8 @@ async def set_welcome_template(ctx, text: str) -> None:
def create_greet_embed(
member: discord.Member,
template: Optional[str] = None,
member: discord.Member,
template: Optional[str] = None,
) -> discord.Embed:
embed: discord.Embed = discord.Embed(
color=discord.Color.embed_background(),

View file

@ -1,8 +1,9 @@
import discord
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from services.config_service import GuildConfig
from lib import formatter
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from services.config_service import GuildConfig
async def set_level_channel(ctx, channel: discord.TextChannel):

View file

@ -1,8 +1,9 @@
import discord
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from services.moderation.modlog_service import ModLogService
from lib.embed_builder import EmbedBuilder
from lib.exceptions.LumiExceptions import LumiException
from services.moderation.modlog_service import ModLogService
async def set_mod_log_channel(ctx, channel: discord.TextChannel):

View file

@ -1,5 +1,5 @@
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from services.config_service import GuildConfig

View file

@ -1,8 +1,10 @@
import discord
from typing import List, Tuple, Optional
import discord
from discord import Guild
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from services.config_service import GuildConfig
from services.moderation.modlog_service import ModLogService

View file

@ -1,7 +1,7 @@
import discord
from services.xp_service import XpRewardService
from lib.constants import CONST
from services.xp_service import XpRewardService
async def show(ctx):

View file

@ -1,6 +1,7 @@
import discord
from discord.ext.commands import guild_only
from discord.ext import bridge, commands
from discord.ext.commands import guild_only
from modules.economy import balance, blackjack, daily, give, slots
@ -13,7 +14,7 @@ class Economy(commands.Cog):
aliases=["bal", "$"],
description="Shows your current Lumi balance.",
help="Shows your current Lumi balance. The economy system is global, meaning your balance will be synced in "
"all servers.",
"all servers.",
contexts={discord.InteractionContextType.guild},
)
@guild_only()

View file

@ -7,10 +7,10 @@ from discord.ext import commands
from loguru import logger
from lib import interaction
from lib.constants import CONST
from lib.exceptions.LumiExceptions import LumiException
from services.currency_service import Currency
from services.stats_service import BlackJackStats
from lib.exceptions.LumiExceptions import LumiException
from lib.constants import CONST
est = pytz.timezone("US/Eastern")
active_blackjack_games = {}
@ -178,12 +178,12 @@ async def cmd(ctx, bet: int):
def blackjack_show(
ctx,
bet,
player_hand,
dealer_hand,
player_hand_value,
dealer_hand_value,
ctx,
bet,
player_hand,
dealer_hand,
player_hand_value,
dealer_hand_value,
):
current_time = datetime.now(est).strftime("%I:%M %p")
embed = discord.Embed(

View file

@ -7,11 +7,10 @@ import discord
import pytz
from discord.ext import commands
from lib.constants import CONST
from services.currency_service import Currency
from services.stats_service import SlotsStats
from lib.constants import CONST
est = pytz.timezone("US/Eastern")

View file

@ -1,6 +1,6 @@
import discord
from discord.ext.commands import guild_only
from discord.ext import bridge, commands
from discord.ext.commands import guild_only
from modules.levels import leaderboard, level

View file

@ -132,8 +132,8 @@ class LeaderboardCommandView(discord.ui.View):
embed.set_author(name=CONST.STRINGS["xp_lb_author"], icon_url=icon)
for rank, (user_id, xp, level, xp_needed_for_next_level) in enumerate(
xp_lb[:5],
start=1,
xp_lb[:5],
start=1,
):
try:
member = await self.ctx.guild.fetch_member(user_id)

View file

@ -1,9 +1,9 @@
from datetime import datetime
import discord
from discord.ext.commands import guild_only
from discord.commands import SlashCommandGroup
from discord.ext import bridge, commands, tasks
from discord.ext.commands import guild_only
from Client import LumiBot
from modules.config import c_prefix
@ -99,7 +99,7 @@ class Misc(commands.Cog):
aliases=["intro", "introduce"],
description="This command can only be used in DMs.",
help="Introduce yourself. For now this command "
"can only be done in ONE server and only in Lumi's DMs.",
"can only be done in ONE server and only in Lumi's DMs.",
contexts={discord.InteractionContextType.bot_dm},
)
@commands.dm_only()

View file

@ -35,8 +35,8 @@ async def cmd(self, ctx: bridge.Context) -> None:
)
if not channel or isinstance(
channel,
(discord.ForumChannel, discord.CategoryChannel),
channel,
(discord.ForumChannel, discord.CategoryChannel),
):
await ctx.respond(
embed=EmbedBuilder.create_error_embed(

View file

@ -10,9 +10,9 @@ _xkcd = Client()
async def print_comic(
ctx: bridge.Context,
latest: bool = False,
number: Optional[int] = None,
ctx: bridge.Context,
latest: bool = False,
number: Optional[int] = None,
) -> None:
try:
if latest:

View file

@ -20,11 +20,11 @@ class Moderation(commands.Cog):
@commands.bot_has_permissions(ban_members=True)
@guild_only()
async def ban_command(
self,
ctx,
target: discord.User,
*,
reason: str | None = None,
self,
ctx,
target: discord.User,
*,
reason: str | None = None,
):
await ban.ban_user(self, ctx, target, reason)
@ -75,11 +75,11 @@ class Moderation(commands.Cog):
@commands.bot_has_permissions(kick_members=True)
@guild_only()
async def kick_command(
self,
ctx,
target: discord.Member,
*,
reason: str | None = None,
self,
ctx,
target: discord.Member,
*,
reason: str | None = None,
):
await kick.kick_user(self, ctx, target, reason)
@ -106,11 +106,11 @@ class Moderation(commands.Cog):
@commands.bot_has_permissions(ban_members=True)
@guild_only()
async def softban_command(
self,
ctx,
target: discord.Member,
*,
reason: str | None = None,
self,
ctx,
target: discord.Member,
*,
reason: str | None = None,
):
await softban.softban_user(ctx, target, reason)
@ -125,12 +125,12 @@ class Moderation(commands.Cog):
@commands.bot_has_permissions(moderate_members=True)
@guild_only()
async def timeout_command(
self,
ctx,
target: discord.Member,
duration: str,
*,
reason: str | None = None,
self,
ctx,
target: discord.Member,
duration: str,
*,
reason: str | None = None,
):
await timeout.timeout_user(self, ctx, target, duration, reason)
@ -145,11 +145,11 @@ class Moderation(commands.Cog):
@commands.bot_has_permissions(ban_members=True)
@guild_only()
async def unban_command(
self,
ctx,
target: discord.User,
*,
reason: str | None = None,
self,
ctx,
target: discord.User,
*,
reason: str | None = None,
):
await ban.unban_user(ctx, target, reason)
@ -164,11 +164,11 @@ class Moderation(commands.Cog):
@commands.bot_has_permissions(moderate_members=True)
@guild_only()
async def untimeout_command(
self,
ctx,
target: discord.Member,
*,
reason: str | None = None,
self,
ctx,
target: discord.Member,
*,
reason: str | None = None,
):
await timeout.untimeout_user(ctx, target, reason)
@ -182,11 +182,11 @@ class Moderation(commands.Cog):
@bridge.has_permissions(kick_members=True)
@guild_only()
async def warn_command(
self,
ctx,
target: discord.Member,
*,
reason: str | None = None,
self,
ctx,
target: discord.Member,
*,
reason: str | None = None,
):
await warn.warn_user(ctx, target, reason)

View file

@ -1,13 +1,14 @@
import asyncio
from typing import Optional
import discord
from discord.ext.commands import MemberConverter
from lib import formatter
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from modules.moderation.utils.actionable import async_actionable
from modules.moderation.utils.case_handler import create_case
from typing import Optional
from discord.ext.commands import MemberConverter
async def ban_user(cog, ctx, target: discord.User, reason: Optional[str] = None):

View file

@ -1,16 +1,18 @@
import asyncio
import discord
from discord.ext import pages
from discord.ext.commands import UserConverter
from services.moderation.case_service import CaseService
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from lib.formatter import format_case_number
from modules.moderation.utils.case_embed import (
create_case_embed,
create_case_list_embed,
)
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from discord.ext import pages
from lib.formatter import format_case_number
from modules.moderation.utils.case_handler import edit_case_modlog
from services.moderation.case_service import CaseService
case_service = CaseService()
@ -52,7 +54,7 @@ async def view_all_cases_in_guild(ctx, guild_id: int):
pages_list = []
for i in range(0, len(cases), 10):
chunk = cases[i : i + 10]
chunk = cases[i: i + 10]
embed = create_case_list_embed(
ctx,
chunk,
@ -77,7 +79,7 @@ async def view_all_cases_by_mod(ctx, guild_id: int, moderator: discord.Member):
pages_list = []
for i in range(0, len(cases), 10):
chunk = cases[i : i + 10]
chunk = cases[i: i + 10]
embed = create_case_list_embed(
ctx,
chunk,

View file

@ -1,13 +1,14 @@
import asyncio
from typing import Optional
import discord
from discord.ext.commands import UserConverter, MemberConverter
from lib import formatter
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from modules.moderation.utils.actionable import async_actionable
from modules.moderation.utils.case_handler import create_case
from typing import Optional
from discord.ext.commands import UserConverter, MemberConverter
async def kick_user(cog, ctx, target: discord.Member, reason: Optional[str] = None):

View file

@ -1,7 +1,9 @@
import asyncio
import discord
from typing import Optional
import discord
from discord.ext.commands import MemberConverter, UserConverter
from lib import formatter
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder

View file

@ -1,23 +1,24 @@
import asyncio
import discord
import datetime
from typing import Optional
import discord
from discord.ext.commands import UserConverter, MemberConverter
from lib import formatter
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from lib.formatter import format_duration_to_seconds, format_seconds_to_duration_string
from modules.moderation.utils.actionable import async_actionable
from modules.moderation.utils.case_handler import create_case
from typing import Optional
from discord.ext.commands import UserConverter, MemberConverter
from lib.formatter import format_duration_to_seconds, format_seconds_to_duration_string
async def timeout_user(
cog,
ctx,
target: discord.Member,
duration: str,
reason: Optional[str] = None,
cog,
ctx,
target: discord.Member,
duration: str,
reason: Optional[str] = None,
):
bot_member = await MemberConverter().convert(ctx, str(ctx.bot.user.id))
await async_actionable(target, ctx.author, bot_member)

View file

@ -1,12 +1,13 @@
import discord
from lib.exceptions.LumiExceptions import LumiException
from lib.constants import CONST
from lib.exceptions.LumiExceptions import LumiException
async def async_actionable(
target: discord.Member,
invoker: discord.Member,
bot_user: discord.Member,
target: discord.Member,
invoker: discord.Member,
bot_user: discord.Member,
) -> None:
"""
Checks if the invoker and client have a higher role than the target user.

View file

@ -1,20 +1,22 @@
import discord
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from lib.formatter import format_case_number
from typing import Optional
import datetime
from typing import Optional
import discord
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from lib.formatter import format_case_number
from lib.formatter import format_seconds_to_duration_string
def create_case_embed(
ctx,
target: discord.User,
case_number: int,
action_type: str,
reason: Optional[str],
timestamp: Optional[datetime.datetime] = None,
duration: Optional[int] = None,
ctx,
target: discord.User,
case_number: int,
action_type: str,
reason: Optional[str],
timestamp: Optional[datetime.datetime] = None,
duration: Optional[int] = None,
) -> discord.Embed:
embed = EmbedBuilder.create_warning_embed(
ctx,

View file

@ -1,22 +1,24 @@
from typing import Optional
import discord
from discord.ext.commands import TextChannelConverter, UserConverter
from loguru import logger
from modules.moderation.utils.case_embed import create_case_embed
from services.moderation.case_service import CaseService
from services.moderation.modlog_service import ModLogService
from modules.moderation.utils.case_embed import create_case_embed
from typing import Optional
from discord.ext.commands import TextChannelConverter, UserConverter
case_service = CaseService()
modlog_service = ModLogService()
async def create_case(
ctx,
target: discord.User,
action_type: str,
reason: Optional[str] = None,
duration: Optional[int] = None,
expires_at: Optional[str] = None,
ctx,
target: discord.User,
action_type: str,
reason: Optional[str] = None,
duration: Optional[int] = None,
expires_at: Optional[str] = None,
):
"""
Creates a new moderation case and logs it to the modlog channel if configured.
@ -88,10 +90,10 @@ async def create_case(
async def edit_case_modlog(
ctx,
guild_id: int,
case_number: int,
new_reason: str,
ctx,
guild_id: int,
case_number: int,
new_reason: str,
) -> bool:
"""
Edits the reason for an existing case and updates the modlog message if it exists.

View file

@ -1,11 +1,13 @@
import discord
from typing import Optional
from discord.ext.commands import UserConverter, MemberConverter
import asyncio
from lib.embed_builder import EmbedBuilder
from typing import Optional
import discord
from discord.ext.commands import UserConverter, MemberConverter
from lib.constants import CONST
from modules.moderation.utils.case_handler import create_case
from lib.embed_builder import EmbedBuilder
from modules.moderation.utils.actionable import async_actionable
from modules.moderation.utils.case_handler import create_case
async def warn_user(ctx, target: discord.Member, reason: Optional[str]):

View file

@ -1,7 +1,7 @@
import discord
from discord.ext.commands import guild_only
from discord.commands import SlashCommandGroup
from discord.ext import commands
from discord.ext.commands import guild_only
from Client import LumiBot
from modules.triggers.add import add_reaction
@ -28,11 +28,11 @@ class Triggers(commands.Cog):
)
@guild_only()
async def add_text_reaction_command(
self,
ctx,
trigger_text: str,
response: str,
is_full_match: bool,
self,
ctx,
trigger_text: str,
response: str,
is_full_match: bool,
):
await add_reaction(ctx, trigger_text, response, None, False, is_full_match)
@ -43,11 +43,11 @@ class Triggers(commands.Cog):
)
@guild_only()
async def add_emoji_reaction_command(
self,
ctx,
trigger_text: str,
emoji: discord.Emoji,
is_full_match: bool,
self,
ctx,
trigger_text: str,
emoji: discord.Emoji,
is_full_match: bool,
):
await add_reaction(ctx, trigger_text, None, emoji.id, True, is_full_match)
@ -58,9 +58,9 @@ class Triggers(commands.Cog):
)
@guild_only()
async def delete_reaction_command(
self,
ctx,
reaction_id: int,
self,
ctx,
reaction_id: int,
):
await delete_reaction(ctx, reaction_id)
@ -71,8 +71,8 @@ class Triggers(commands.Cog):
)
@guild_only()
async def list_reactions_command(
self,
ctx,
self,
ctx,
):
await list_reactions(ctx)

View file

@ -1,20 +1,21 @@
from typing import Optional
from discord.ext import bridge
from services.reactions_service import CustomReactionsService
from lib.exceptions.LumiExceptions import LumiException
from lib import formatter
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from lib import formatter
from lib.exceptions.LumiExceptions import LumiException
from services.reactions_service import CustomReactionsService
async def add_reaction(
ctx: bridge.Context,
trigger_text: str,
response: Optional[str],
emoji_id: Optional[int],
is_emoji: bool,
is_full_match: bool,
ctx: bridge.Context,
trigger_text: str,
response: Optional[str],
emoji_id: Optional[int],
is_emoji: bool,
is_full_match: bool,
) -> None:
if ctx.guild is None:
return
@ -24,15 +25,15 @@ async def add_reaction(
creator_id: int = ctx.author.id
if not await check_reaction_limit(
reaction_service,
guild_id,
reaction_service,
guild_id,
):
return
if not await check_existing_trigger(
reaction_service,
guild_id,
trigger_text,
reaction_service,
guild_id,
trigger_text,
):
return
@ -82,8 +83,8 @@ async def add_reaction(
async def check_reaction_limit(
reaction_service: CustomReactionsService,
guild_id: int,
reaction_service: CustomReactionsService,
guild_id: int,
) -> bool:
limit_reached = await reaction_service.count_custom_reactions(guild_id) >= 100
@ -94,9 +95,9 @@ async def check_reaction_limit(
async def check_existing_trigger(
reaction_service: CustomReactionsService,
guild_id: int,
trigger_text: str,
reaction_service: CustomReactionsService,
guild_id: int,
trigger_text: str,
) -> bool:
existing_trigger = await reaction_service.find_trigger(guild_id, trigger_text)

View file

@ -1,8 +1,9 @@
from discord.ext import bridge
from services.reactions_service import CustomReactionsService
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from lib.exceptions.LumiExceptions import LumiException
from services.reactions_service import CustomReactionsService
async def delete_reaction(ctx: bridge.Context, reaction_id: int) -> None:

View file

@ -1,11 +1,12 @@
from typing import Any, Dict, List
import discord
from discord.ext import bridge, pages
from lib import formatter
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from services.reactions_service import CustomReactionsService
from typing import Any, Dict, List
from lib import formatter
import discord
async def list_reactions(ctx: bridge.Context) -> None:

1210
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@ from datetime import datetime, timedelta
from typing import List, Optional, Tuple
import pytz
from db import database
from lib.constants import CONST
from services.currency_service import Currency
@ -68,14 +69,14 @@ class Dailies:
"""
check_1: bool = (
self.claimed_at.date() == (self.time_now - timedelta(days=1)).date()
self.claimed_at.date() == (self.time_now - timedelta(days=1)).date()
)
check_2: bool = (
self.claimed_at.date() == (self.time_now - timedelta(days=2)).date()
self.claimed_at.date() == (self.time_now - timedelta(days=2)).date()
)
check_3: bool = (
self.claimed_at.date() == self.time_now.date()
and self.claimed_at < self.reset_time
self.claimed_at.date() == self.time_now.date()
and self.claimed_at < self.reset_time
)
return check_1 or check_2 or check_3

View file

@ -1,8 +1,8 @@
import discord
from discord.ext import commands
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
from lib.exceptions.LumiExceptions import LumiException

View file

@ -1,21 +1,22 @@
from db.database import execute_query, select_query_one, select_query_dict
from typing import Optional, Dict, Any, List
from db.database import execute_query, select_query_one, select_query_dict
class CaseService:
def __init__(self):
pass
def create_case(
self,
guild_id: int,
target_id: int,
moderator_id: int,
action_type: str,
reason: Optional[str] = None,
duration: Optional[int] = None,
expires_at: Optional[str] = None,
modlog_message_id: Optional[int] = None,
self,
guild_id: int,
target_id: int,
moderator_id: int,
action_type: str,
reason: Optional[str] = None,
duration: Optional[int] = None,
expires_at: Optional[str] = None,
modlog_message_id: Optional[int] = None,
) -> int:
# Get the next case number for the guild
query: str = """
@ -62,10 +63,10 @@ class CaseService:
execute_query(query, (guild_id, case_number))
def edit_case_reason(
self,
guild_id: int,
case_number: int,
new_reason: Optional[str] = None,
self,
guild_id: int,
case_number: int,
new_reason: Optional[str] = None,
) -> bool:
query = """
UPDATE cases
@ -102,9 +103,9 @@ class CaseService:
return result[0] if result else None
def fetch_case_by_guild_and_number(
self,
guild_id: int,
case_number: int,
self,
guild_id: int,
case_number: int,
) -> Optional[Dict[str, Any]]:
query: str = """
SELECT * FROM cases
@ -125,9 +126,9 @@ class CaseService:
return results
def fetch_cases_by_target(
self,
guild_id: int,
target_id: int,
self,
guild_id: int,
target_id: int,
) -> List[Dict[str, Any]]:
query: str = """
SELECT * FROM cases
@ -138,9 +139,9 @@ class CaseService:
return results
def fetch_cases_by_moderator(
self,
guild_id: int,
moderator_id: int,
self,
guild_id: int,
moderator_id: int,
) -> List[Dict[str, Any]]:
query: str = """
SELECT * FROM cases
@ -154,9 +155,9 @@ class CaseService:
return results
def fetch_cases_by_action_type(
self,
guild_id: int,
action_type: str,
self,
guild_id: int,
action_type: str,
) -> List[Dict[str, Any]]:
query: str = """
SELECT * FROM cases

View file

@ -1,6 +1,7 @@
from db.database import execute_query, select_query_one
from typing import Optional
from db.database import execute_query, select_query_one
class ModLogService:
def __init__(self):

View file

@ -9,9 +9,9 @@ class CustomReactionsService:
pass
async def find_trigger(
self,
guild_id: int,
message_content: str,
self,
guild_id: int,
message_content: str,
) -> Optional[Dict[str, Any]]:
message_content = message_content.lower()
query = """
@ -24,8 +24,8 @@ class CustomReactionsService:
LIMIT 1
"""
if result := database.select_query(
query,
(guild_id, message_content, message_content, guild_id),
query,
(guild_id, message_content, message_content, guild_id),
):
reaction = result[0] # Get the first result from the list
return {
@ -96,15 +96,15 @@ class CustomReactionsService:
]
async def create_custom_reaction(
self,
guild_id: int,
creator_id: int,
trigger_text: str,
response: Optional[str] = None,
emoji_id: Optional[int] = None,
is_emoji: bool = False,
is_full_match: bool = False,
is_global: bool = True,
self,
guild_id: int,
creator_id: int,
trigger_text: str,
response: Optional[str] = None,
emoji_id: Optional[int] = None,
is_emoji: bool = False,
is_full_match: bool = False,
is_global: bool = True,
) -> bool:
if await self.count_custom_reactions(guild_id) >= 100:
return False
@ -130,13 +130,13 @@ class CustomReactionsService:
return True
async def edit_custom_reaction(
self,
reaction_id: int,
new_response: Optional[str] = None,
new_emoji_id: Optional[int] = None,
is_emoji: Optional[bool] = None,
is_full_match: Optional[bool] = None,
is_global: Optional[bool] = None,
self,
reaction_id: int,
new_response: Optional[str] = None,
new_emoji_id: Optional[int] = None,
is_emoji: Optional[bool] = None,
is_full_match: Optional[bool] = None,
is_global: Optional[bool] = None,
) -> bool:
query = """
UPDATE custom_reactions

View file

@ -30,11 +30,11 @@ class Comic:
"""
def __init__(
self,
xkcd_dict: dict[str, Any],
raw_image: bytes | None = None,
comic_url: str | None = None,
explanation_url: str | None = None,
self,
xkcd_dict: dict[str, Any],
raw_image: bytes | None = None,
comic_url: str | None = None,
explanation_url: str | None = None,
) -> None:
self.id: int | None = xkcd_dict.get("num")
self.date: datetime.date | None = self._determine_date(xkcd_dict)
@ -104,9 +104,9 @@ class Comic:
class Client:
def __init__(
self,
api_url: str = "https://xkcd.com",
explanation_wiki_url: str = "https://www.explainxkcd.com/wiki/index.php/",
self,
api_url: str = "https://xkcd.com",
explanation_wiki_url: str = "https://www.explainxkcd.com/wiki/index.php/",
) -> None:
self._api_url = api_url
self._explanation_wiki_url = explanation_wiki_url

View file

@ -132,9 +132,9 @@ class XpService:
@staticmethod
def generate_progress_bar(
current_value: int,
target_value: int,
bar_length: int = 10,
current_value: int,
target_value: int,
bar_length: int = 10,
) -> str:
"""
Generates an XP progress bar based on the current level and XP.