Skip to content

Commit ff54aec

Browse files
committed
Shorten Command and Tests.
1 parent 4c4b9b8 commit ff54aec

File tree

5 files changed

+181
-103
lines changed

5 files changed

+181
-103
lines changed

bot/cogs/shorten/command/shorten.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
from __future__ import annotations
22

3+
import asyncio
4+
import inspect
5+
import types
36
from typing import TYPE_CHECKING
47

8+
from urlextract import URLExtract
9+
510
from bot.ext import Context, Response, commands
11+
from bot.utils import SessionsCaches, UploadThings
612

713
from .translations import Translations
814

@@ -14,6 +20,8 @@ class ShortenCmd(commands.CustomComponent):
1420
def __init__(self, bot: Gorenmu) -> None:
1521
self.bot = bot
1622
self.translations: Translations = Translations(bot)
23+
self.UploadThings: UploadThings = UploadThings(bot)
24+
self.SessionsCaches: SessionsCaches = SessionsCaches(bot)
1725

1826
cooldown_rate = 3
1927
cooldown_per = 10
@@ -25,9 +33,38 @@ async def component_command_error(self, payload: commands.CommandErrorPayload) -
2533
def guards_component(self, ctx: commands.Context) -> bool: # NOQA
2634
return True
2735

28-
@commands.command(name="shorten", aliases=[])
29-
async def shorten(self, ctx: Context, *, args) -> Response:
30-
return self.translations.Exceptions.echo(ctx, args)
36+
@commands.command(name="shorten", aliases=["short"])
37+
async def shorten(self, ctx: Context, *, content) -> Response:
38+
links = URLExtract().find_urls(text=content)
39+
if not links:
40+
...
41+
session = self.SessionsCaches.Shorten.session
42+
if len(links) > 1:
43+
link = ""
44+
for url in links:
45+
await asyncio.sleep(0.1)
46+
short = await self.UploadThings.shortener(url, ["shortener"], session)
47+
if not short:
48+
fake_exc = fake_stacktrace(f"External shortener API failed for: {url}")
49+
await self.bot.CommandHandler.send_bug(ctx, fake_exc)
50+
return self.translations.Shorten.api_erro(ctx)
51+
link += f"{short} "
52+
return self.translations.Shorten.urls(ctx, link)
53+
else:
54+
short = await self.UploadThings.shortener(links[0], ["shortener"], session)
55+
if short:
56+
return self.translations.Shorten.url(ctx, short)
57+
fake_exc = fake_stacktrace(f"External shortener API failed for: {links[0]}")
58+
await self.bot.CommandHandler.send_bug(ctx, fake_exc)
59+
return self.translations.Shorten.api_erro(ctx)
60+
61+
62+
def fake_stacktrace(message: str) -> Exception | None:
63+
exc = Exception(message)
64+
tb = types.TracebackType(tb_next=None, tb_frame=inspect.currentframe().f_back, tb_lasti=0, tb_lineno=1)
65+
66+
exc.__traceback__ = tb
67+
return exc
3168

3269

3370
async def setup(bot: Gorenmu) -> None:

bot/cogs/shorten/command/translations.py

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from typing import TYPE_CHECKING
44

5-
from bot.ext import Admonitions, CommandExemples, Response, TBase, TranslationBase
5+
from bot.ext import Response, TBase, TranslationBase
66

77
if TYPE_CHECKING:
88
from bot.bot import Gorenmu
@@ -18,52 +18,43 @@ class Shorten(TBase):
1818
def __init__(self):
1919
super().__init__()
2020

21-
def placeholder(self, ctx: Context, *args) -> Response:
21+
def api_erro(self, ctx: Context) -> Response:
2222
response = Response(ctx=ctx, success=False, handle=None, response_list=None)
2323
with self.lang_dict.once(self._cname):
24-
self.lang_dict.add_with("en", "")
25-
self.lang_dict.add_with(["pt_br", "pt"], "")
26-
return response.format_response(self._untangle_str(ctx, self._cname), args)
24+
self.lang_dict.add_with("en", "The shortener API is currently experiencing issues.")
25+
self.lang_dict.add_with(["pt_br", "pt"], "A API do encurtador apresentando problemas no momento.")
26+
return response.format_response(self._untangle_str(ctx, self._cname))
2727

28-
def placeholder2(self, ctx: Context, *args) -> Response:
29-
response = Response(ctx=ctx, success=False, handle=None, response_list=None)
28+
def urls(self, ctx: Context, urls) -> Response:
29+
response = Response(ctx=ctx, success=True, handle=None, response_list=None)
30+
with self.lang_dict.once(self._cname):
31+
self.lang_dict.add_with("en", "Here are all the URLs: {}")
32+
self.lang_dict.add_with(["pt_br", "pt"], "Aqui estão todos os URLs: {}")
33+
return response.format_response(self._untangle_str(ctx, self._cname), urls)
34+
35+
def url(self, ctx: Context, url) -> Response:
36+
response = Response(ctx=ctx, success=True, handle=None, response_list=None)
3037
with self.lang_dict.once(self._cname):
31-
self.lang_dict.add_with("en", "")
32-
self.lang_dict.add_with(["pt_br", "pt"], "")
33-
return response.format_response(self._untangle_str(ctx, self._cname), args)
38+
self.lang_dict.add_with("en", "Here is the URL: {}")
39+
self.lang_dict.add_with(["pt_br", "pt"], "Aqui está URL: {}")
40+
return response.format_response(self._untangle_str(ctx, self._cname), url)
3441

3542
def deco_helper(self, ctx: Context, *args, **kwargs) -> str:
3643
with self.lang_dict.once(self._cname):
37-
self.lang_dict.add_with("en", "")
38-
self.lang_dict.add_with(["pt_br", "pt"], "")
44+
self.lang_dict.add_with("en", "Shorten links using my link shortening service.")
45+
self.lang_dict.add_with(["pt_br", "pt"], "Encurta links usando o meu serviço de encurtar links.")
3946
return self._untangle_str(ctx, self._cname)
4047

4148
def deco_usage(self, ctx: Context, prefix: str | None = None, *args, **kwargs) -> str:
4249
with self.lang_dict.once(self._cname):
43-
self.lang_dict.add_with("en", "")
44-
self.lang_dict.add_with(["pt_br", "pt"], "")
50+
self.lang_dict.add_with("en", "To use: {}shorten (links)")
51+
self.lang_dict.add_with(["pt_br", "pt"], "Para usar: {}shorten (links)")
4552
return self._untangle_str(ctx, self._cname).format(prefix)
4653

47-
# region Hide.
48-
4954
def deco_description(self, ctx: Context, *args, **kwargs) -> str:
5055
with self.lang_dict.once(self._cname):
51-
self.lang_dict.add_with("en", "")
52-
self.lang_dict.add_with(["pt_br", "pt"], "")
56+
self.lang_dict.add_with("en", "Shorten links using my link shortening service.")
57+
self.lang_dict.add_with(["pt_br", "pt"], "Encurta links usando o meu serviço de encurtar links.")
5358
return self._untangle_str(ctx, self._cname)
5459

55-
def deco_commands(self, ctx: Context, *args, **kwargs) -> CommandExemples:
56-
with self.lang_dict.once(self._cname):
57-
self.lang_dict.add_with("en", CommandExemples([]))
58-
self.lang_dict.add_with(["pt_br", "pt"], CommandExemples([]))
59-
return self._untangle_commands(ctx, self._cname)
60-
61-
def deco_admonitions(self, ctx: Context, *args, **kwargs) -> Admonitions:
62-
with self.lang_dict.once(self._cname):
63-
self.lang_dict.add_with("en", Admonitions([]))
64-
self.lang_dict.add_with(["pt_br", "pt"], Admonitions([]))
65-
return self._untangle_admonitions(ctx, self._cname)
66-
67-
# endregion
68-
6960
Shorten: Shorten

bot/utils/cache_sessions.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,6 @@ def get_expiry_times(self) -> dict:
234234

235235
Bug: Bug
236236

237-
# endregion
238-
239237
class Suggest(BaseCachedSession):
240238
def __init__(self, bot: Gorenmu, useragent: str):
241239
self.allowed_codes = (200,)
@@ -279,6 +277,8 @@ def get_expiry_times(self) -> dict:
279277

280278
RandomLine: RandomLine
281279

280+
# endregion
281+
282282
class Nicks(BaseCachedSession):
283283
def __init__(self, bot: Gorenmu, useragent: str):
284284
self.allowed_codes = (200,)
@@ -288,3 +288,13 @@ def get_expiry_times(self) -> dict:
288288
return {self.bot.config.ApisConfig.best_logs / "*": timedelta(microseconds=250)}
289289

290290
Nicks: Nicks
291+
292+
class Shorten(BaseCachedSession):
293+
def __init__(self, bot: Gorenmu, useragent: str):
294+
self.allowed_codes = (200,)
295+
super().__init__(bot=bot, useragent=useragent)
296+
297+
def get_expiry_times(self) -> dict:
298+
return {self.bot.config.ApisConfig.best_logs / "*": timedelta(microseconds=250)}
299+
300+
Shorten: Shorten

tests/tests/cogs/shorten/shorten/test_params.py

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,49 @@
55

66
class Params:
77
decorators: ClassVar[list] = [
8-
pytest.param("en", "", "", marks=pytest.mark.en, id="en"),
8+
pytest.param(
9+
"en",
10+
"Shorten links using my link shortening service.",
11+
"To use: +shorten (links)",
12+
marks=pytest.mark.en,
13+
id="en",
14+
),
915
pytest.param(
1016
"pt_BR",
11-
"",
12-
"",
17+
"Encurta links usando o meu serviço de encurtar links.",
18+
"Para usar: +shorten (links)",
1319
marks=pytest.mark.pt_BR,
1420
id="pt_BR",
1521
),
1622
]
1723

18-
no_content: ClassVar[list] = [
19-
pytest.param("en", "blablabla", marks=pytest.mark.en, id="en"),
20-
pytest.param("pt_BR", "blablabla", marks=pytest.mark.pt_BR, id="pt_BR"),
24+
one_link: ClassVar[list] = [
25+
pytest.param("en", "Here is the URL: https://success.url/", marks=pytest.mark.en, id="en"),
26+
pytest.param("pt_BR", "Aqui está URL: https://success.url/", marks=pytest.mark.pt_BR, id="pt_BR"),
2127
]
2228

23-
params_: ClassVar[list] = [
24-
pytest.param("en", "blablabla", marks=pytest.mark.en, id="en"),
25-
pytest.param("pt_BR", "blablabla", marks=pytest.mark.pt_BR, id="pt_BR"),
29+
multiple_links: ClassVar[list] = [
30+
pytest.param(
31+
"en",
32+
"Here are all the URLs: https://success.url/ https://success.url/ https://success.url/ ",
33+
marks=pytest.mark.en,
34+
id="en",
35+
),
36+
pytest.param(
37+
"pt_BR",
38+
"Aqui estão todos os URLs: https://success.url/ https://success.url/ https://success.url/ ",
39+
marks=pytest.mark.pt_BR,
40+
id="pt_BR",
41+
),
2642
]
2743

28-
params_: ClassVar[list] = [
29-
pytest.param("en", "blablabla", marks=pytest.mark.en, id="en"),
30-
pytest.param("pt_BR", "blablabla", marks=pytest.mark.pt_BR, id="pt_BR"),
44+
error_link: ClassVar[list] = [
45+
pytest.param("en", "The shortener API is currently experiencing issues.", marks=pytest.mark.en, id="en"),
46+
pytest.param(
47+
"pt_BR", "A API do encurtador apresentando problemas no momento.", marks=pytest.mark.pt_BR, id="pt_BR"
48+
),
3149
]
50+
51+
json_success: ClassVar[dict] = {"shortUrl": "https://success.url/"}
52+
53+
json_error: ClassVar[dict] = {"status": "error"}
Lines changed: 72 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,72 @@
1-
# import pytest
2-
# import pytest_asyncio
3-
#
4-
# from bot.cogs.shorten.command.shorten import ShortenCmd
5-
# from tests.helpers.mock_classes import MockContext
6-
#
7-
# from .test_params import Params
8-
9-
10-
# @pytest_asyncio.fixture
11-
# async def interact(mock_bot):
12-
# return ShortenCmd(bot=mock_bot)
13-
14-
15-
# @pytest.mark.asyncio
16-
# @pytest.mark.parametrize("lang, helper, usage", Params.decorators)
17-
# async def test_decorators(interact, mock_context: MockContext, lang: str, helper: str, usage: str):
18-
# await mock_context.prepare_context(lang)
19-
# mock_context.Asserter.assert_string(interact.translations.
20-
# Shorten.deco_usage(mock_context, "+"), usage, strict=True)
21-
# mock_context.Asserter.assert_string(
22-
# interact.translations.Shorten.deco_helper(mock_context, "+"), helper, strict=True
23-
# )
24-
25-
26-
# async def base_shorten(
27-
# interact,
28-
# mock_context: MockContext,
29-
# lang: str,
30-
# content: str,
31-
# expected: str | None = None,
32-
# re_expected: str | None = None,
33-
# success: bool = False,
34-
# ):
35-
# await mock_context.prepare_context(lang)
36-
# response: Response = await interact.shorten._callback(
37-
# interact, mock_context, content
38-
# ) # NOQA
39-
# mock_context.Asserter.assert_string(
40-
# response.response_string, expected=expected, re_expected=re_expected
41-
# )
42-
# mock_context.Asserter.assert_boolean(response.success, success)
43-
44-
45-
# @pytest.mark.asyncio
46-
# @pytest.mark.parametrize("lang, expected", Params.no_content)
47-
# async def test_no_content(interact, mock_context: MockContext, lang: str, expected: str):
48-
# await base_shorten(interact, mock_context, lang=lang, content="", expected=expected, success=True)
49-
#
50-
#
51-
# @pytest.mark.asyncio
52-
# @pytest.mark.parametrize("lang, expected", Params.no_content)
53-
# async def test_(interact, mock_context: MockContext, lang: str, expected: str):
54-
# await base_shorten(interact, mock_context, lang=lang, content="", expected=expected, success=True)
1+
import pytest
2+
import pytest_asyncio
3+
4+
from bot.cogs.shorten.command.shorten import ShortenCmd
5+
from tests.helpers.mock_classes import MockContext
6+
7+
from .test_params import Params
8+
9+
10+
@pytest_asyncio.fixture
11+
async def interact(mock_bot):
12+
return ShortenCmd(bot=mock_bot)
13+
14+
15+
@pytest.mark.asyncio
16+
@pytest.mark.parametrize("lang, helper, usage", Params.decorators)
17+
async def test_decorators(interact, mock_context: MockContext, lang: str, helper: str, usage: str):
18+
await mock_context.prepare_context(lang)
19+
mock_context.Asserter.assert_string(interact.translations.Shorten.deco_usage(mock_context, "+"), usage, strict=True)
20+
mock_context.Asserter.assert_string(
21+
interact.translations.Shorten.deco_helper(mock_context, "+"), helper, strict=True
22+
)
23+
24+
25+
async def base_shorten(
26+
interact,
27+
mock_context: MockContext,
28+
lang: str,
29+
content: str,
30+
expected: str | None = None,
31+
re_expected: str | None = None,
32+
success: bool = False,
33+
):
34+
await mock_context.prepare_context(lang)
35+
response = await interact.shorten._callback(interact, mock_context, content=content) # NOQA
36+
mock_context.Asserter.assert_string(response.response_string, expected=expected, re_expected=re_expected)
37+
mock_context.Asserter.assert_boolean(response.success, success)
38+
39+
40+
@pytest.mark.asyncio
41+
@pytest.mark.parametrize("lang, expected", Params.one_link)
42+
async def test_one_link(interact, mock_context: MockContext, lang: str, expected: str):
43+
session = interact.SessionsCaches.Shorten.session
44+
async with mock_context.MockBuilder.Session.post_json(session, Params.json_success):
45+
await base_shorten(
46+
interact, mock_context, lang=lang, content="https://someurl.org/url", expected=expected, success=True
47+
)
48+
49+
50+
@pytest.mark.asyncio
51+
@pytest.mark.parametrize("lang, expected", Params.multiple_links)
52+
async def test_multiple_links(interact, mock_context: MockContext, lang: str, expected: str):
53+
session = interact.SessionsCaches.Shorten.session
54+
async with mock_context.MockBuilder.Session.post_json(session, Params.json_success):
55+
await base_shorten(
56+
interact,
57+
mock_context,
58+
lang=lang,
59+
content="https://someurl.org/url, https://someurl.org/url2, https://someurl.org/url3",
60+
expected=expected,
61+
success=True,
62+
)
63+
64+
65+
@pytest.mark.asyncio
66+
@pytest.mark.parametrize("lang, expected", Params.error_link)
67+
async def test_error(interact, mock_context: MockContext, lang: str, expected: str):
68+
session = interact.SessionsCaches.Shorten.session
69+
async with mock_context.MockBuilder.Session.post_json(session, Params.json_error).Errors.send_bug():
70+
await base_shorten(
71+
interact, mock_context, lang=lang, content="https://someurl.org/url", expected=expected, success=False
72+
)

0 commit comments

Comments
 (0)