Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ jobs:
- name: Poetry Config
run: poetry config virtualenvs.in-project true

- uses: actions/cache@v2
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libjpeg-dev zlib1g-dev

- uses: actions/cache@v4
with:
path: .venv
key: poetry-${{ hashFiles('**/poetry.lock') }}
Expand All @@ -50,3 +53,6 @@ jobs:

- name: Type-check (as warnings only)
run: poetry run python -m mypy . || true

- name: Run tests
run: poetry run pytest -q
6 changes: 6 additions & 0 deletions bot/bot_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@ async def load_all_extensions(self):

self.disabled_commands()

try:
synced = await self.tree.sync()
print(f"- Synced {len(synced)} application command(s).")
except Exception as e:
print(f"Failed to sync application commands: {e}")

return errored

async def reload_all_extensions(self):
Expand Down
28 changes: 19 additions & 9 deletions bot/cogs/amigosecreto.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,17 @@ async def roll_amigo_secreto(self, ctx: Context):

not_receiving = AmigoSecretoPerson.objects.filter(receiving=False).count()

if not_receiving > 0:
await ctx.author.send(f'Erro ao montar Amigo Secreto. Pessoas sem receber: {not_receiving}. Contate NRiver.')
return

await ctx.author.send(f'Amigo Secreto montado com sucesso. Total de pessoas: {AmigoSecretoPerson.objects.count()}')
if not_receiving > 0:
await ctx.author.send(
f"Erro ao montar Amigo Secreto. Pessoas sem receber: {not_receiving}. "
"Contate NRiver."
)
return

await ctx.author.send(
"Amigo Secreto montado com sucesso. Total de pessoas: "
f"{AmigoSecretoPerson.objects.count()}"
)

@commands.check(is_pedim_or_nriver)
@commands.command()
Expand Down Expand Up @@ -205,9 +211,10 @@ async def activate_amigo_secreto(self, ctx: Context):
start_date_brt = await ctx.prompt(
"Digite a data de inicio do Amigo Secreto (exemplo '20/12/2025 20:00'):"
)
end_date_brt = await ctx.prompt(
"Digite a data de fim do Amigo Secreto (exemplo '30/12/2025 20:00'). A data do sorteio será 2 dias antes da data final informada:"
)
end_date_brt = await ctx.prompt(
"Digite a data de fim do Amigo Secreto (exemplo '30/12/2025 20:00'). "
"A data do sorteio será 2 dias antes da data final informada:"
)

start_date_utc = datetime.strptime(start_date_brt, "%d/%m/%Y %H:%M") - timedelta(hours=3)
end_date_utc = datetime.strptime(end_date_brt, "%d/%m/%Y %H:%M") - timedelta(hours=3)
Expand Down Expand Up @@ -237,7 +244,10 @@ async def delete_amigo_secreto(self, ctx: Context):
if not confirmation:
return await ctx.send("Comando cancelado")

return await ctx.send(f"Todas as inscrições do Amigo Secreto do Atlantis foram deletadas. Total de pessoas inscritas: {total_count}")
return await ctx.send(
"Todas as inscrições do Amigo Secreto do Atlantis foram deletadas. "
f"Total de pessoas inscritas: {total_count}"
)

@commands.check(is_authenticated)
@commands.command(aliases=["amigosecreto", "amigo"])
Expand Down
14 changes: 8 additions & 6 deletions bot/cogs/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,12 +314,14 @@ async def github(self, ctx: Context):
github_embed.set_thumbnail(url=github_icon)
return await ctx.send(content=None, embed=github_embed)

# @commands.bot_has_permissions(embed_links=True)
@commands.command(aliases=["atlbot", "atlbotcommands"])
async def atlcommands(self, ctx: Context):
runepixels_url = (
f"https://runepixels.com/clans/{self.bot.setting.clan_name}/about"
)
# @commands.bot_has_permissions(embed_links=True)
@commands.hybrid_command(
name="atlantisbot", aliases=["atlbot", "atlbotcommands", "atlcommands"]
)
async def atlantisbot(self, ctx: Context):
runepixels_url = (
f"https://runepixels.com/clans/{self.bot.setting.clan_name}/about"
)
clan_banner = f"http://services.runescape.com/m=avatar-rs/l=3/a=869/{self.bot.setting.clan_name}/clanmotif.png"
embed_title = "RunePixels"

Expand Down
45 changes: 44 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ ruff = "^0.0.265"
mypy = "^1.2.0"
mypy_extensions = "^1.0.0"
black = "^23.3.0"
pytest = "^7.4.0"

[build-system]
requires = ["poetry-core>=1.0.0"]
Expand Down
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Test package for AtlantisBot."""
105 changes: 105 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
from __future__ import annotations

import sys
import types
from dataclasses import dataclass
from pathlib import Path
from types import SimpleNamespace
from typing import Any


ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.append(str(ROOT))


def _stub_modules():
stub_rs3clans = types.ModuleType("rs3clans")
stub_rs3clans.Clan = object
stub_rs3clans.Player = object
sys.modules["rs3clans"] = stub_rs3clans

stub_bot_client = types.ModuleType("bot.bot_client")

class Bot:
pass

stub_bot_client.Bot = Bot
sys.modules["bot.bot_client"] = stub_bot_client

stub_tools = types.ModuleType("bot.utils.tools")
stub_tools.right_arrow = "->"

def has_any_role(*_args, **_kwargs):
return False

stub_tools.has_any_role = has_any_role
sys.modules["bot.utils.tools"] = stub_tools

stub_checks = types.ModuleType("bot.utils.checks")

async def is_authenticated(ctx):
return True

async def is_admin(ctx):
return True

stub_checks.is_authenticated = is_authenticated
stub_checks.is_admin = is_admin
sys.modules["bot.utils.checks"] = stub_checks

stub_context = types.ModuleType("bot.utils.context")

class Context:
pass

stub_context.Context = Context
sys.modules["bot.utils.context"] = stub_context

stub_raids = types.ModuleType("bot.cogs.raids")

async def time_till_raids():
return 0, 0, 0

stub_raids.time_till_raids = time_till_raids
sys.modules["bot.cogs.raids"] = stub_raids


@dataclass
class FakeSettings:
clan_name: str = "Atlantis"
banner_image: str = "https://example.com/banner.png"
prefix: str = "!"
role: dict[str, int] | None = None
chat: dict[str, int] | None = None

def __post_init__(self):
if self.role is None:
self.role = {"pvm_teacher": 123, "aod": 456, "aod_learner": 789}
if self.chat is None:
self.chat = {"aod": 321}


class FakeContext:
def __init__(self):
self.sent_embed = None
self.sent_content = None
self.author = SimpleNamespace(roles=[])

async def send(self, content=None, *, embed=None):
self.sent_embed = embed
self.sent_content = content


def make_chat():
_stub_modules()
from bot.cogs.chat import Chat # noqa: E402

fake_bot = SimpleNamespace(setting=FakeSettings())
return Chat(fake_bot)


def run_async(coro: Any):
import asyncio

return asyncio.run(coro)
12 changes: 12 additions & 0 deletions tests/test_aplicar_aod_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from tests.helpers import FakeContext, make_chat, run_async


def test_aplicar_aod_sends_text_message():
chat = make_chat()
ctx = FakeContext()

run_async(chat.aplicar_aod.callback(chat, ctx))

assert ctx.sent_embed is None
assert ctx.sent_content is not None
assert "Você aplicou para receber a tag de AoD" in ctx.sent_content
20 changes: 20 additions & 0 deletions tests/test_atlantisbot_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from discord.ext import commands

from tests.helpers import FakeContext, make_chat, run_async


def test_atlantisbot_is_hybrid_command():
chat = make_chat()
ctx = FakeContext()

command = chat.atlantisbot
assert isinstance(command, commands.HybridCommand)
assert command.name == "atlantisbot"
assert "atlbot" in command.aliases

run_async(command.callback(chat, ctx))

assert ctx.sent_content is None
assert ctx.sent_embed is not None
assert ctx.sent_embed.title == "RunePixels"
assert any(field.name.startswith("!claninfo") for field in ctx.sent_embed.fields)