Ejemplo n.º 1
0
    async def obama(self, ctx, *, text: str):
        """
            Synthesize video clips of Obama
        """
        text = ctx.message.clean_content[len(f"{ctx.prefix}{ctx.invoked_with}"
                                             ):]
        if len(text) > 280:
            msg = "A maximum character total of 280 is enforced. You sent: `{}` characters"
            return await ctx.send(msg.format(len(text)))
        async with ctx.typing():
            async with self.session.post(
                    url="http://talkobamato.me/synthesize.py",
                    data={"input_text": text}) as resp:
                if resp.status >= 400:
                    raise discord.HTTPException(
                        resp, f"{resp.url} returned error code {resp.status}")
                url = resp.url

            key = url.query['speech_key']
            link = f"http://talkobamato.me/synth/output/{key}/obama.mp4"
            await asyncio.sleep(len(text) // 5)
            async with self.session.get(link) as resp:
                if resp.status >= 400:
                    raise discord.HTTPException(
                        resp, f"{resp.url} returned error code {resp.status}")
            async with self.session.get(link) as r:
                data = BytesIO(await r.read())
            data.name = "obama.mp4"
            data.seek(0)
            file = discord.File(data)
            await ctx.send(files=[file])
Ejemplo n.º 2
0
    async def make_request(self,
                           method: str,
                           url: str,
                           *,
                           github=False,
                           json=None):
        """Makes a request to either the GitLab API or Github API

        Parameters
        -----------
        method: str
            The type of method to use.
        url: str
            The URL you are requesting.
        """
        if github:
            headers = self.github_headers
            headers.update({'Accept': 'application/vnd.github.v3+json'})
        else:
            headers = self.gitlab_headers
        headers.update({"User-Agent": "Lightning Bot Git Cog"})
        async with self.bot.aiosession.request(method,
                                               url,
                                               headers=headers,
                                               json=json) as resp:
            ratelimit = resp.headers.get("RateLimit-Remaining")
            if ratelimit == 0:
                raise LightningError(
                    "Currently ratelimited. Try again later(?)")
            elif 300 > resp.status >= 200:
                data = await resp.json()
            else:
                raise discord.HTTPException(response=resp,
                                            message=str(resp.reason))
        return data
Ejemplo n.º 3
0
    async def test_relay_message_handles_attachment_http_error(
            self, send_attachments, send_webhook):
        """The `relay_message` method should handle irretrievable attachments."""
        message = helpers.MockMessage(clean_content="message",
                                      attachments=["attachment"])

        self.cog.webhook = helpers.MockAsyncWebhook()
        log = logging.getLogger("bot.cogs.duck_pond")

        side_effect = discord.HTTPException(MagicMock(), "")
        send_attachments.side_effect = side_effect
        with self.subTest(side_effect=type(side_effect).__name__):
            with self.assertLogs(logger=log,
                                 level=logging.ERROR) as log_watcher:
                await self.cog.relay_message(message)

            send_webhook.assert_called_once_with(
                content=message.clean_content,
                username=message.author.display_name,
                avatar_url=message.author.avatar_url)

            self.assertEqual(len(log_watcher.records), 1)

            record = log_watcher.records[0]
            self.assertEqual(record.levelno, logging.ERROR)
Ejemplo n.º 4
0
    async def create_and_add_channel_webhook(
            self, conn, channel: discord.Channel) -> (str, str):
        # This method is only called if there's no webhook found in the DB (and hopefully within a transaction)
        # No need to worry about error handling if there's a DB conflict (which will throw an exception because DB constraints)
        req_headers = {"Authorization": "Bot {}".format(self.token)}

        # First, check if there's already a webhook belonging to the bot
        async with self.session.get(
            "https://discordapp.com/api/v6/channels/{}/webhooks".format(
                channel.id),
            headers=req_headers) as resp:
            if resp.status == 200:
                webhooks = await resp.json()
                for webhook in webhooks:
                    if webhook["user"]["id"] == self.client.user.id:
                        # This webhook belongs to us, we can use that, return it and save it
                        return await self.save_channel_webhook(
                            conn, channel, webhook["id"], webhook["token"])
            elif resp.status == 403:
                self.logger.warning(
                    "Did not have permission to fetch webhook list (server={}, channel={})"
                    .format(channel.server.id, channel.id))
                raise WebhookPermissionError()
            else:
                raise discord.HTTPException(resp, await resp.text())

        # Then, try submitting a new one
        req_data = {"name": "PluralKit Proxy Webhook"}
        async with self.session.post(
                "https://discordapp.com/api/v6/channels/{}/webhooks".format(
                    channel.id),
                json=req_data,
                headers=req_headers) as resp:
            if resp.status == 200:
                webhook = await resp.json()
                return await self.save_channel_webhook(conn, channel,
                                                       webhook["id"],
                                                       webhook["token"])
            elif resp.status == 403:
                self.logger.warning(
                    "Did not have permission to create webhook (server={}, channel={})"
                    .format(channel.server.id, channel.id))
                raise WebhookPermissionError()
            else:
                raise discord.HTTPException(resp, await resp.text())
async def test_add_emoji_role_pair_emoji_http_exception_400(mocker):
    """Adds a emoji/role pair to the role message creation, but there is an HTTPException 400."""
    cog, mock_bot, _ = init_mocks()
    mock_message = tosurnament_mock.DEFAULT_MESSAGE_MOCK
    mock_not_found_response = mocker.Mock()
    mock_not_found_response.status = 400
    mock_message.add_reaction = mocker.AsyncMock(side_effect=discord.HTTPException(mock_not_found_response, ""))
    await cog.add_emoji_role_pair(cog, tosurnament_mock.CtxMock(mock_bot, message=mock_message), "🛎️", None)
    cog.send_reply.assert_called_once_with(mocker.ANY, "emoji_not_found", "🛎️")
Ejemplo n.º 6
0
    async def test_send_prompt_returns_none_if_channel_fetch_fails(self):
        """None should be returned if there's an HTTPException when fetching the channel."""
        self.bot.get_channel.return_value = None
        self.bot.fetch_channel.side_effect = discord.HTTPException(
            mock.MagicMock(), "test error!")

        ret_val = await self.syncer._send_prompt()

        self.assertIsNone(ret_val)
async def test_add_emoji_role_pair_emoji_http_exception_other(mocker):
    """Adds a emoji/role pair to the role message creation, but there is an HTTPException other than 400."""
    cog, mock_bot, _ = init_mocks()
    mock_message = tosurnament_mock.DEFAULT_MESSAGE_MOCK
    mock_not_found_response = mocker.Mock()
    mock_not_found_response.status = 500
    mock_message.add_reaction = mocker.AsyncMock(side_effect=discord.HTTPException(mock_not_found_response, ""))
    with pytest.raises(discord.HTTPException):
        await cog.add_emoji_role_pair(cog, tosurnament_mock.CtxMock(mock_bot, message=mock_message), "🛎️", None)
Ejemplo n.º 8
0
    async def create_video(self, text):
        with async_timeout.timeout(10):
            async with self.bot.session.post(
                    url="http://talkobamato.me/synthesize.py",
                    data={"input_text": text}) as resp:
                if resp.status >= 400:
                    raise discord.HTTPException(
                        resp, f"{resp.url} returned error code {resp.status}")
                url = resp.url

        key = url.query['speech_key']
        link = f"http://talkobamato.me/synth/output/{key}/obama.mp4"
        await asyncio.sleep(len(text) // 5)
        with async_timeout.timeout(10):
            async with self.bot.session.get(link) as resp:
                if resp.status >= 400:
                    raise discord.HTTPException(
                        resp, f"{resp.url} returned error code {resp.status}")
        return link
Ejemplo n.º 9
0
    async def test_download_file_fail(self):
        """If `to_file` fails on a non-404 error, function logs the exception & returns None."""
        arbitrary_error = discord.HTTPException(
            MagicMock(aiohttp.ClientResponse), "Arbitrary API error")
        attachment = MockAttachment(to_file=AsyncMock(
            side_effect=arbitrary_error))

        with self.assertLogs(logger=incidents.log, level=logging.ERROR):
            acquired_file = await incidents.download_file(attachment)

        self.assertIsNone(acquired_file)
async def test_on_reaction_add_to_message_exception_when_adding_role(mocker):
    """Adds the selected role from a role message, but an exception occurs."""
    cog, mock_bot, reaction_for_role_message = init_mocks()
    reaction_for_role_message.message_id = tosurnament_mock.DEFAULT_MESSAGE_MOCK.id
    reaction_for_role_message.emojis = "🛎️"
    reaction_for_role_message.roles = str(tosurnament_mock.VERIFIED_ROLE_MOCK.id)
    mock_author = tosurnament_mock.DEFAULT_USER_MOCK
    mock_not_found_response = mocker.Mock()
    mock_not_found_response.status = 400
    mock_author.add_roles = mocker.AsyncMock(side_effect=discord.HTTPException(mock_not_found_response, ""))
    await cog.on_reaction_add_to_message.__wrapped__(cog, tosurnament_mock.CtxMock(mock_bot, mock_author), "🛎️")
    mock_author.add_roles.assert_called_once_with(tosurnament_mock.VERIFIED_ROLE_MOCK)
Ejemplo n.º 11
0
    def test_send_webhook_logs_when_sending_message_fails(self):
        """The `send_webhook` method should catch a `discord.HTTPException` and log accordingly."""
        self.cog.webhook = helpers.MockAsyncWebhook()
        self.cog.webhook.send.side_effect = discord.HTTPException(response=MagicMock(), message="Something failed.")

        log = logging.getLogger('bot.cogs.duck_pond')
        with self.assertLogs(logger=log, level=logging.ERROR) as log_watcher:
            asyncio.run(self.cog.send_webhook())

        self.assertEqual(len(log_watcher.records), 1)

        record = log_watcher.records[0]
        self.assertEqual(record.levelno, logging.ERROR)
Ejemplo n.º 12
0
    def test_fetch_webhook_logs_when_unable_to_fetch_webhook(self):
        """The `fetch_webhook` method should log an exception when it fails to fetch the webhook."""
        self.bot.fetch_webhook.side_effect = discord.HTTPException(response=MagicMock(), message="Not found.")
        self.cog.webhook_id = 1

        log = logging.getLogger('bot.cogs.duck_pond')
        with self.assertLogs(logger=log, level=logging.ERROR) as log_watcher:
            asyncio.run(self.cog.fetch_webhook())

        self.bot.wait_until_guild_available.assert_called_once()
        self.bot.fetch_webhook.assert_called_once_with(1)

        self.assertEqual(len(log_watcher.records), 1)

        record = log_watcher.records[0]
        self.assertEqual(record.levelno, logging.ERROR)
Ejemplo n.º 13
0
    async def test_resolve_message_fetch_fails(self):
        """
        Non-404 errors are handled, logged & None is returned.

        In contrast with a 404, this should make an error-level log. We assert that at least
        one such log was made - we do not make any assertions about the log's message.
        """
        self.cog_instance.bot._connection._get_message = MagicMock(
            return_value=None)  # Cache returns None

        arbitrary_error = discord.HTTPException(
            response=MagicMock(aiohttp.ClientResponse),
            message="Arbitrary error",
        )
        fetch_message = AsyncMock(side_effect=arbitrary_error)
        self.cog_instance.bot.get_channel = MagicMock(
            return_value=MockTextChannel(fetch_message=fetch_message))

        with self.assertLogs(logger=incidents.log, level=logging.ERROR):
            self.assertIsNone(await self.cog_instance.resolve_message(123))
Ejemplo n.º 14
0
    async def get_from_cdn(url) -> bytes:
        """
        A method that downloads an image from a url.

        Parameters:
            url (str): The url of the image.

        Returns:
            (bytes): A bytes object of the downloaded image.
        """

        async with ClientSession() as session:
            async with session.get(url) as resp:
                if resp.status == 200:
                    return await resp.read()
                elif resp.status == 404:
                    raise discord.NotFound(resp, 'Not Found')
                elif resp.status == 403:
                    raise discord.Forbidden(resp, 'Forbidden')
                else:
                    raise discord.HTTPException(resp, 'Failed')
Ejemplo n.º 15
0
 def error(*args, **kwargs):
     raise dpy.HTTPException(MockDpyObject(status=400, reason="No"),
                             "no")
Ejemplo n.º 16
0
    async def do_proxy_message(self,
                               conn,
                               member: db.ProxyMember,
                               original_message: discord.Message,
                               text: str,
                               attachment_url: str,
                               has_already_retried=False):
        hook_id, hook_token = await self.get_webhook_for_channel(
            conn, original_message.channel)

        form_data = aiohttp.FormData()
        form_data.add_field(
            "username", "{} {}".format(member.name, member.tag or "").strip())

        if text:
            form_data.add_field("content", text)

        if attachment_url:
            attachment_resp = await self.session.get(attachment_url)
            form_data.add_field("file",
                                attachment_resp.content,
                                content_type=attachment_resp.content_type,
                                filename=attachment_resp.url.name)

        if member.avatar_url:
            form_data.add_field("avatar_url", member.avatar_url)

        time_before = time.perf_counter()
        async with self.session.post(
                "https://discordapp.com/api/v6/webhooks/{}/{}?wait=true".
                format(hook_id, hook_token),
                data=form_data) as resp:
            if resp.status == 200:
                message = await resp.json()

                # Report webhook stats to Influx
                await self.stats.report_webhook(
                    time.perf_counter() - time_before, True)

                await db.add_message(conn, message["id"],
                                     message["channel_id"], member.id,
                                     original_message.author.id, text or "")

                try:
                    await self.client.delete_message(original_message)
                except discord.Forbidden:
                    self.logger.warning(
                        "Did not have permission to delete original message (server={}, channel={})"
                        .format(original_message.server.id,
                                original_message.channel.id))
                    raise DeletionPermissionError()
                except discord.NotFound:
                    self.logger.warning(
                        "Tried to delete message when proxying, but message was already gone (server={}, channel={})"
                        .format(original_message.server.id,
                                original_message.channel.id))

                message_image = None
                if message["attachments"]:
                    first_attachment = message["attachments"][0]
                    if "width" in first_attachment and "height" in first_attachment:
                        # Only log attachments that are actually images
                        message_image = first_attachment["url"]

                await self.channel_logger.log_message_proxied(
                    conn,
                    server_id=original_message.server.id,
                    channel_name=original_message.channel.name,
                    channel_id=original_message.channel.id,
                    sender_name=original_message.author.name,
                    sender_disc=original_message.author.discriminator,
                    member_name=member.name,
                    member_hid=member.hid,
                    member_avatar_url=member.avatar_url,
                    system_name=member.system_name,
                    system_hid=member.system_hid,
                    message_text=text,
                    message_image=message_image,
                    message_timestamp=ciso8601.parse_datetime(
                        message["timestamp"]),
                    message_id=message["id"])
            elif resp.status == 404 and not has_already_retried:
                # Report webhook stats to Influx
                await self.stats.report_webhook(
                    time.perf_counter() - time_before, False)

                # Webhook doesn't exist. Delete it from the DB, create, and add a new one
                self.logger.warning(
                    "Webhook registered in DB doesn't exist, deleting hook from DB, re-adding, and trying again (channel={}, hook={})"
                    .format(original_message.channel.id, hook_id))
                await db.delete_webhook(conn, original_message.channel.id)
                await self.create_and_add_channel_webhook(
                    conn, original_message.channel)

                # Then try again all over, making sure to not retry again and go in a loop should it continually fail
                return await self.do_proxy_message(conn,
                                                   member,
                                                   original_message,
                                                   text,
                                                   attachment_url,
                                                   has_already_retried=True)
            else:
                # Report webhook stats to Influx
                await self.stats.report_webhook(
                    time.perf_counter() - time_before, False)

                raise discord.HTTPException(resp, await resp.text())
Ejemplo n.º 17
0
def disc_http_exception():
    response = simple_class_factory(status=401, reason="")
    return discord.HTTPException(message="", response=response)