Skip to content
This repository has been archived by the owner on Nov 24, 2019. It is now read-only.

Commit

Permalink
Release v0.7.5
Browse files Browse the repository at this point in the history
  • Loading branch information
sco1 committed Sep 23, 2018
2 parents a77c5d7 + dc6e4b4 commit cc88e1d
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 13 deletions.
98 changes: 96 additions & 2 deletions cogs/bot.py
@@ -1,4 +1,6 @@
import asyncio
import logging
import string
from datetime import datetime

import discord
Expand All @@ -10,6 +12,8 @@ class MainCommands():
def __init__(self, bot):
self.bot = bot

self._lettermap = self._buildletterunicode()

@commands.command()
async def ver(self, ctx: commands.Context):
"""
Expand Down Expand Up @@ -50,24 +54,114 @@ async def kill(self, ctx: commands.Context):
logging.info(f'Unauthorized kill attempt by {ctx.message.author}')
await ctx.send(f'{ctx.message.author.mention}, you are not authorized to perform this operation')

@commands.command()
async def reactmessage(self, ctx: commands.Context, *args, selfdestructdelay: int=10):
"""
Add reaction message to a message ID
e.g. ~reactmessage 492366085232787467 Hype
Command and any feedback are deleted after selfdestructdelay seconds
"""
# Assume last entry in args is the message ID and concatenate everything else into the message
continueflag = False
try:
messageID = int(args[0])
except ValueError:
pass
reactmessage = ''.join(args[1::]).replace(' ', '').upper() # Remove spaces & normalize to lowercase

if not Helpers.isWumbologist(ctx.message.author):
feedbackmsg = await ctx.send(f'{ctx.message.author.mention}, you are not authorized to perform this operation')
elif len(reactmessage) == 0:
feedbackmsg = await ctx.send("Command must be invoked with both a message and a message ID")
elif not reactmessage.isalpha():
feedbackmsg = await ctx.send("Reaction message must only contain alphabetic characters")
elif len(reactmessage) != len(set(reactmessage.lower())):
feedbackmsg = await ctx.send("Reaction message cannot contain duplicate letters")
else:
continueflag = True

if not continueflag:
await asyncio.sleep(selfdestructdelay)
await ctx.message.delete()
await feedbackmsg.delete()
return

continueflag = False
messageObj = None
for channel in self.bot.get_all_channels():
if isinstance(channel, discord.TextChannel):
try:
foundchannel = channel
messageObj = await channel.get_message(messageID)
continueflag = True
except (discord.NotFound, discord.Forbidden, discord.HTTPException):
continue
finally:
if not messageObj:
feedbackmsg = await ctx.send(f"Message ID '{messageID}' could not be obtained")

if continueflag:
async with foundchannel.typing():
for letter in reactmessage:
await messageObj.add_reaction(self._lettermap[letter])
await asyncio.sleep(selfdestructdelay)
else:
await asyncio.sleep(selfdestructdelay)
await ctx.message.delete()
await feedbackmsg.delete()

await ctx.message.delete()


@staticmethod
def _buildletterunicode():
"""
Return a dictionary mapping of alphabetical characters to their
Unicode Regional Indicator Symbol Equivalent (1F1E6..1F1FF)
See:
https://en.wikipedia.org/wiki/Regional_Indicator_Symbol
https://www.unicode.org/charts/PDF/U1F100.pdf
"""
# # Offset alphabetic letter index & convert to base 16
# a = [(n + 5) % 16 for n in range(1, 27)]
# hexes = [hex(n)[2::].upper() for n in a]

# suffix = ['E']*10 + ['F']*16
# unicodez = [f"\\u1F1{x}{y}" for x,y in zip(suffix, hexes)]

# return {letter:unicode for letter, unicode in zip(string.ascii_uppercase, unicodez)}

# Map using ord and the unicode code point rather than the above
return {letter:chr(ID) for letter, ID in zip(string.ascii_uppercase, range(127462, 127488))}


class Helpers:
@staticmethod
def isOwner(user: discord.User):
def isOwner(user: discord.User) -> bool:
"""
Check to see if the input User's ID matches the Owner ID
"""
ownerID = 129606635545952258
return user.id == ownerID

@staticmethod
def isDM(channel: discord.TextChannel):
def isDM(channel: discord.TextChannel) -> bool:
"""
Check to see if a channel is a DM
A DM is either an instance of DMChannel or GroupChannel
"""
return isinstance(channel, (discord.DMChannel, discord.GroupChannel))

def isWumbologist(member: discord.Member) -> bool:
"""
Check to see if a discord.Member has the 'Wumbologists' role
"""
return 'Wumbologists' in [str(role) for role in member.roles]


def setup(bot):
bot.add_cog(MainCommands(bot))
2 changes: 1 addition & 1 deletion cogs/mhw.py
Expand Up @@ -122,7 +122,7 @@ def saveposted(self, logJSONpath: Path=None):
if self.postedMHWnews:
with logJSONpath.open(mode='w') as fID:
json.dump([str(url) for url in self.postedMHWnews], fID)
logging.info(f"Saved {len(self.postedpatches)} MHW news post(s)")
logging.info(f"Saved {len(self.postedMHWnews)} MHW news post(s)")
else:
logging.info("No MHW news posts to save")

Expand Down
2 changes: 1 addition & 1 deletion cogs/overwatch.py
Expand Up @@ -31,7 +31,7 @@ async def getpatchgifs(self, jsonURL: URL=None):
"""
jsonURL = jsonURL if jsonURL is not None else self.postjsonURL
postobjs = await RedditPost.asyncfromJSON(jsonURL)
logging.info(f"Found {len(postobjs)} OW GIF post(s)")
logging.info(f"Found {len(postobjs)} submission(s) by /u/itsjieyang")

patchposts = []
for postobj in postobjs:
Expand Down
4 changes: 2 additions & 2 deletions cogs/reddit.py
Expand Up @@ -25,8 +25,8 @@ def __init__(self, inJSON:typing.Dict):
self.subreddit = inJSON['data']['subreddit']
self.title = inJSON['data']['title']
self.createdUTC = datetime.utcfromtimestamp(inJSON['data']['created_utc'])
self.contentURL = inJSON['data']['url']
self.permalink = f"https://www.reddit.com{inJSON['data']['permalink']}"
self.contentURL = URL(inJSON['data']['url'])
self.permalink = URL(f"https://www.reddit.com{inJSON['data']['permalink']}")

def __repr__(self):
return f"{self.title}: {self.permalink}"
Expand Down
29 changes: 24 additions & 5 deletions docs/cogs/bot.rst
Expand Up @@ -39,15 +39,34 @@ Commands are prefixed with ``~``

Disconnects Wumbot from the server.

.. note::
This command is only enabled for the server owner via DM.

.. code-block:: none
[13:37] ELA: ~kill
[13:37] Wumbot: Shutting down... :wave:
.. note::
This command is only enabled for the server owner via DM.

.. code-block:: none
[13:37] notELA: ~kill
[13:37] Wumbot: You are not authorized to perform this operation
.. function:: ~reactmessage messageID message

Applies a reaction message to a message, as specified by the message's integer ID.

.. code-block:: none
[13:37] notELA: ~kill
[13:37] Wumbot: You are not authorized to perform this operation
[13:37] ELA: ~reactmessage 492366085232787467 Hype
``reactionmessage`` is constrained as follows:

* Command may only be invoked by the 'Wumbologists' role
* Message must be alphabetic (includes space)
* Message must not contain repeat characters

.. note::
If the reaction message is successful, the invoking command is automatically deleted after 10 seconds.

Any feedback on incorrectly formed input or permission restriction is also automatically deleted after 10 seconds.
6 changes: 4 additions & 2 deletions setup.py
Expand Up @@ -15,7 +15,7 @@
setup(name='wumbot',
author='sco1',
url='https://github.com/Wumbology-Inc/Wumbot',
version='v0.7.4',
version='v0.7.5',
description='A Python Discord bot for Wumbology, Inc.',
long_description=readme,
extras_require=extras_require,
Expand All @@ -25,8 +25,10 @@
'Intended Audience :: Developers',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Topic :: Internet',
'Topic :: Communications :: Chat',
'Topic :: Internet'
]
)

0 comments on commit cc88e1d

Please sign in to comment.