[Docs] Warnings Cog Guide (#4920)

* Initial commit

* labeler and index

* change parameter names and labeler

* fix typo

* docstrings, quotes and improved names

* merge conflict affect fixes

* remove aliases

* get from v3/develop

* update var names

* fixes

* improve grammar

* black
This commit is contained in:
Kreusada 2021-05-28 18:06:52 +01:00 committed by GitHub
parent db86de3a7a
commit b630e71d08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 433 additions and 32 deletions

3
.github/labeler.yml vendored
View File

@ -177,4 +177,7 @@
# Docs # Docs
- docs/framework_utils.rst - docs/framework_utils.rst
"Category: Warnings": "Category: Warnings":
# Source
- redbot/cogs/warnings/* - redbot/cogs/warnings/*
# Docs
- docs/cog_guides/warnings.rst

View File

@ -0,0 +1,403 @@
.. _warnings:
========
Warnings
========
This is the cog guide for the warnings cog. You will
find detailed docs about usage and commands.
``[p]`` is considered as your prefix.
.. note:: To use this cog, load it by typing this::
[p]load warnings
.. _warnings-usage:
-----
Usage
-----
Warn misbehaving users and take automated actions.
.. _warnings-commands:
--------
Commands
--------
.. _warnings-command-actionlist:
^^^^^^^^^^
actionlist
^^^^^^^^^^
.. note:: |admin-lock|
**Syntax**
.. code-block:: none
[p]actionlist
**Description**
List all configured automated actions for Warnings.
.. _warnings-command-mywarnings:
^^^^^^^^^^
mywarnings
^^^^^^^^^^
**Syntax**
.. code-block:: none
[p]mywarnings
**Description**
List warnings for yourself.
.. _warnings-command-reasonlist:
^^^^^^^^^^
reasonlist
^^^^^^^^^^
.. note:: |admin-lock|
**Syntax**
.. code-block:: none
[p]reasonlist
**Description**
List all configured reasons for Warnings.
.. _warnings-command-unwarn:
^^^^^^
unwarn
^^^^^^
.. note:: |admin-lock|
**Syntax**
.. code-block:: none
[p]unwarn <member> <warn_id> [reason]
**Description**
Remove a warning from a member.
**Arguments**
* ``<member>``: The member to remove the warning from. |member-input-quotes|
* ``<warn_id>``: The warning ID to remove from the member.
* ``[reason]``: The reason for unwarning this member.
.. _warnings-command-warn:
^^^^
warn
^^^^
.. note:: |admin-lock|
**Syntax**
.. code-block:: none
[p]warn <member> [points=1] <reason>
**Description**
Warn the user for the specified reason.
**Arguments**
* ``<member>``: The member to warn. |member-input-quotes|
* ``[points]``: The number of points the warning should be for. If no number is supplied, 1 point will be given. Pre-set warnings disregard this.
* ``<reason>``: The reason for the warning. This can be a registered reason, or a custom reason if ``[p]warningset allowcustomreasons`` is set.
.. _warnings-command-warnaction:
^^^^^^^^^^
warnaction
^^^^^^^^^^
.. note:: |guildowner-lock|
**Syntax**
.. code-block:: none
[p]warnaction
**Description**
Manage automated actions for Warnings.
Actions are essentially command macros. Any command can be run
when the action is initially triggered, and/or when the action
is lifted.
Actions must be given a name and a points threshold. When a
user is warned enough so that their points go over this
threshold, the action will be executed.
.. _warnings-command-warnaction-add:
""""""""""""""
warnaction add
""""""""""""""
**Syntax**
.. code-block:: none
[p]warnaction add <name> <points>
**Description**
Create an automated action.
Duplicate action names are not allowed.
**Arguments**
* ``<name>``: The name of the action.
* ``<points>``: The number of points for this action.
.. _warnings-command-warnaction-delete:
"""""""""""""""""
warnaction delete
"""""""""""""""""
**Syntax**
.. code-block:: none
[p]warnaction delete <action_name>
**Description**
Delete the action with the specified name.
**Arguments**
* ``<action_name>``: The name of the action to delete.
.. _warnings-command-warnings:
^^^^^^^^
warnings
^^^^^^^^
.. note:: |admin-lock|
**Syntax**
.. code-block:: none
[p]warnings <member>
**Description**
List the warnings for the specified member.
**Arguments**
* ``<member>``: The member to get the warnings for. |member-input|
.. _warnings-command-warningset:
^^^^^^^^^^
warningset
^^^^^^^^^^
.. note:: |guildowner-lock|
**Syntax**
.. code-block:: none
[p]warningset
**Description**
Manage settings for Warnings.
.. _warnings-command-warningset-allowcustomreasons:
"""""""""""""""""""""""""""""
warningset allowcustomreasons
"""""""""""""""""""""""""""""
**Syntax**
.. code-block:: none
[p]warningset allowcustomreasons <true_or_false>
**Description**
Enable or disable custom reasons for a warning.
**Arguments**
* ``<true_or_false>``: |bool-input|
.. _warnings-command-warningset-senddm:
"""""""""""""""""
warningset senddm
"""""""""""""""""
**Syntax**
.. code-block:: none
[p]warningset senddm <true_or_false>
**Description**
Set whether warnings should be sent to users in DMs.
**Arguments**
* ``<true_or_false>``: |bool-input|
.. _warnings-command-warningset-showmoderator:
""""""""""""""""""""""""
warningset showmoderator
""""""""""""""""""""""""
**Syntax**
.. code-block:: none
[p]warningset showmoderator <true_or_false>
**Description**
Decide whether the name of the moderator warning a user should be included in the DM to that user.
**Arguments**
* ``<true_or_false>``: |bool-input|
.. _warnings-command-warningset-usewarnchannel:
"""""""""""""""""""""""""
warningset usewarnchannel
"""""""""""""""""""""""""
**Syntax**
.. code-block:: none
[p]warningset usewarnchannel <true_or_false>
**Description**
Set if warnings should be sent to a channel set with ``[p]warningset warnchannel``.
**Arguments**
* ``<true_or_false>``: |bool-input|
.. _warnings-command-warningset-warnchannel:
""""""""""""""""""""""
warningset warnchannel
""""""""""""""""""""""
**Syntax**
.. code-block:: none
[p]warningset warnchannel [channel]
**Description**
Set the channel where warnings should be sent to.
**Arguments**
* ``[channel]``: |channel-input| Leave empty to use the channel ``[p]warn`` command was called in.
.. _warnings-command-warnreason:
^^^^^^^^^^
warnreason
^^^^^^^^^^
.. note:: |guildowner-lock|
**Syntax**
.. code-block:: none
[p]warnreason
**Description**
Manage warning reasons.
Reasons must be given a name, description and points value. The
name of the reason must be given when a user is warned.
.. _warnings-command-warnreason-create:
"""""""""""""""""
warnreason create
"""""""""""""""""
**Syntax**
.. code-block:: none
[p]warnreason create <name> <points> <description>
.. tip:: Alias: ``warnreason add``
**Description**
Create a warning reason.
**Arguments**
* ``<name>``: The name for the new reason.
* ``<points>``: The number of points with the new reason.
* ``<description>``: The description of the new warn reason.
.. _warnings-command-warnreason-delete:
"""""""""""""""""
warnreason delete
"""""""""""""""""
**Syntax**
.. code-block:: none
[p]warnreason delete <reason_name>
**Description**
Delete a warning reason.
**Arguments**
* ``<reason_name>``: The name of the reason to delete.

View File

@ -52,6 +52,7 @@ Welcome to Red - Discord Bot's documentation!
cog_guides/reports cog_guides/reports
cog_guides/streams cog_guides/streams
cog_guides/trivia cog_guides/trivia
cog_guides/warnings
red_core_data_statement red_core_data_statement
.. toctree:: .. toctree::

View File

@ -156,7 +156,6 @@ class Warnings(commands.Cog):
@commands.guild_only() @commands.guild_only()
async def warnchannel(self, ctx: commands.Context, channel: discord.TextChannel = None): async def warnchannel(self, ctx: commands.Context, channel: discord.TextChannel = None):
"""Set the channel where warnings should be sent to. """Set the channel where warnings should be sent to.
Leave empty to use the channel `[p]warn` command was called in. Leave empty to use the channel `[p]warn` command was called in.
""" """
guild = ctx.guild guild = ctx.guild
@ -192,11 +191,9 @@ class Warnings(commands.Cog):
@checks.guildowner_or_permissions(administrator=True) @checks.guildowner_or_permissions(administrator=True)
async def warnaction(self, ctx: commands.Context): async def warnaction(self, ctx: commands.Context):
"""Manage automated actions for Warnings. """Manage automated actions for Warnings.
Actions are essentially command macros. Any command can be run Actions are essentially command macros. Any command can be run
when the action is initially triggered, and/or when the action when the action is initially triggered, and/or when the action
is lifted. is lifted.
Actions must be given a name and a points threshold. When a Actions must be given a name and a points threshold. When a
user is warned enough so that their points go over this user is warned enough so that their points go over this
threshold, the action will be executed. threshold, the action will be executed.
@ -207,7 +204,6 @@ class Warnings(commands.Cog):
@commands.guild_only() @commands.guild_only()
async def action_add(self, ctx: commands.Context, name: str, points: int): async def action_add(self, ctx: commands.Context, name: str, points: int):
"""Create an automated action. """Create an automated action.
Duplicate action names are not allowed. Duplicate action names are not allowed.
""" """
guild = ctx.guild guild = ctx.guild
@ -259,7 +255,6 @@ class Warnings(commands.Cog):
@checks.guildowner_or_permissions(administrator=True) @checks.guildowner_or_permissions(administrator=True)
async def warnreason(self, ctx: commands.Context): async def warnreason(self, ctx: commands.Context):
"""Manage warning reasons. """Manage warning reasons.
Reasons must be given a name, description and points value. The Reasons must be given a name, description and points value. The
name of the reason must be given when a user is warned. name of the reason must be given when a user is warned.
""" """
@ -368,26 +363,25 @@ class Warnings(commands.Cog):
async def warn( async def warn(
self, self,
ctx: commands.Context, ctx: commands.Context,
user: discord.Member, member: discord.Member,
points: UserInputOptional[int] = 1, points: UserInputOptional[int] = 1,
*, *,
reason: str, reason: str,
): ):
"""Warn the user for the specified reason. """Warn the user for the specified reason.
`<points>` number of points the warning should be for. If no number is supplied `<points>` number of points the warning should be for. If no number is supplied
1 point will be given. Pre-set warnings disregard this. 1 point will be given. Pre-set warnings disregard this.
`<reason>` can be a registered reason if it exists or a custom one `<reason>` is reason for the warning. This can be a registered reason,
is created by default. or a custom reason if ``[p]warningset allowcustomreasons`` is set.
""" """
guild = ctx.guild guild = ctx.guild
if user == ctx.author: if member == ctx.author:
return await ctx.send(_("You cannot warn yourself.")) return await ctx.send(_("You cannot warn yourself."))
if user.bot: if member.bot:
return await ctx.send(_("You cannot warn other bots.")) return await ctx.send(_("You cannot warn other bots."))
if user == ctx.guild.owner: if member == ctx.guild.owner:
return await ctx.send(_("You cannot warn the server owner.")) return await ctx.send(_("You cannot warn the server owner."))
if user.top_role >= ctx.author.top_role and ctx.author != ctx.guild.owner: if member.top_role >= ctx.author.top_role and ctx.author != ctx.guild.owner:
return await ctx.send( return await ctx.send(
_( _(
"The person you're trying to warn is equal or higher than you in the discord hierarchy, you cannot warn them." "The person you're trying to warn is equal or higher than you in the discord hierarchy, you cannot warn them."
@ -421,7 +415,7 @@ class Warnings(commands.Cog):
return await ctx.send(msg) return await ctx.send(msg)
if reason_type is None: if reason_type is None:
return return
member_settings = self.config.member(user) member_settings = self.config.member(member)
current_point_count = await member_settings.total_points() current_point_count = await member_settings.total_points()
warning_to_add = { warning_to_add = {
str(ctx.message.id): { str(ctx.message.id): {
@ -443,7 +437,7 @@ class Warnings(commands.Cog):
) )
em.add_field(name=_("Points"), value=str(reason_type["points"])) em.add_field(name=_("Points"), value=str(reason_type["points"]))
try: try:
await user.send( await member.send(
_("You have received a warning in {guild_name}.").format( _("You have received a warning in {guild_name}.").format(
guild_name=ctx.guild.name guild_name=ctx.guild.name
), ),
@ -457,13 +451,13 @@ class Warnings(commands.Cog):
_( _(
"A warning for {user} has been issued," "A warning for {user} has been issued,"
" but I wasn't able to send them a warn message." " but I wasn't able to send them a warn message."
).format(user=user.mention) ).format(user=member.mention)
) )
async with member_settings.warnings() as user_warnings: async with member_settings.warnings() as user_warnings:
user_warnings.update(warning_to_add) user_warnings.update(warning_to_add)
current_point_count += reason_type["points"] current_point_count += reason_type["points"]
await member_settings.total_points.set(current_point_count) await member_settings.total_points.set(current_point_count)
await warning_points_add_check(self.config, ctx, user, current_point_count) await warning_points_add_check(self.config, ctx, member, current_point_count)
toggle_channel = guild_settings["toggle_channel"] toggle_channel = guild_settings["toggle_channel"]
if toggle_channel: if toggle_channel:
@ -480,7 +474,7 @@ class Warnings(commands.Cog):
if warn_channel.permissions_for(guild.me).send_messages: if warn_channel.permissions_for(guild.me).send_messages:
with contextlib.suppress(discord.HTTPException): with contextlib.suppress(discord.HTTPException):
await warn_channel.send( await warn_channel.send(
_("{user} has been warned.").format(user=user.mention), _("{user} has been warned.").format(user=member.mention),
embed=em, embed=em,
) )
@ -489,7 +483,7 @@ class Warnings(commands.Cog):
await ctx.tick() await ctx.tick()
else: else:
await ctx.send( await ctx.send(
_("{user} has been warned.").format(user=user.mention), embed=em _("{user} has been warned.").format(user=member.mention), embed=em
) )
else: else:
if not dm_failed: if not dm_failed:
@ -501,7 +495,7 @@ class Warnings(commands.Cog):
description=reason_type["description"], points=reason_type["points"] description=reason_type["description"], points=reason_type["points"]
), ),
prefix=ctx.clean_prefix, prefix=ctx.clean_prefix,
user=user.id, user=member.id,
message=ctx.message.id, message=ctx.message.id,
) )
await modlog.create_case( await modlog.create_case(
@ -509,7 +503,7 @@ class Warnings(commands.Cog):
ctx.guild, ctx.guild,
ctx.message.created_at.replace(tzinfo=timezone.utc), ctx.message.created_at.replace(tzinfo=timezone.utc),
"warning", "warning",
user, member,
ctx.message.author, ctx.message.author,
reason_msg, reason_msg,
until=None, until=None,
@ -519,18 +513,18 @@ class Warnings(commands.Cog):
@commands.command() @commands.command()
@commands.guild_only() @commands.guild_only()
@checks.admin() @checks.admin()
async def warnings(self, ctx: commands.Context, user: Union[discord.Member, int]): async def warnings(self, ctx: commands.Context, member: Union[discord.Member, int]):
"""List the warnings for the specified user.""" """List the warnings for the specified user."""
try: try:
userid: int = user.id userid: int = member.id
except AttributeError: except AttributeError:
userid: int = user userid: int = member
user = ctx.guild.get_member(userid) member = ctx.guild.get_member(userid)
user = user or namedtuple("Member", "id guild")(userid, ctx.guild) member = member or namedtuple("Member", "id guild")(userid, ctx.guild)
msg = "" msg = ""
member_settings = self.config.member(user) member_settings = self.config.member(member)
async with member_settings.warnings() as user_warnings: async with member_settings.warnings() as user_warnings:
if not user_warnings.keys(): # no warnings for the user if not user_warnings.keys(): # no warnings for the user
await ctx.send(_("That user has no warnings!")) await ctx.send(_("That user has no warnings!"))
@ -554,7 +548,7 @@ class Warnings(commands.Cog):
await ctx.send_interactive( await ctx.send_interactive(
pagify(msg, shorten_by=58), pagify(msg, shorten_by=58),
box_lang=_("Warnings for {user}").format( box_lang=_("Warnings for {user}").format(
user=user if isinstance(user, discord.Member) else user.id user=member if isinstance(member, discord.Member) else member.id
), ),
) )
@ -598,7 +592,7 @@ class Warnings(commands.Cog):
async def unwarn( async def unwarn(
self, self,
ctx: commands.Context, ctx: commands.Context,
user: Union[discord.Member, int], member: Union[discord.Member, int],
warn_id: str, warn_id: str,
*, *,
reason: str = None, reason: str = None,
@ -608,10 +602,10 @@ class Warnings(commands.Cog):
guild = ctx.guild guild = ctx.guild
try: try:
user_id = user.id user_id = member.id
member = user member = member
except AttributeError: except AttributeError:
user_id = user user_id = member
member = guild.get_member(user_id) member = guild.get_member(user_id)
member = member or namedtuple("Member", "guild id")(guild, user_id) member = member or namedtuple("Member", "guild id")(guild, user_id)