Merge pull request #3 from StudyLions/staging
Bugfixes and minor UI improvements
This commit is contained in:
@@ -1,4 +1,9 @@
|
|||||||
from cmdClient import Command, Module
|
import asyncio
|
||||||
|
import traceback
|
||||||
|
import logging
|
||||||
|
import discord
|
||||||
|
|
||||||
|
from cmdClient import Command, Module, FailedCheck
|
||||||
from cmdClient.lib import SafeCancellation
|
from cmdClient.lib import SafeCancellation
|
||||||
|
|
||||||
from meta import log
|
from meta import log
|
||||||
@@ -79,3 +84,87 @@ class LionModule(Module):
|
|||||||
# Check guild's own member blacklist
|
# Check guild's own member blacklist
|
||||||
if ctx.author.id in ctx.client.objects['ignored_members'][ctx.guild.id]:
|
if ctx.author.id in ctx.client.objects['ignored_members'][ctx.guild.id]:
|
||||||
raise SafeCancellation
|
raise SafeCancellation
|
||||||
|
|
||||||
|
# Check channel permissions are sane
|
||||||
|
if not ctx.ch.permissions_for(ctx.guild.me).send_messages:
|
||||||
|
raise SafeCancellation
|
||||||
|
if not ctx.ch.permissions_for(ctx.guild.me).embed_links:
|
||||||
|
await ctx.reply("I need permission to send embeds in this channel before I can run any commands!")
|
||||||
|
raise SafeCancellation
|
||||||
|
|
||||||
|
# Start typing
|
||||||
|
await ctx.ch.trigger_typing()
|
||||||
|
|
||||||
|
async def on_exception(self, ctx, exception):
|
||||||
|
try:
|
||||||
|
raise exception
|
||||||
|
except (FailedCheck, SafeCancellation):
|
||||||
|
# cmdClient generated and handled exceptions
|
||||||
|
raise exception
|
||||||
|
except (asyncio.CancelledError, asyncio.TimeoutError):
|
||||||
|
# Standard command and task exceptions, cmdClient will also handle these
|
||||||
|
raise exception
|
||||||
|
except discord.Forbidden:
|
||||||
|
# Unknown uncaught Forbidden
|
||||||
|
try:
|
||||||
|
# Attempt a general error reply
|
||||||
|
await ctx.reply("I don't have enough channel or server permissions to complete that command here!")
|
||||||
|
except discord.Forbidden:
|
||||||
|
# We can't send anything at all. Exit quietly, but log.
|
||||||
|
full_traceback = traceback.format_exc()
|
||||||
|
log(("Caught an unhandled 'Forbidden' while "
|
||||||
|
"executing command '{cmdname}' from module '{module}' "
|
||||||
|
"from user '{message.author}' (uid:{message.author.id}) "
|
||||||
|
"in guild '{message.guild}' (gid:{guildid}) "
|
||||||
|
"in channel '{message.channel}' (cid:{message.channel.id}).\n"
|
||||||
|
"Message Content:\n"
|
||||||
|
"{content}\n"
|
||||||
|
"{traceback}\n\n"
|
||||||
|
"{flat_ctx}").format(
|
||||||
|
cmdname=ctx.cmd.name,
|
||||||
|
module=ctx.cmd.module.name,
|
||||||
|
message=ctx.msg,
|
||||||
|
guildid=ctx.guild.id if ctx.guild else None,
|
||||||
|
content='\n'.join('\t' + line for line in ctx.msg.content.splitlines()),
|
||||||
|
traceback=full_traceback,
|
||||||
|
flat_ctx=ctx.flatten()
|
||||||
|
),
|
||||||
|
context="mid:{}".format(ctx.msg.id),
|
||||||
|
level=logging.WARNING)
|
||||||
|
except Exception as e:
|
||||||
|
# Unknown exception!
|
||||||
|
full_traceback = traceback.format_exc()
|
||||||
|
only_error = "".join(traceback.TracebackException.from_exception(e).format_exception_only())
|
||||||
|
|
||||||
|
log(("Caught an unhandled exception while "
|
||||||
|
"executing command '{cmdname}' from module '{module}' "
|
||||||
|
"from user '{message.author}' (uid:{message.author.id}) "
|
||||||
|
"in guild '{message.guild}' (gid:{guildid}) "
|
||||||
|
"in channel '{message.channel}' (cid:{message.channel.id}).\n"
|
||||||
|
"Message Content:\n"
|
||||||
|
"{content}\n"
|
||||||
|
"{traceback}\n\n"
|
||||||
|
"{flat_ctx}").format(
|
||||||
|
cmdname=ctx.cmd.name,
|
||||||
|
module=ctx.cmd.module.name,
|
||||||
|
message=ctx.msg,
|
||||||
|
guildid=ctx.guild.id if ctx.guild else None,
|
||||||
|
content='\n'.join('\t' + line for line in ctx.msg.content.splitlines()),
|
||||||
|
traceback=full_traceback,
|
||||||
|
flat_ctx=ctx.flatten()
|
||||||
|
),
|
||||||
|
context="mid:{}".format(ctx.msg.id),
|
||||||
|
level=logging.ERROR)
|
||||||
|
|
||||||
|
error_embed = discord.Embed(title="Something went wrong!")
|
||||||
|
error_embed.description = (
|
||||||
|
"An unexpected error occurred while processing your command!\n"
|
||||||
|
"Our development team has been notified, and the issue should be fixed soon.\n"
|
||||||
|
)
|
||||||
|
if logging.getLogger().getEffectiveLevel() < logging.INFO:
|
||||||
|
error_embed.add_field(
|
||||||
|
name="Exception",
|
||||||
|
value="`{}`".format(only_error)
|
||||||
|
)
|
||||||
|
|
||||||
|
await ctx.reply(embed=error_embed)
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ from .reminders import *
|
|||||||
from .renting import *
|
from .renting import *
|
||||||
from .moderation import *
|
from .moderation import *
|
||||||
from .accountability import *
|
from .accountability import *
|
||||||
|
from .plugins import *
|
||||||
|
|||||||
@@ -409,12 +409,13 @@ class TimeSlot:
|
|||||||
if self.channel:
|
if self.channel:
|
||||||
try:
|
try:
|
||||||
await self.channel.delete()
|
await self.channel.delete()
|
||||||
|
self.channel = None
|
||||||
except discord.HTTPException:
|
except discord.HTTPException:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if self.message:
|
if self.message:
|
||||||
try:
|
try:
|
||||||
timestamp = self.start_time.timestamp()
|
timestamp = int(self.start_time.timestamp())
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="Session <t:{}:t> - <t:{}:t>".format(
|
title="Session <t:{}:t> - <t:{}:t>".format(
|
||||||
timestamp, timestamp + 3600
|
timestamp, timestamp + 3600
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import asyncio
|
||||||
import discord
|
import discord
|
||||||
|
|
||||||
import settings
|
import settings
|
||||||
@@ -37,12 +38,12 @@ class accountability_category(settings.Channel, settings.GuildSetting):
|
|||||||
return "The accountability system has been started in **{}**.".format(self.value.name)
|
return "The accountability system has been started in **{}**.".format(self.value.name)
|
||||||
else:
|
else:
|
||||||
if self.id in AG.cache:
|
if self.id in AG.cache:
|
||||||
aguild = AG.cache[self.id]
|
aguild = AG.cache.pop(self.id)
|
||||||
if aguild.current_slot:
|
if aguild.current_slot:
|
||||||
aguild.current_lost.cancel()
|
asyncio.create_task(aguild.current_slot.cancel())
|
||||||
if aguild.upcoming_slot:
|
if aguild.upcoming_slot:
|
||||||
aguild.upcoming_slot.cancel()
|
asyncio.create_task(aguild.upcoming_slot.cancel())
|
||||||
return "The accountability system has been stopped."
|
return "The accountability system has been shut down."
|
||||||
else:
|
else:
|
||||||
return "The accountability category has been unset."
|
return "The accountability category has been unset."
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ async def cmd_send(ctx):
|
|||||||
# Extract target and amount
|
# Extract target and amount
|
||||||
# Handle a slightly more flexible input than stated
|
# Handle a slightly more flexible input than stated
|
||||||
splits = ctx.args.split()
|
splits = ctx.args.split()
|
||||||
digits = [split.isdigit() for split in splits]
|
digits = [split.isdigit() for split in splits[:2]]
|
||||||
mentions = ctx.msg.mentions
|
mentions = ctx.msg.mentions
|
||||||
if len(splits) < 2 or not any(digits) or not (all(digits) or mentions):
|
if len(splits) < 2 or not any(digits) or not (all(digits) or mentions):
|
||||||
return await _send_usage(ctx)
|
return await _send_usage(ctx)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import discord
|
import discord
|
||||||
|
from cmdClient.lib import SafeCancellation
|
||||||
|
|
||||||
from wards import guild_admin
|
from wards import guild_admin, guild_moderator
|
||||||
from settings import UserInputError, GuildSettings
|
from settings import UserInputError, GuildSettings
|
||||||
|
|
||||||
from utils.lib import prop_tabulate
|
from utils.lib import prop_tabulate
|
||||||
@@ -26,12 +27,40 @@ descriptions = {
|
|||||||
desc="View and modify the server settings.",
|
desc="View and modify the server settings.",
|
||||||
flags=('add', 'remove'),
|
flags=('add', 'remove'),
|
||||||
group="Guild Configuration")
|
group="Guild Configuration")
|
||||||
@guild_admin()
|
@guild_moderator()
|
||||||
async def cmd_config(ctx, flags):
|
async def cmd_config(ctx, flags):
|
||||||
|
"""
|
||||||
|
Usage``:
|
||||||
|
{prefix}config
|
||||||
|
{prefix}config info
|
||||||
|
{prefix}config <setting>
|
||||||
|
{prefix}config <setting> <value>
|
||||||
|
Description:
|
||||||
|
Display the server configuration panel, and view/modify the server settings.
|
||||||
|
|
||||||
|
Use `{prefix}config` to see the settings with their current values, or `{prefix}config info` to \
|
||||||
|
show brief descriptions instead.
|
||||||
|
Use `{prefix}config <setting>` (e.g. `{prefix}config event_log`) to view a more detailed description for each setting, \
|
||||||
|
including the possible values.
|
||||||
|
Finally, use `{prefix}config <setting> <value>` to set the setting to the given value.
|
||||||
|
To unset a setting, or set it to the default, use `{prefix}config <setting> None`.
|
||||||
|
|
||||||
|
Additional usage for settings which accept a list of values:
|
||||||
|
`{prefix}config <setting> <value1>, <value2>, ...`
|
||||||
|
`{prefix}config <setting> --add <value1>, <value2>, ...`
|
||||||
|
`{prefix}config <setting> --remove <value1>, <value2>, ...`
|
||||||
|
Note that the first form *overwrites* the setting completely,\
|
||||||
|
while the second two will only *add* and *remove* values, respectively.
|
||||||
|
Examples``:
|
||||||
|
{prefix}config event_log
|
||||||
|
{prefix}config event_log {ctx.ch.name}
|
||||||
|
{prefix}config autoroles Member, Level 0, Level 10
|
||||||
|
{prefix}config autoroles --remove Level 10
|
||||||
|
"""
|
||||||
# Cache and map some info for faster access
|
# Cache and map some info for faster access
|
||||||
setting_displaynames = {setting.display_name.lower(): setting for setting in GuildSettings.settings.values()}
|
setting_displaynames = {setting.display_name.lower(): setting for setting in GuildSettings.settings.values()}
|
||||||
|
|
||||||
if not ctx.args or ctx.args.lower() == 'help':
|
if not ctx.args or ctx.args.lower() in ('info', 'help'):
|
||||||
# Fill the setting cats
|
# Fill the setting cats
|
||||||
cats = {}
|
cats = {}
|
||||||
for setting in GuildSettings.settings.values():
|
for setting in GuildSettings.settings.values():
|
||||||
@@ -60,8 +89,14 @@ async def cmd_config(ctx, flags):
|
|||||||
colour=discord.Colour.orange(),
|
colour=discord.Colour.orange(),
|
||||||
title=page_name,
|
title=page_name,
|
||||||
description=(
|
description=(
|
||||||
"View brief setting descriptions with `{prefix}config help`.\n"
|
"View brief setting descriptions with `{prefix}config info`.\n"
|
||||||
"See `{prefix}help config` for more general usage.".format(prefix=ctx.best_prefix)
|
"Use e.g. `{prefix}config event_log` to see more details.\n"
|
||||||
|
"Modify a setting with e.g. `{prefix}config event_log {ctx.ch.name}`.\n"
|
||||||
|
"See the [Online Tutorial]({tutorial}) for a complete setup guide.".format(
|
||||||
|
prefix=ctx.best_prefix,
|
||||||
|
ctx=ctx,
|
||||||
|
tutorial="https://discord.studylions.com/tutorial"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for name, value in page.items():
|
for name, value in page.items():
|
||||||
@@ -71,7 +106,7 @@ async def cmd_config(ctx, flags):
|
|||||||
|
|
||||||
if len(pages) > 1:
|
if len(pages) > 1:
|
||||||
[
|
[
|
||||||
embed.set_footer(text="Page {}/{}".format(i+1, len(pages)))
|
embed.set_footer(text="Page {} of {}".format(i+1, len(pages)))
|
||||||
for i, embed in enumerate(pages)
|
for i, embed in enumerate(pages)
|
||||||
]
|
]
|
||||||
await ctx.pager(pages)
|
await ctx.pager(pages)
|
||||||
@@ -98,9 +133,12 @@ async def cmd_config(ctx, flags):
|
|||||||
await setting.get(ctx.guild.id).widget(ctx, flags=flags)
|
await setting.get(ctx.guild.id).widget(ctx, flags=flags)
|
||||||
else:
|
else:
|
||||||
# config <setting> <value>
|
# config <setting> <value>
|
||||||
|
# Ignoring the write ward currently and just enforcing admin
|
||||||
# Check the write ward
|
# Check the write ward
|
||||||
if not await setting.write_ward.run(ctx):
|
# if not await setting.write_ward.run(ctx):
|
||||||
await ctx.error_reply(setting.write_ward.msg)
|
# raise SafeCancellation(setting.write_ward.msg)
|
||||||
|
if not await guild_admin.run(ctx):
|
||||||
|
raise SafeCancellation("You need to be a server admin to modify settings!")
|
||||||
|
|
||||||
# Attempt to set config setting
|
# Attempt to set config setting
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -732,7 +732,8 @@ async def cmd_reactionroles(ctx, flags):
|
|||||||
|
|
||||||
# Add the reactions to the message, if possible
|
# Add the reactions to the message, if possible
|
||||||
existing_reactions = set(
|
existing_reactions = set(
|
||||||
reaction.emoji.name if reaction.emoji.id is None else reaction.emoji.id
|
reaction.emoji if not reaction.custom_emoji else
|
||||||
|
(reaction.emoji.name if reaction.emoji.id is None else reaction.emoji.id)
|
||||||
for reaction in message.reactions
|
for reaction in message.reactions
|
||||||
)
|
)
|
||||||
missing = [
|
missing = [
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ def schedule_expiry(guildid, userid, roleid, expiry, reactionid=None):
|
|||||||
_wakeup_event.set()
|
_wakeup_event.set()
|
||||||
|
|
||||||
|
|
||||||
def cancel_expiry(key):
|
def cancel_expiry(*key):
|
||||||
"""
|
"""
|
||||||
Cancel expiry for the given member and role, if it exists.
|
Cancel expiry for the given member and role, if it exists.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -546,7 +546,7 @@ class ReactionRoleMessage:
|
|||||||
@client.add_after_event('raw_reaction_add')
|
@client.add_after_event('raw_reaction_add')
|
||||||
async def reaction_role_add(client, payload):
|
async def reaction_role_add(client, payload):
|
||||||
reaction_message = ReactionRoleMessage.fetch(payload.message_id)
|
reaction_message = ReactionRoleMessage.fetch(payload.message_id)
|
||||||
if not payload.member.bot and reaction_message and reaction_message.enabled:
|
if payload.guild_id and not payload.member.bot and reaction_message and reaction_message.enabled:
|
||||||
try:
|
try:
|
||||||
await reaction_message.process_raw_reaction_add(payload)
|
await reaction_message.process_raw_reaction_add(payload)
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -564,7 +564,7 @@ async def reaction_role_add(client, payload):
|
|||||||
@client.add_after_event('raw_reaction_remove')
|
@client.add_after_event('raw_reaction_remove')
|
||||||
async def reaction_role_remove(client, payload):
|
async def reaction_role_remove(client, payload):
|
||||||
reaction_message = ReactionRoleMessage.fetch(payload.message_id)
|
reaction_message = ReactionRoleMessage.fetch(payload.message_id)
|
||||||
if reaction_message and reaction_message.enabled:
|
if payload.guild_id and reaction_message and reaction_message.enabled:
|
||||||
try:
|
try:
|
||||||
await reaction_message.process_raw_reaction_remove(payload)
|
await reaction_message.process_raw_reaction_remove(payload)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|||||||
@@ -42,7 +42,11 @@ bot_admin_group_order = (
|
|||||||
# TODO: Add config fields for this
|
# TODO: Add config fields for this
|
||||||
title = "StudyLion Command List"
|
title = "StudyLion Command List"
|
||||||
header = """
|
header = """
|
||||||
Use `{ctx.best_prefix}help <command>` (e.g. `{ctx.best_prefix}help send`) to see how to use each command.
|
[StudyLion](https://bot.studylions.com/) is a fully featured study assistant \
|
||||||
|
that tracks your study time and offers productivity tools \
|
||||||
|
such as to-do lists, task reminders, private study rooms, group accountability sessions, and much much more.\n
|
||||||
|
Use `{ctx.best_prefix}help <command>` (e.g. `{ctx.best_prefix}help send`) to learn how to use each command, \
|
||||||
|
or [click here](https://discord.studylions.com/tutorial) for a comprehensive tutorial.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
0
bot/modules/plugins/.gitignore
vendored
Normal file
0
bot/modules/plugins/.gitignore
vendored
Normal file
@@ -37,6 +37,15 @@ async def cmd_rent(ctx):
|
|||||||
# Fetch the members' room, if it exists
|
# Fetch the members' room, if it exists
|
||||||
room = Room.fetch(ctx.guild.id, ctx.author.id)
|
room = Room.fetch(ctx.guild.id, ctx.author.id)
|
||||||
|
|
||||||
|
# Handle pre-deletion of the room
|
||||||
|
if room and not room.channel:
|
||||||
|
ctx.guild_settings.event_log.log(
|
||||||
|
title="Private study room not found!",
|
||||||
|
description="{}'s study room was deleted before it expired!".format(ctx.author.mention)
|
||||||
|
)
|
||||||
|
room.delete()
|
||||||
|
room = None
|
||||||
|
|
||||||
if room:
|
if room:
|
||||||
# Show room status, or add/remove remebers
|
# Show room status, or add/remove remebers
|
||||||
lower = ctx.args.lower()
|
lower = ctx.args.lower()
|
||||||
|
|||||||
@@ -112,7 +112,8 @@ class Room:
|
|||||||
@property
|
@property
|
||||||
def owner(self):
|
def owner(self):
|
||||||
"""
|
"""
|
||||||
The Member owning the room, if we can find them
|
The Member owning the room.
|
||||||
|
May be `None` if the member is no longer in the guild, or is otherwise not visible.
|
||||||
"""
|
"""
|
||||||
guild = client.get_guild(self.data.guildid)
|
guild = client.get_guild(self.data.guildid)
|
||||||
if guild:
|
if guild:
|
||||||
@@ -122,6 +123,7 @@ class Room:
|
|||||||
def channel(self):
|
def channel(self):
|
||||||
"""
|
"""
|
||||||
The Channel corresponding to this rented room.
|
The Channel corresponding to this rented room.
|
||||||
|
May be `None` if the channel was already deleted.
|
||||||
"""
|
"""
|
||||||
guild = client.get_guild(self.data.guildid)
|
guild = client.get_guild(self.data.guildid)
|
||||||
if guild:
|
if guild:
|
||||||
@@ -176,9 +178,6 @@ class Room:
|
|||||||
"""
|
"""
|
||||||
Expire the room.
|
Expire the room.
|
||||||
"""
|
"""
|
||||||
owner = self.owner
|
|
||||||
guild_settings = GuildSettings(owner.guild.id)
|
|
||||||
|
|
||||||
if self.channel:
|
if self.channel:
|
||||||
# Delete the discord channel
|
# Delete the discord channel
|
||||||
try:
|
try:
|
||||||
@@ -189,9 +188,10 @@ class Room:
|
|||||||
# Delete the room from data (cascades to member deletion)
|
# Delete the room from data (cascades to member deletion)
|
||||||
self.delete()
|
self.delete()
|
||||||
|
|
||||||
|
guild_settings = GuildSettings(self.data.guildid)
|
||||||
guild_settings.event_log.log(
|
guild_settings.event_log.log(
|
||||||
title="Private study room expired!",
|
title="Private study room expired!",
|
||||||
description="{}'s private study room expired.".format(owner.mention)
|
description="<@{}>'s private study room expired.".format(self.data.ownerid)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def add_members(self, *members):
|
async def add_members(self, *members):
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
import asyncio
|
import asyncio
|
||||||
import itertools
|
import itertools
|
||||||
|
import traceback
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
@@ -753,11 +754,19 @@ class Message(SettingType):
|
|||||||
if as_json:
|
if as_json:
|
||||||
try:
|
try:
|
||||||
args = json.loads(userstr)
|
args = json.loads(userstr)
|
||||||
except json.JSONDecodeError:
|
if not isinstance(args, dict) or (not args.get('content', None) and not args.get('embed', None)):
|
||||||
|
raise ValueError("At least one of the 'content' or 'embed' data fields are required.")
|
||||||
|
if 'embed' in args:
|
||||||
|
discord.Embed.from_dict(
|
||||||
|
args['embed']
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
only_error = "".join(traceback.TracebackException.from_exception(e).format_exception_only())
|
||||||
raise UserInputError(
|
raise UserInputError(
|
||||||
"Couldn't parse your message! "
|
"Couldn't parse your message! "
|
||||||
"You can test and fix it on the embed builder "
|
"You can test and fix it on the embed builder "
|
||||||
"[here](https://glitchii.github.io/embedbuilder/?editor=json)."
|
"[here](https://glitchii.github.io/embedbuilder/?editor=json).\n"
|
||||||
|
"```{}```".format(only_error)
|
||||||
)
|
)
|
||||||
if 'embed' in args and 'timestamp' in args['embed']:
|
if 'embed' in args and 'timestamp' in args['embed']:
|
||||||
args['embed'].pop('timestamp')
|
args['embed'].pop('timestamp')
|
||||||
@@ -770,6 +779,8 @@ class Message(SettingType):
|
|||||||
if data is None:
|
if data is None:
|
||||||
return "Empty"
|
return "Empty"
|
||||||
value = cls._data_to_value(id, data, **kwargs)
|
value = cls._data_to_value(id, data, **kwargs)
|
||||||
|
if 'embed' not in value and 'content' not in value:
|
||||||
|
return "Invalid"
|
||||||
if 'embed' not in value and len(value['content']) < 100:
|
if 'embed' not in value and len(value['content']) < 100:
|
||||||
return "`{}`".format(value['content'])
|
return "`{}`".format(value['content'])
|
||||||
else:
|
else:
|
||||||
@@ -788,9 +799,9 @@ class Message(SettingType):
|
|||||||
value = self.value
|
value = self.value
|
||||||
substitutions = self.substitution_keys(ctx, **kwargs)
|
substitutions = self.substitution_keys(ctx, **kwargs)
|
||||||
args = {}
|
args = {}
|
||||||
if 'content' in value:
|
if value.get('content', None):
|
||||||
args['content'] = multiple_replace(value['content'], substitutions)
|
args['content'] = multiple_replace(value['content'], substitutions)
|
||||||
if 'embed' in value:
|
if value.get('embed', None):
|
||||||
args['embed'] = discord.Embed.from_dict(
|
args['embed'] = discord.Embed.from_dict(
|
||||||
json.loads(multiple_replace(json.dumps(value['embed']), substitutions))
|
json.loads(multiple_replace(json.dumps(value['embed']), substitutions))
|
||||||
)
|
)
|
||||||
@@ -800,7 +811,7 @@ class Message(SettingType):
|
|||||||
value = self.value
|
value = self.value
|
||||||
args = self.args(ctx, **kwargs)
|
args = self.args(ctx, **kwargs)
|
||||||
|
|
||||||
if not value:
|
if not value or not args:
|
||||||
return await ctx.reply(embed=self.embed)
|
return await ctx.reply(embed=self.embed)
|
||||||
|
|
||||||
current_str = None
|
current_str = None
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import discord
|
import discord
|
||||||
from cmdClient import Context
|
from cmdClient import Context
|
||||||
|
from cmdClient.lib import SafeCancellation
|
||||||
|
|
||||||
from data import tables
|
from data import tables
|
||||||
from core import Lion
|
from core import Lion
|
||||||
@@ -17,9 +18,11 @@ async def embed_reply(ctx, desc, colour=discord.Colour.orange(), **kwargs):
|
|||||||
"""
|
"""
|
||||||
embed = discord.Embed(description=desc, colour=colour, **kwargs)
|
embed = discord.Embed(description=desc, colour=colour, **kwargs)
|
||||||
try:
|
try:
|
||||||
return await ctx.reply(embed=embed, reference=ctx.msg)
|
return await ctx.reply(embed=embed, reference=ctx.msg.to_reference(fail_if_not_exists=False))
|
||||||
except discord.NotFound:
|
except discord.Forbidden:
|
||||||
return await ctx.reply(embed=embed)
|
if not ctx.guild or ctx.ch.permissions_for(ctx.guild.me).send_mssages:
|
||||||
|
await ctx.reply("Command failed, I don't have permission to send embeds in this channel!")
|
||||||
|
raise SafeCancellation
|
||||||
|
|
||||||
|
|
||||||
@Context.util
|
@Context.util
|
||||||
@@ -34,15 +37,17 @@ async def error_reply(ctx, error_str, **kwargs):
|
|||||||
)
|
)
|
||||||
message = None
|
message = None
|
||||||
try:
|
try:
|
||||||
message = await ctx.ch.send(embed=embed, reference=ctx.msg, **kwargs)
|
message = await ctx.ch.send(
|
||||||
except discord.NotFound:
|
embed=embed,
|
||||||
message = await ctx.ch.send(embed=embed, **kwargs)
|
reference=ctx.msg.to_reference(fail_if_not_exists=False),
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
ctx.sent_messages.append(message)
|
||||||
|
return message
|
||||||
except discord.Forbidden:
|
except discord.Forbidden:
|
||||||
message = await ctx.reply(error_str)
|
if not ctx.guild or ctx.ch.permissions_for(ctx.guild.me).send_mssages:
|
||||||
finally:
|
await ctx.reply("Command failed, I don't have permission to send embeds in this channel!")
|
||||||
if message:
|
raise SafeCancellation
|
||||||
ctx.sent_messages.append(message)
|
|
||||||
return message
|
|
||||||
|
|
||||||
|
|
||||||
@Context.util
|
@Context.util
|
||||||
|
|||||||
Reference in New Issue
Block a user