aboutsummaryrefslogtreecommitdiffstats
path: root/bot/exts/evergreen/fun.py
diff options
context:
space:
mode:
authorGravatar scragly <[email protected]>2020-09-21 18:43:54 +1000
committerGravatar GitHub <[email protected]>2020-09-21 18:43:54 +1000
commitbb02341c959b434cd8d2b6d40f0726a3b1388fb0 (patch)
tree179c12922ec2be15072380f144c2dadfe86615fc /bot/exts/evergreen/fun.py
parentPrevent uwu output from pinging globally allowed roles. (diff)
parentMerge pull request #445 from python-discord/fix/issue-pr-command (diff)
Merge branch 'master' into clean_uwu
Diffstat (limited to 'bot/exts/evergreen/fun.py')
-rw-r--r--bot/exts/evergreen/fun.py117
1 files changed, 109 insertions, 8 deletions
diff --git a/bot/exts/evergreen/fun.py b/bot/exts/evergreen/fun.py
index 5d4743e4..1668982b 100644
--- a/bot/exts/evergreen/fun.py
+++ b/bot/exts/evergreen/fun.py
@@ -1,14 +1,16 @@
import functools
+import json
import logging
import random
-from typing import Callable, Tuple, Union
+from pathlib import Path
+from typing import Callable, Iterable, Tuple, Union
from discord import Embed, Message
from discord.ext import commands
from discord.ext.commands import Bot, Cog, Context, MessageConverter, clean_content
from bot import utils
-from bot.constants import Emojis
+from bot.constants import Colours, Emojis
log = logging.getLogger(__name__)
@@ -26,12 +28,35 @@ UWU_WORDS = {
}
+def caesar_cipher(text: str, offset: int) -> Iterable[str]:
+ """
+ Implements a lazy Caesar Cipher algorithm.
+
+ Encrypts a `text` given a specific integer `offset`. The sign
+ of the `offset` dictates the direction in which it shifts to,
+ with a negative value shifting to the left, and a positive
+ value shifting to the right.
+ """
+ for char in text:
+ if not char.isascii() or not char.isalpha() or char.isspace():
+ yield char
+ continue
+
+ case_start = 65 if char.isupper() else 97
+ true_offset = (ord(char) - case_start + offset) % 26
+
+ yield chr(case_start + true_offset)
+
+
class Fun(Cog):
"""A collection of general commands for fun."""
def __init__(self, bot: Bot) -> None:
self.bot = bot
+ with Path("bot/resources/evergreen/caesar_info.json").open("r", encoding="UTF-8") as f:
+ self._caesar_cipher_embed = json.load(f)
+
@commands.command()
async def roll(self, ctx: Context, num_rolls: int = 1) -> None:
"""Outputs a number of random dice emotes (up to 6)."""
@@ -79,23 +104,99 @@ class Fun(Cog):
converted_text = f">>> {converted_text.lstrip('> ')}"
await ctx.send(content=converted_text, embed=embed)
+ @commands.group(name="caesarcipher", aliases=("caesar", "cc",))
+ async def caesarcipher_group(self, ctx: Context) -> None:
+ """
+ Translates a message using the Caesar Cipher.
+
+ See `decrypt`, `encrypt`, and `info` subcommands.
+ """
+ if ctx.invoked_subcommand is None:
+ await ctx.invoke(self.bot.get_command("help"), "caesarcipher")
+
+ @caesarcipher_group.command(name="info")
+ async def caesarcipher_info(self, ctx: Context) -> None:
+ """Information about the Caesar Cipher."""
+ embed = Embed.from_dict(self._caesar_cipher_embed)
+ embed.colour = Colours.dark_green
+
+ await ctx.send(embed=embed)
+
+ @staticmethod
+ async def _caesar_cipher(ctx: Context, offset: int, msg: str, left_shift: bool = False) -> None:
+ """
+ Given a positive integer `offset`, translates and sends the given `msg`.
+
+ Performs a right shift by default unless `left_shift` is specified as `True`.
+
+ Also accepts a valid Discord Message ID or link.
+ """
+ if offset < 0:
+ await ctx.send(":no_entry: Cannot use a negative offset.")
+ return
+
+ if left_shift:
+ offset = -offset
+
+ def conversion_func(text: str) -> str:
+ """Encrypts the given string using the Caesar Cipher."""
+ return "".join(caesar_cipher(text, offset))
+
+ text, embed = await Fun._get_text_and_embed(ctx, msg)
+
+ if embed is not None:
+ embed = Fun._convert_embed(conversion_func, embed)
+
+ converted_text = conversion_func(text)
+
+ if converted_text:
+ converted_text = f">>> {converted_text.lstrip('> ')}"
+
+ await ctx.send(content=converted_text, embed=embed)
+
+ @caesarcipher_group.command(name="encrypt", aliases=("rightshift", "rshift", "enc",))
+ async def caesarcipher_encrypt(self, ctx: Context, offset: int, *, msg: str) -> None:
+ """
+ Given a positive integer `offset`, encrypt the given `msg`.
+
+ Performs a right shift of the letters in the message.
+
+ Also accepts a valid Discord Message ID or link.
+ """
+ await self._caesar_cipher(ctx, offset, msg, left_shift=False)
+
+ @caesarcipher_group.command(name="decrypt", aliases=("leftshift", "lshift", "dec",))
+ async def caesarcipher_decrypt(self, ctx: Context, offset: int, *, msg: str) -> None:
+ """
+ Given a positive integer `offset`, decrypt the given `msg`.
+
+ Performs a left shift of the letters in the message.
+
+ Also accepts a valid Discord Message ID or link.
+ """
+ await self._caesar_cipher(ctx, offset, msg, left_shift=True)
+
@staticmethod
async def _get_text_and_embed(ctx: Context, text: str) -> Tuple[str, Union[Embed, None]]:
"""
Attempts to extract the text and embed from a possible link to a discord Message.
+ Does not retrieve the text and embed from the Message if it is in a channel the user does
+ not have read permissions in.
+
Returns a tuple of:
str: If `text` is a valid discord Message, the contents of the message, else `text`.
Union[Embed, None]: The embed if found in the valid Message, else None
"""
embed = None
- # message = await Fun._get_discord_message(ctx, text)
- # if isinstance(message, Message):
- # text = message.content
- # # Take first embed because we can't send multiple embeds
- # if message.embeds:
- # embed = message.embeds[0]
+ msg = await Fun._get_discord_message(ctx, text)
+ # Ensure the user has read permissions for the channel the message is in
+ if isinstance(msg, Message) and ctx.author.permissions_in(msg.channel).read_messages:
+ text = msg.content
+ # Take first embed because we can't send multiple embeds
+ if msg.embeds:
+ embed = msg.embeds[0]
return (text, embed)