mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 11:18:54 -05:00
[V3] Warning system (#1173)
* [V3 Warning] initial work on a warning system for v3 * [V3 Warning] rename some stuff and add a case type * [V3 Warnings] rename package from warning * [V3 Warnings] restructuring commands * [V3 Warnings] remove expiry stuff + other refactoring * [V3 Warnings] refactoring action logic * [V3 Warnings] rewrites to action logic * [V3 Warnings] add regen_messages.py
This commit is contained in:
parent
21de95e0a6
commit
c1ac78eea4
5
redbot/cogs/warnings/__init__.py
Normal file
5
redbot/cogs/warnings/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from .warnings import Warnings
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Warnings(bot))
|
||||||
142
redbot/cogs/warnings/helpers.py
Normal file
142
redbot/cogs/warnings/helpers.py
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
from copy import copy
|
||||||
|
from discord.ext import commands
|
||||||
|
import asyncio
|
||||||
|
import inspect
|
||||||
|
import discord
|
||||||
|
|
||||||
|
from redbot.core import RedContext, Config, checks
|
||||||
|
from redbot.core.i18n import CogI18n
|
||||||
|
|
||||||
|
_ = CogI18n("Warnings", __file__)
|
||||||
|
|
||||||
|
|
||||||
|
async def warning_points_add_check(config: Config, ctx: RedContext, user: discord.Member, points: int):
|
||||||
|
"""Handles any action that needs to be taken or not based on the points"""
|
||||||
|
guild = ctx.guild
|
||||||
|
guild_settings = config.guild(guild)
|
||||||
|
act = {}
|
||||||
|
async with guild_settings.actions() as registered_actions:
|
||||||
|
for a in registered_actions.keys():
|
||||||
|
if points >= registered_actions[a]["point_count"]:
|
||||||
|
act = registered_actions[a]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if act: # some action needs to be taken
|
||||||
|
await create_and_invoke_context(ctx, act["exceed_command"], user)
|
||||||
|
|
||||||
|
|
||||||
|
async def warning_points_remove_check(config: Config, ctx: RedContext, user: discord.Member, points: int):
|
||||||
|
guild = ctx.guild
|
||||||
|
guild_settings = config.guild(guild)
|
||||||
|
act = {}
|
||||||
|
async with guild_settings.actions() as registered_actions:
|
||||||
|
for a in registered_actions.keys():
|
||||||
|
if points >= registered_actions[a]["point_count"]:
|
||||||
|
act = registered_actions[a]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if act: # some action needs to be taken
|
||||||
|
await create_and_invoke_context(ctx, act["drop_command"], user)
|
||||||
|
|
||||||
|
|
||||||
|
async def create_and_invoke_context(realctx: RedContext, command_str: str, user: discord.Member):
|
||||||
|
m = copy(realctx.message)
|
||||||
|
m.content = command_str.format(user=user.mention, prefix=realctx.prefix)
|
||||||
|
fctx = await realctx.bot.get_context(m, cls=RedContext)
|
||||||
|
try:
|
||||||
|
await realctx.bot.invoke(fctx)
|
||||||
|
except (commands.CheckFailure, commands.CommandOnCooldown):
|
||||||
|
await fctx.reinvoke()
|
||||||
|
|
||||||
|
|
||||||
|
def get_command_from_input(bot, userinput: str):
|
||||||
|
com = None
|
||||||
|
orig = userinput
|
||||||
|
while com is None:
|
||||||
|
com = bot.get_command(userinput)
|
||||||
|
if com is None:
|
||||||
|
userinput = ' '.join(userinput.split(' ')[:-1])
|
||||||
|
if len(userinput) == 0:
|
||||||
|
break
|
||||||
|
if com is None:
|
||||||
|
return None, _("I could not find a command from that input!")
|
||||||
|
|
||||||
|
check_str = inspect.getsource(checks.is_owner)
|
||||||
|
if any(inspect.getsource(x) in check_str for x in com.checks):
|
||||||
|
# command the user specified has the is_owner check
|
||||||
|
return None, _("That command requires bot owner. I can't "
|
||||||
|
"allow you to use that for an action")
|
||||||
|
return "{prefix}" + orig, None
|
||||||
|
|
||||||
|
|
||||||
|
async def get_command_for_exceeded_points(ctx: RedContext):
|
||||||
|
"""Gets the command to be executed when the user is at or exceeding
|
||||||
|
the points threshold for the action"""
|
||||||
|
await ctx.send(
|
||||||
|
_("Enter the command to be run when the user exceeds the points for "
|
||||||
|
"this action to occur.\nEnter it exactly as you would if you were "
|
||||||
|
"actually trying to run the command, except don't put a prefix and "
|
||||||
|
"use {user} in place of any user/member arguments\n\n"
|
||||||
|
"WARNING: The command entered will be run without regard to checks or cooldowns. "
|
||||||
|
"Commands requiring bot owner are not allowed for security reasons.\n\n"
|
||||||
|
"Please wait 15 seconds before entering your response.")
|
||||||
|
)
|
||||||
|
await asyncio.sleep(15)
|
||||||
|
|
||||||
|
await ctx.send(_("You may enter your response now."))
|
||||||
|
|
||||||
|
def same_author_check(m):
|
||||||
|
return m.author == ctx.author
|
||||||
|
|
||||||
|
try:
|
||||||
|
msg = await ctx.bot.wait_for("message", check=same_author_check, timeout=30)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await ctx.send(_("Ok then."))
|
||||||
|
return None
|
||||||
|
|
||||||
|
command, m = get_command_from_input(ctx.bot, msg.content)
|
||||||
|
if command is None:
|
||||||
|
await ctx.send(m)
|
||||||
|
return None
|
||||||
|
|
||||||
|
return command
|
||||||
|
|
||||||
|
|
||||||
|
async def get_command_for_dropping_points(ctx: RedContext):
|
||||||
|
"""
|
||||||
|
Gets the command to be executed when the user drops below the points
|
||||||
|
threshold
|
||||||
|
|
||||||
|
This is intended to be used for reversal of the action that was executed
|
||||||
|
when the user exceeded the threshold
|
||||||
|
"""
|
||||||
|
await ctx.send(
|
||||||
|
_("Enter the command to be run when the user returns to a value below "
|
||||||
|
"the points for this action to occur. Please note that this is "
|
||||||
|
"intended to be used for reversal of the action taken when the user "
|
||||||
|
"exceeded the action's point value\nEnter it exactly as you would "
|
||||||
|
"if you were actually trying to run the command, except don't put a prefix "
|
||||||
|
"and use {user} in place of any user/member arguments\n\n"
|
||||||
|
"WARNING: The command entered will be run without regard to checks or cooldowns. "
|
||||||
|
"Commands requiring bot owner are not allowed for security reasons.\n\n"
|
||||||
|
"Please wait 15 seconds before entering your response.")
|
||||||
|
)
|
||||||
|
await asyncio.sleep(15)
|
||||||
|
|
||||||
|
await ctx.send(_("You may enter your response now."))
|
||||||
|
|
||||||
|
def same_author_check(m):
|
||||||
|
return m.author == ctx.author
|
||||||
|
|
||||||
|
try:
|
||||||
|
msg = await ctx.bot.wait_for("message", check=same_author_check, timeout=30)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await ctx.send(_("Ok then."))
|
||||||
|
return None
|
||||||
|
|
||||||
|
command, m = get_command_from_input(ctx.bot, msg.content)
|
||||||
|
if command is None:
|
||||||
|
await ctx.send(m)
|
||||||
|
return None
|
||||||
|
|
||||||
|
return command
|
||||||
117
redbot/cogs/warnings/locales/messages.pot
Normal file
117
redbot/cogs/warnings/locales/messages.pot
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR ORGANIZATION
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"POT-Creation-Date: 2018-02-25 17:26+AKST\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=CHARSET\n"
|
||||||
|
"Content-Transfer-Encoding: ENCODING\n"
|
||||||
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
|
|
||||||
|
|
||||||
|
#: ../helpers.py:62
|
||||||
|
msgid "I could not find a command from that input!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../helpers.py:67
|
||||||
|
msgid "That command requires bot owner. I can't allow you to use that for an action"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../helpers.py:76
|
||||||
|
msgid ""
|
||||||
|
"Enter the command to be run when the user exceeds the points for this action to occur.\n"
|
||||||
|
"Enter it exactly as you would if you were actually trying to run the command, except don't put a prefix and use {user} in place of any user/member arguments\n"
|
||||||
|
"\n"
|
||||||
|
"WARNING: The command entered will be run without regard to checks or cooldowns. Commands requiring bot owner are not allowed for security reasons.\n"
|
||||||
|
"\n"
|
||||||
|
"Please wait 15 seconds before entering your response."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../helpers.py:86 ../helpers.py:126
|
||||||
|
msgid "You may enter your response now."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../helpers.py:94 ../helpers.py:134
|
||||||
|
msgid "Ok then."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../helpers.py:114
|
||||||
|
msgid ""
|
||||||
|
"Enter the command to be run when the user returns to a value below the points for this action to occur. Please note that this is intended to be used for reversal of the action taken when the user exceeded the action's point value\n"
|
||||||
|
"Enter it exactly as you would if you were actually trying to run the command, except don't put a prefix and use {user} in place of any user/member arguments\n"
|
||||||
|
"\n"
|
||||||
|
"WARNING: The command entered will be run without regard to checks or cooldowns. Commands requiring bot owner are not allowed for security reasons.\n"
|
||||||
|
"\n"
|
||||||
|
"Please wait 15 seconds before entering your response."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:66
|
||||||
|
msgid "Custom reasons have been {}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:66
|
||||||
|
msgid "disabled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:66
|
||||||
|
msgid "enabled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:92 ../warnings.py:351 ../warnings.py:368
|
||||||
|
msgid "Ok then"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:117
|
||||||
|
msgid "Duplicate action name found!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:171
|
||||||
|
msgid "That reason has been registered"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:181
|
||||||
|
msgid "Removed reason {}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:183
|
||||||
|
msgid "That is not a registered reason name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:230
|
||||||
|
msgid "Custom reasons are not allowed! Please see {} for a complete list of valid reasons"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:243
|
||||||
|
msgid "That is not a registered reason!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:277
|
||||||
|
msgid "You are not allowed to check warnings for other users!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:290
|
||||||
|
msgid "That user has no warnings!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:347
|
||||||
|
msgid "How many points should be given for this reason?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:356
|
||||||
|
msgid "That isn't a number!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:360
|
||||||
|
msgid "The point value needs to be greater than 0!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../warnings.py:364
|
||||||
|
msgid "Enter a description for this reason"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
16
redbot/cogs/warnings/locales/regen_messages.py
Normal file
16
redbot/cogs/warnings/locales/regen_messages.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import subprocess
|
||||||
|
|
||||||
|
TO_TRANSLATE = [
|
||||||
|
'../warnings.py',
|
||||||
|
'../helpers.py'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def regen_messages():
|
||||||
|
subprocess.run(
|
||||||
|
['pygettext', '-n'] + TO_TRANSLATE
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
regen_messages()
|
||||||
371
redbot/cogs/warnings/warnings.py
Normal file
371
redbot/cogs/warnings/warnings.py
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
from discord.ext import commands
|
||||||
|
import discord
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from redbot.cogs.warnings.helpers import warning_points_add_check, get_command_for_exceeded_points, \
|
||||||
|
get_command_for_dropping_points, warning_points_remove_check
|
||||||
|
from redbot.core import Config, modlog, checks
|
||||||
|
from redbot.core.bot import Red
|
||||||
|
from redbot.core.context import RedContext
|
||||||
|
from redbot.core.i18n import CogI18n
|
||||||
|
from redbot.core.utils.mod import is_admin_or_superior
|
||||||
|
from redbot.core.utils.chat_formatting import warning, pagify
|
||||||
|
|
||||||
|
_ = CogI18n("Warnings", __file__)
|
||||||
|
|
||||||
|
|
||||||
|
class Warnings:
|
||||||
|
"""A warning system for Red"""
|
||||||
|
|
||||||
|
default_guild = {
|
||||||
|
"actions": [],
|
||||||
|
"reasons": {},
|
||||||
|
"allow_custom_reasons": False
|
||||||
|
}
|
||||||
|
|
||||||
|
default_member = {
|
||||||
|
"total_points": 0,
|
||||||
|
"status": "",
|
||||||
|
"warnings": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, bot: Red):
|
||||||
|
self.config = Config.get_conf(self, identifier=5757575755)
|
||||||
|
self.config.register_guild(**self.default_guild)
|
||||||
|
self.config.register_member(**self.default_member)
|
||||||
|
self.bot = bot
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.create_task(self.register_warningtype())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def register_warningtype():
|
||||||
|
try:
|
||||||
|
await modlog.register_casetype(
|
||||||
|
"warning", True, "\N{WARNING SIGN}", "Warning", None
|
||||||
|
)
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@commands.group()
|
||||||
|
@commands.guild_only()
|
||||||
|
@checks.guildowner_or_permissions(administrator=True)
|
||||||
|
async def warningset(self, ctx: RedContext):
|
||||||
|
"""Warning settings"""
|
||||||
|
if ctx.invoked_subcommand is None:
|
||||||
|
await ctx.send_help()
|
||||||
|
|
||||||
|
@warningset.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
async def allowcustomreasons(self, ctx: RedContext, allowed: bool):
|
||||||
|
"""Allow or disallow custom reasons for a warning"""
|
||||||
|
guild = ctx.guild
|
||||||
|
await self.config.guild(guild).allow_custom_reasons.set(allowed)
|
||||||
|
await ctx.send(
|
||||||
|
_("Custom reasons have been {}").format(_("enabled") if allowed else _("disabled"))
|
||||||
|
)
|
||||||
|
|
||||||
|
@commands.group()
|
||||||
|
@commands.guild_only()
|
||||||
|
@checks.guildowner_or_permissions(administrator=True)
|
||||||
|
async def warnaction(self, ctx: RedContext):
|
||||||
|
"""Action management"""
|
||||||
|
if ctx.invoked_subcommand is None:
|
||||||
|
await ctx.send_help()
|
||||||
|
|
||||||
|
@warnaction.command(name="add")
|
||||||
|
@commands.guild_only()
|
||||||
|
async def action_add(self, ctx: RedContext, name: str, points: int):
|
||||||
|
"""Create an action to be taken at a specified point count
|
||||||
|
Duplicate action names are not allowed"""
|
||||||
|
guild = ctx.guild
|
||||||
|
|
||||||
|
await ctx.send("Would you like to enter commands to be run? (y/n)")
|
||||||
|
|
||||||
|
def same_author_check(m):
|
||||||
|
return m.author == ctx.author
|
||||||
|
|
||||||
|
try:
|
||||||
|
msg = await ctx.bot.wait_for("message", check=same_author_check, timeout=30)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await ctx.send(_("Ok then"))
|
||||||
|
return
|
||||||
|
|
||||||
|
if msg.content.lower() == "y":
|
||||||
|
exceed_command = await get_command_for_exceeded_points(ctx)
|
||||||
|
if exceed_command is None:
|
||||||
|
return
|
||||||
|
drop_command = await get_command_for_dropping_points(ctx)
|
||||||
|
if drop_command is None:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
exceed_command = None
|
||||||
|
drop_command = None
|
||||||
|
to_add = {
|
||||||
|
"action_name": name,
|
||||||
|
"points": points,
|
||||||
|
"exceed_command": exceed_command,
|
||||||
|
"drop_command": drop_command
|
||||||
|
}
|
||||||
|
|
||||||
|
# Have all details for the action, now save the action
|
||||||
|
guild_settings = self.config.guild(guild)
|
||||||
|
async with guild_settings.actions() as registered_actions:
|
||||||
|
for act in registered_actions:
|
||||||
|
if act["action_name"] == to_add["action_name"]:
|
||||||
|
await ctx.send(_("Duplicate action name found!"))
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
registered_actions.append(to_add)
|
||||||
|
# Sort in descending order by point count for ease in
|
||||||
|
# finding the highest possible action to take
|
||||||
|
registered_actions.sort(key=lambda a: a["point_count"], reverse=True)
|
||||||
|
await ctx.tick()
|
||||||
|
|
||||||
|
@warnaction.command(name="del")
|
||||||
|
@commands.guild_only()
|
||||||
|
async def action_del(self, ctx: RedContext, action_name: str):
|
||||||
|
"""Delete the point count action with the specified name"""
|
||||||
|
guild = ctx.guild
|
||||||
|
guild_settings = self.config.guild(guild)
|
||||||
|
async with guild_settings.actions() as registered_actions:
|
||||||
|
to_remove = None
|
||||||
|
for act in registered_actions:
|
||||||
|
if act["action_name"] == action_name:
|
||||||
|
to_remove = act
|
||||||
|
break
|
||||||
|
if to_remove:
|
||||||
|
registered_actions.remove(to_remove)
|
||||||
|
|
||||||
|
@commands.group()
|
||||||
|
@commands.guild_only()
|
||||||
|
@checks.guildowner_or_permissions(administrator=True)
|
||||||
|
async def warnreason(self, ctx: RedContext):
|
||||||
|
"""Add reasons for warnings"""
|
||||||
|
if ctx.invoked_subcommand is None:
|
||||||
|
await ctx.send_help()
|
||||||
|
|
||||||
|
@warnreason.command(name="add")
|
||||||
|
@commands.guild_only()
|
||||||
|
async def reason_add(self, ctx: RedContext, name: str, points: int, *, description: str):
|
||||||
|
"""Add a reason to be available for warnings"""
|
||||||
|
guild = ctx.guild
|
||||||
|
|
||||||
|
if name.lower() == "custom":
|
||||||
|
await ctx.send("That cannot be used as a reason name!")
|
||||||
|
return
|
||||||
|
to_add = {
|
||||||
|
"points": points,
|
||||||
|
"description": description
|
||||||
|
}
|
||||||
|
completed = {
|
||||||
|
name.lower(): to_add
|
||||||
|
}
|
||||||
|
|
||||||
|
guild_settings = self.config.guild(guild)
|
||||||
|
|
||||||
|
async with guild_settings.reasons() as registered_reasons:
|
||||||
|
registered_reasons.update(completed)
|
||||||
|
|
||||||
|
await ctx.send(_("That reason has been registered"))
|
||||||
|
|
||||||
|
@warnreason.command(name="del")
|
||||||
|
@commands.guild_only()
|
||||||
|
async def reason_del(self, ctx: RedContext, reason_name: str):
|
||||||
|
"""Delete the reason with the specified name"""
|
||||||
|
guild = ctx.guild
|
||||||
|
guild_settings = self.config.guild(guild)
|
||||||
|
async with guild_settings.reasons() as registered_reasons:
|
||||||
|
if registered_reasons.pop(reason_name.lower(), None):
|
||||||
|
await ctx.send(_("Removed reason {}").format(reason_name))
|
||||||
|
else:
|
||||||
|
await ctx.send(_("That is not a registered reason name"))
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
@checks.admin_or_permissions(ban_members=True)
|
||||||
|
async def reasonlist(self, ctx: RedContext):
|
||||||
|
"""List all configured reasons for warnings"""
|
||||||
|
guild = ctx.guild
|
||||||
|
guild_settings = self.config.guild(guild)
|
||||||
|
msg_list = []
|
||||||
|
async with guild_settings.reasons() as registered_reasons:
|
||||||
|
for r in registered_reasons.keys():
|
||||||
|
msg_list.append(
|
||||||
|
"Name: {}\nPoints: {}\nAction: {}".format(
|
||||||
|
r, r["points"], r["action"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await ctx.send_interactive(msg_list)
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
@checks.admin_or_permissions(ban_members=True)
|
||||||
|
async def actionlist(self, ctx: RedContext):
|
||||||
|
"""List the actions to be taken at specific point values"""
|
||||||
|
guild = ctx.guild
|
||||||
|
guild_settings = self.config.guild(guild)
|
||||||
|
msg_list = []
|
||||||
|
async with guild_settings.actions() as registered_actions:
|
||||||
|
for r in registered_actions.keys():
|
||||||
|
msg_list.append(
|
||||||
|
"Name: {}\nPoints: {}\nDescription: {}".format(
|
||||||
|
r, r["points"], r["description"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await ctx.send_interactive(msg_list)
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
@checks.admin_or_permissions(ban_members=True)
|
||||||
|
async def warn(self, ctx: RedContext, user: discord.Member, reason: str):
|
||||||
|
"""Warn the user for the specified reason
|
||||||
|
Reason must be a registered reason, or custom if custom reasons are allowed"""
|
||||||
|
reason_type = {}
|
||||||
|
if reason.lower() == "custom":
|
||||||
|
custom_allowed = await self.config.guild(ctx.guild).allow_custom_reasons()
|
||||||
|
if not custom_allowed:
|
||||||
|
await ctx.send(
|
||||||
|
_(
|
||||||
|
"Custom reasons are not allowed! Please see {} for "
|
||||||
|
"a complete list of valid reasons"
|
||||||
|
).format(
|
||||||
|
"`{}reasonlist`".format(ctx.prefix)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
reason_type = await self.custom_warning_reason(ctx)
|
||||||
|
else:
|
||||||
|
guild_settings = self.config.guild(ctx.guild)
|
||||||
|
async with guild_settings.reasons() as registered_reasons:
|
||||||
|
if reason.lower() not in registered_reasons:
|
||||||
|
await ctx.send(_("That is not a registered reason!"))
|
||||||
|
else:
|
||||||
|
reason_type = registered_reasons[reason.lower()]
|
||||||
|
|
||||||
|
member_settings = self.config.member(user)
|
||||||
|
current_point_count = await member_settings.total_points()
|
||||||
|
warning_to_add = {
|
||||||
|
str(ctx.message.id): {
|
||||||
|
"points": reason_type["points"],
|
||||||
|
"description": reason_type["description"],
|
||||||
|
"mod": ctx.author.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async with member_settings.warnings() as user_warnings:
|
||||||
|
user_warnings.update(warning_to_add)
|
||||||
|
current_point_count += reason_type["points"]
|
||||||
|
await member_settings.total_points.set(current_point_count)
|
||||||
|
|
||||||
|
await warning_points_add_check(self.config, ctx, user, current_point_count)
|
||||||
|
await ctx.tick()
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
async def warnings(self, ctx: RedContext, userid: int=None):
|
||||||
|
"""Show warnings for the specified user.
|
||||||
|
If userid is None, show warnings for the person running the command
|
||||||
|
Note that showing warnings for users other than yourself requires
|
||||||
|
appropriate permissions"""
|
||||||
|
if userid is None:
|
||||||
|
user = ctx.author
|
||||||
|
else:
|
||||||
|
if not is_admin_or_superior(self.bot, ctx.author):
|
||||||
|
await ctx.send(
|
||||||
|
warning(
|
||||||
|
_("You are not allowed to check "
|
||||||
|
"warnings for other users!")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
user = ctx.guild.get_member(userid)
|
||||||
|
if user is None: # user not in guild
|
||||||
|
user = namedtuple("Member", "id guild")(userid, ctx.guild)
|
||||||
|
msg = ""
|
||||||
|
member_settings = self.config.member(user)
|
||||||
|
async with member_settings.warnings() as user_warnings:
|
||||||
|
if not user_warnings.keys(): # no warnings for the user
|
||||||
|
await ctx.send(_("That user has no warnings!"))
|
||||||
|
else:
|
||||||
|
for key in user_warnings.keys():
|
||||||
|
mod = ctx.guild.get_member(user_warnings[key]["mod"])
|
||||||
|
if mod is None:
|
||||||
|
mod = discord.utils.get(
|
||||||
|
self.bot.get_all_members(),
|
||||||
|
id=user_warnings[key]["mod"]
|
||||||
|
)
|
||||||
|
if mod is None:
|
||||||
|
mod = await self.bot.get_user_info(
|
||||||
|
user_warnings[key]["mod"]
|
||||||
|
)
|
||||||
|
msg += "{} point warning {} issued by {} for {}\n".format(
|
||||||
|
user_warnings[key]["points"],
|
||||||
|
key,
|
||||||
|
mod,
|
||||||
|
user_warnings[key]["description"]
|
||||||
|
)
|
||||||
|
await ctx.send_interactive(
|
||||||
|
pagify(msg), box_lang="Warnings for {}".format(user)
|
||||||
|
)
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
@checks.admin_or_permissions(ban_members=True)
|
||||||
|
async def unwarn(self, ctx: RedContext, user_id: int, warn_id: str):
|
||||||
|
"""Removes the specified warning from the user specified"""
|
||||||
|
guild = ctx.guild
|
||||||
|
member = guild.get_member(user_id)
|
||||||
|
if member is None: # no longer in guild, but need a "member" object
|
||||||
|
member = namedtuple("Member", "guild id")(guild, user_id)
|
||||||
|
member_settings = self.config.member(member)
|
||||||
|
|
||||||
|
current_point_count = await member_settings.total_points()
|
||||||
|
await warning_points_remove_check(self.config, ctx, member, current_point_count)
|
||||||
|
async with member_settings.warnings() as user_warnings:
|
||||||
|
if warn_id not in user_warnings.keys():
|
||||||
|
await ctx.send("That warning doesn't exist!")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
current_point_count -= user_warnings[warn_id]["points"]
|
||||||
|
await member_settings.total_points.set(current_point_count)
|
||||||
|
user_warnings.pop(warn_id)
|
||||||
|
await ctx.tick()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def custom_warning_reason(ctx: RedContext):
|
||||||
|
"""Handles getting description and points for custom reasons"""
|
||||||
|
to_add = {
|
||||||
|
"points": 0,
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
def same_author_check(m):
|
||||||
|
return m.author == ctx.author
|
||||||
|
|
||||||
|
await ctx.send(_("How many points should be given for this reason?"))
|
||||||
|
try:
|
||||||
|
msg = await ctx.bot.wait_for("message", check=same_author_check, timeout=30)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await ctx.send(_("Ok then"))
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
int(msg.content)
|
||||||
|
except ValueError:
|
||||||
|
await ctx.send(_("That isn't a number!"))
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if int(msg.content) <= 0:
|
||||||
|
await ctx.send(_("The point value needs to be greater than 0!"))
|
||||||
|
return
|
||||||
|
to_add["points"] = int(msg.content)
|
||||||
|
|
||||||
|
await ctx.send(_("Enter a description for this reason"))
|
||||||
|
try:
|
||||||
|
msg = await ctx.bot.wait_for("message", check=same_author_check, timeout=30)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await ctx.send(_("Ok then"))
|
||||||
|
return
|
||||||
|
to_add["description"] = msg.content
|
||||||
|
return to_add
|
||||||
Loading…
x
Reference in New Issue
Block a user