mirror of
https://github.com/brandons209/Red-bot-Cogs.git
synced 2024-09-30 17:17:35 +13:00
767 lines
34 KiB
Python
767 lines
34 KiB
Python
import asyncio
|
|
import discord
|
|
|
|
from typing import Optional, Literal
|
|
from discord.utils import get
|
|
from datetime import timedelta
|
|
|
|
from redbot.core import Config, checks, commands
|
|
from redbot.core.utils.predicates import MessagePredicate, ReactionPredicate
|
|
from redbot.core.utils.menus import start_adding_reactions
|
|
from redbot.core.utils.antispam import AntiSpam
|
|
|
|
from redbot.core.bot import Red
|
|
from .discord_thread_feature import create_thread, add_user_thread
|
|
|
|
|
|
class Suggestion(commands.Cog):
|
|
"""
|
|
Simple suggestion box, basically.
|
|
|
|
**Use `[p]setsuggest setup` first.**
|
|
Only admins can approve or reject suggestions.
|
|
"""
|
|
|
|
__author__ = "saurichable"
|
|
__version__ = "1.4.0"
|
|
|
|
def __init__(self, bot: Red):
|
|
self.bot = bot
|
|
self.config = Config.get_conf(self, identifier=2115656421364, force_registration=True)
|
|
self.antispam = {}
|
|
self.config.register_guild(
|
|
same=False,
|
|
suggest_id=None,
|
|
approve_id=None,
|
|
reject_id=None,
|
|
next_id=1,
|
|
up_emoji=None,
|
|
down_emoji=None,
|
|
delete_suggest=False,
|
|
create_threads=False,
|
|
)
|
|
self.config.register_global(toggle=False, server_id=None, channel_id=None, next_id=1, ignore=[])
|
|
self.config.init_custom("SUGGESTION", 2)
|
|
self.config.register_custom(
|
|
"SUGGESTION",
|
|
author=[],
|
|
msg_id=0,
|
|
finished=False,
|
|
approved=False,
|
|
rejected=False,
|
|
reason=False,
|
|
stext=None,
|
|
rtext=None,
|
|
num_up=0,
|
|
num_down=0,
|
|
)
|
|
|
|
@commands.command()
|
|
@commands.guild_only()
|
|
@checks.bot_has_permissions(add_reactions=True)
|
|
async def suggest(self, ctx: commands.Context, *, suggestion: str):
|
|
"""Suggest something. Message is required."""
|
|
suggest_id = await self.config.guild(ctx.guild).suggest_id()
|
|
if not suggest_id:
|
|
if await self.config.toggle():
|
|
if ctx.guild.id in await self.config.ignore():
|
|
return await ctx.send("Uh oh, suggestions aren't enabled.")
|
|
global_guild = self.bot.get_guild(await self.config.server_id())
|
|
channel = get(global_guild.text_channels, id=await self.config.channel_id())
|
|
else:
|
|
return await ctx.send("Uh oh, suggestions aren't enabled.")
|
|
else:
|
|
channel = get(ctx.guild.text_channels, id=suggest_id)
|
|
if not channel:
|
|
return await ctx.send("Uh oh, looks like your Admins haven't added the required channel.")
|
|
if ctx.guild not in self.antispam:
|
|
self.antispam[ctx.guild] = {}
|
|
if ctx.author not in self.antispam[ctx.guild]:
|
|
self.antispam[ctx.guild][ctx.author] = AntiSpam([(timedelta(days=1), 6)])
|
|
if self.antispam[ctx.guild][ctx.author].spammy:
|
|
return await ctx.send("Uh oh, you're doing this way too frequently.")
|
|
embed = discord.Embed(color=await ctx.embed_colour(), description=suggestion)
|
|
embed.set_author(
|
|
name=f"Suggestion by {ctx.author.display_name}",
|
|
icon_url=ctx.author.avatar_url,
|
|
)
|
|
embed.set_footer(text=f"Suggested by {ctx.author.name}#{ctx.author.discriminator} ({ctx.author.id})")
|
|
|
|
if not suggest_id:
|
|
if await self.config.toggle():
|
|
s_id = await self.config.next_id()
|
|
await self.config.next_id.set(s_id + 1)
|
|
server = 1
|
|
content = f"Global suggestion #{s_id}"
|
|
else:
|
|
s_id = await self.config.guild(ctx.guild).next_id()
|
|
await self.config.guild(ctx.guild).next_id.set(s_id + 1)
|
|
server = ctx.guild.id
|
|
content = f"Suggestion #{s_id}"
|
|
msg = await channel.send(content=content, embed=embed)
|
|
|
|
up_emoji = self.bot.get_emoji(await self.config.guild(ctx.guild).up_emoji())
|
|
if not up_emoji:
|
|
up_emoji = "✅"
|
|
down_emoji = self.bot.get_emoji(await self.config.guild(ctx.guild).down_emoji())
|
|
if not down_emoji:
|
|
down_emoji = "❎"
|
|
await msg.add_reaction(up_emoji)
|
|
await msg.add_reaction(down_emoji)
|
|
|
|
async with self.config.custom("SUGGESTION", server, s_id).author() as author:
|
|
author.append(ctx.author.id)
|
|
author.append(ctx.author.name)
|
|
author.append(ctx.author.discriminator)
|
|
await self.config.custom("SUGGESTION", server, s_id).stext.set(suggestion)
|
|
await self.config.custom("SUGGESTION", server, s_id).msg_id.set(msg.id)
|
|
|
|
self.antispam[ctx.guild][ctx.author].stamp()
|
|
if await self.config.guild(ctx.guild).delete_suggest():
|
|
await ctx.message.delete()
|
|
else:
|
|
await ctx.tick()
|
|
|
|
if await self.config.guild(ctx.guild).create_threads():
|
|
# always use max archive, function will clip it if needed
|
|
try:
|
|
thread = await create_thread(self.bot, channel, msg, name=content, archive=10080)
|
|
await add_user_thread(self.bot, thread, ctx.author)
|
|
except:
|
|
await ctx.send("Error in creating a thread for this suggestion, please check permissions!")
|
|
|
|
try:
|
|
await ctx.author.send(content="Your suggestion has been sent for approval!", embed=embed)
|
|
except discord.Forbidden:
|
|
pass
|
|
|
|
@checks.admin_or_permissions(administrator=True)
|
|
@commands.command()
|
|
@commands.guild_only()
|
|
@checks.bot_has_permissions(manage_messages=True)
|
|
async def approve(
|
|
self,
|
|
ctx: commands.Context,
|
|
suggestion_id: int,
|
|
is_global: Optional[bool] = False,
|
|
*,
|
|
reason: str = "",
|
|
):
|
|
"""Approve a suggestion."""
|
|
if is_global:
|
|
if await self.config.toggle():
|
|
if ctx.author.id != self.bot.owner_id:
|
|
return await ctx.send("Uh oh, you're not my owner.")
|
|
server = 1
|
|
global_guild = self.bot.get_guild(await self.config.server_id())
|
|
oldchannel = get(global_guild.text_channels, id=await self.config.channel_id())
|
|
else:
|
|
return await ctx.send("Global suggestions aren't enabled.")
|
|
else:
|
|
server = ctx.guild.id
|
|
oldchannel = get(
|
|
ctx.guild.text_channels,
|
|
id=await self.config.guild(ctx.guild).suggest_id(),
|
|
)
|
|
channel = get(
|
|
ctx.guild.text_channels,
|
|
id=await self.config.guild(ctx.guild).approve_id(),
|
|
)
|
|
msg_id = await self.config.custom("SUGGESTION", server, suggestion_id).msg_id()
|
|
if msg_id != 0:
|
|
if await self.config.custom("SUGGESTION", server, suggestion_id).finished():
|
|
return await ctx.send("This suggestion has been finished already.")
|
|
try:
|
|
oldmsg = await oldchannel.fetch_message(id=msg_id)
|
|
except discord.NotFound:
|
|
return await ctx.send("Uh oh, message with this ID doesn't exist.")
|
|
if not oldmsg:
|
|
return await ctx.send("Uh oh, message with this ID doesn't exist.")
|
|
embed = oldmsg.embeds[0]
|
|
content = oldmsg.content
|
|
# change to green for Approved
|
|
embed.color = discord.Color.from_rgb(0, 255, 0)
|
|
op_info = await self.config.custom("SUGGESTION", server, suggestion_id).author()
|
|
op_id = int(op_info[0])
|
|
op = await self.bot.fetch_user(op_id)
|
|
op_name = op.name
|
|
op_avatar = op.avatar_url
|
|
if not op:
|
|
op_name = str(op_info[1])
|
|
op_avatar = ctx.guild.icon_url
|
|
embed.set_author(name=f"Approved suggestion by {op_name}", icon_url=op_avatar)
|
|
# get number of reactions for approved / denied
|
|
up_emoji = self.bot.get_emoji(await self.config.guild(ctx.guild).up_emoji())
|
|
if not up_emoji:
|
|
up_emoji = "✅"
|
|
down_emoji = self.bot.get_emoji(await self.config.guild(ctx.guild).down_emoji())
|
|
if not down_emoji:
|
|
down_emoji = "❎"
|
|
reactions = oldmsg.reactions
|
|
num_up = 0
|
|
num_down = 0
|
|
for react in reactions:
|
|
if react.emoji == up_emoji:
|
|
num_up = react.count - 1 # minus 1 for bot
|
|
elif react.emoji == down_emoji:
|
|
num_down = react.count - 1 # minus 1 for bot
|
|
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).num_up.set(num_up)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).num_down.set(num_down)
|
|
embed.add_field(name="Votes:", value=f"For: `{num_up}`, Against: `{num_down}`", inline=False)
|
|
|
|
if reason:
|
|
embed.add_field(name="Reason:", value=reason, inline=False)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).reason.set(True)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).rtext.set(reason)
|
|
if is_global:
|
|
await oldmsg.edit(content=content, embed=embed)
|
|
try:
|
|
await oldmsg.clear_reactions()
|
|
except discord.Forbidden:
|
|
pass
|
|
else:
|
|
if channel:
|
|
await oldmsg.delete()
|
|
nmsg = await channel.send(content=content, embed=embed)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).msg_id.set(nmsg.id)
|
|
else:
|
|
if not await self.config.guild(ctx.guild).same():
|
|
await oldmsg.delete()
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).msg_id.set(1)
|
|
else:
|
|
await oldmsg.edit(content=content, embed=embed)
|
|
try:
|
|
await oldmsg.clear_reactions()
|
|
except discord.Forbidden:
|
|
pass
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).finished.set(True)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).approved.set(True)
|
|
await ctx.tick()
|
|
|
|
try:
|
|
await op.send(content="Your suggestion has been approved!", embed=embed)
|
|
except discord.Forbidden:
|
|
pass
|
|
|
|
@checks.admin_or_permissions(administrator=True)
|
|
@commands.command()
|
|
@commands.guild_only()
|
|
@checks.bot_has_permissions(manage_messages=True)
|
|
async def reject(
|
|
self,
|
|
ctx: commands.Context,
|
|
suggestion_id: int,
|
|
is_global: Optional[bool] = False,
|
|
*,
|
|
reason: str = "",
|
|
):
|
|
"""Reject a suggestion. Reason is optional."""
|
|
if is_global:
|
|
if await self.config.toggle():
|
|
if ctx.author.id != self.bot.owner_id:
|
|
return await ctx.send("Uh oh, you're not my owner.")
|
|
server = 1
|
|
global_guild = self.bot.get_guild(await self.config.server_id())
|
|
oldchannel = get(global_guild.text_channels, id=await self.config.channel_id())
|
|
else:
|
|
return await ctx.send("Global suggestions aren't enabled.")
|
|
else:
|
|
server = ctx.guild.id
|
|
oldchannel = get(
|
|
ctx.guild.text_channels,
|
|
id=await self.config.guild(ctx.guild).suggest_id(),
|
|
)
|
|
channel = get(
|
|
ctx.guild.text_channels,
|
|
id=await self.config.guild(ctx.guild).reject_id(),
|
|
)
|
|
msg_id = await self.config.custom("SUGGESTION", server, suggestion_id).msg_id()
|
|
if msg_id != 0:
|
|
if await self.config.custom("SUGGESTION", server, suggestion_id).finished():
|
|
return await ctx.send("This suggestion has been finished already.")
|
|
try:
|
|
oldmsg = await oldchannel.fetch_message(id=msg_id)
|
|
except discord.NotFound:
|
|
return await ctx.send("Uh oh, message with this ID doesn't exist.")
|
|
if not oldmsg:
|
|
return await ctx.send("Uh oh, message with this ID doesn't exist.")
|
|
embed = oldmsg.embeds[0]
|
|
content = oldmsg.content
|
|
# change to red for denied
|
|
embed.color = discord.Color.from_rgb(255, 0, 0)
|
|
op_info = await self.config.custom("SUGGESTION", server, suggestion_id).author()
|
|
op_id = int(op_info[0])
|
|
op = await self.bot.fetch_user(op_id)
|
|
op_name = op.name
|
|
op_avatar = op.avatar_url
|
|
if not op:
|
|
op_name = str(op_info[1])
|
|
op_avatar = ctx.guild.icon_url
|
|
embed.set_author(name=f"Rejected suggestion by {op_name}", icon_url=op_avatar)
|
|
|
|
# get number of reactions for approved / denied
|
|
up_emoji = self.bot.get_emoji(await self.config.guild(ctx.guild).up_emoji())
|
|
if not up_emoji:
|
|
up_emoji = "✅"
|
|
down_emoji = self.bot.get_emoji(await self.config.guild(ctx.guild).down_emoji())
|
|
if not down_emoji:
|
|
down_emoji = "❎"
|
|
|
|
reactions = oldmsg.reactions
|
|
num_up = 0
|
|
num_down = 0
|
|
for react in reactions:
|
|
if react.emoji == up_emoji:
|
|
num_up = react.count - 1 # minus 1 for bot
|
|
elif react.emoji == down_emoji:
|
|
num_down = react.count - 1 # minus 1 for bot
|
|
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).num_up.set(num_up)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).num_down.set(num_down)
|
|
embed.add_field(name="Votes:", value=f"For: `{num_up}`, Against: `{num_down}`", inline=False)
|
|
if reason:
|
|
embed.add_field(name="Reason:", value=reason, inline=False)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).reason.set(True)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).rtext.set(reason)
|
|
if is_global:
|
|
await oldmsg.edit(content=content, embed=embed)
|
|
try:
|
|
await oldmsg.clear_reactions()
|
|
except discord.Forbidden:
|
|
pass
|
|
else:
|
|
if channel:
|
|
await oldmsg.delete()
|
|
nmsg = await channel.send(content=content, embed=embed)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).msg_id.set(nmsg.id)
|
|
else:
|
|
if not await self.config.guild(ctx.guild).same():
|
|
await oldmsg.delete()
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).msg_id.set(1)
|
|
else:
|
|
await oldmsg.edit(content=content, embed=embed)
|
|
try:
|
|
await oldmsg.clear_reactions()
|
|
except discord.Forbidden:
|
|
pass
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).finished.set(True)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).rejected.set(True)
|
|
await ctx.tick()
|
|
|
|
try:
|
|
await op.send(content="Your suggestion has been rejected!", embed=embed)
|
|
except discord.Forbidden:
|
|
pass
|
|
|
|
@checks.admin_or_permissions(administrator=True)
|
|
@commands.command()
|
|
@commands.guild_only()
|
|
@checks.bot_has_permissions(manage_messages=True)
|
|
async def addreason(
|
|
self,
|
|
ctx: commands.Context,
|
|
suggestion_id: int,
|
|
is_global: Optional[bool] = False,
|
|
*,
|
|
reason: str,
|
|
):
|
|
"""Add a reason to a suggestion.
|
|
|
|
Only works for non global suggestions."""
|
|
if is_global:
|
|
if await self.config.toggle():
|
|
if ctx.author.id != self.bot.owner_id:
|
|
return await ctx.send("Uh oh, you're not my owner.")
|
|
server = 1
|
|
global_guild = self.bot.get_guild(await self.config.server_id())
|
|
channel = get(global_guild.text_channels, id=await self.config.channel_id())
|
|
else:
|
|
return await ctx.send("Global suggestions aren't enabled.")
|
|
else:
|
|
server = ctx.guild.id
|
|
if not await self.config.guild(ctx.guild).same():
|
|
channel = get(
|
|
ctx.guild.text_channels,
|
|
id=await self.config.guild(ctx.guild).reject_id(),
|
|
)
|
|
else:
|
|
channel = get(
|
|
ctx.guild.text_channels,
|
|
id=await self.config.guild(ctx.guild).suggest_id(),
|
|
)
|
|
msg_id = await self.config.custom("SUGGESTION", server, suggestion_id).msg_id()
|
|
if msg_id != 0:
|
|
if await self.config.custom("SUGGESTION", server, suggestion_id).reason():
|
|
return await ctx.send("This suggestion already has a reason.")
|
|
content, embed = await self._build_suggestion(ctx, ctx.author.id, ctx.guild.id, suggestion_id, is_global)
|
|
embed.add_field(name="Reason:", value=reason, inline=False)
|
|
msg = await channel.fetch_message(id=msg_id)
|
|
if msg:
|
|
await msg.edit(content=content, embed=embed)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).reason.set(True)
|
|
await self.config.custom("SUGGESTION", server, suggestion_id).rtext.set(reason)
|
|
await ctx.tick()
|
|
|
|
@checks.admin_or_permissions(administrator=True)
|
|
@commands.command()
|
|
@commands.guild_only()
|
|
async def showsuggestion(
|
|
self,
|
|
ctx: commands.Context,
|
|
suggestion_id: int,
|
|
is_global: Optional[bool] = False,
|
|
):
|
|
"""Show a suggestion."""
|
|
content, embed = await self._build_suggestion(ctx, ctx.author.id, ctx.guild.id, suggestion_id, is_global)
|
|
await ctx.send(content=content, embed=embed)
|
|
|
|
@checks.admin_or_permissions(administrator=True)
|
|
@commands.group(autohelp=True)
|
|
@commands.guild_only()
|
|
async def setsuggest(self, ctx: commands.Context):
|
|
"""Suggestion settings"""
|
|
pass
|
|
|
|
@setsuggest.command(name="threads")
|
|
async def setsuggest_threads(self, ctx: commands.Context, toggle: bool):
|
|
"""
|
|
Enable automatic thread creation for each suggestion, for discussion
|
|
"""
|
|
await self.config.guild(ctx.guild).create_threads.set(toggle)
|
|
await ctx.tick()
|
|
|
|
@checks.bot_has_permissions(manage_channels=True)
|
|
@setsuggest.command(name="setup")
|
|
async def setsuggest_setup(self, ctx: commands.Context):
|
|
"""Go through the initial setup process."""
|
|
await self.config.guild(ctx.guild).same.set(False)
|
|
await self.config.guild(ctx.guild).suggest_id.set(None)
|
|
await self.config.guild(ctx.guild).approve_id.set(None)
|
|
await self.config.guild(ctx.guild).reject_id.set(None)
|
|
predchan = MessagePredicate.valid_text_channel(ctx)
|
|
overwrites = {
|
|
ctx.guild.default_role: discord.PermissionOverwrite(send_messages=False),
|
|
ctx.guild.me: discord.PermissionOverwrite(send_messages=True),
|
|
}
|
|
msg = await ctx.send("Do you already have your channel(s) done?")
|
|
start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS)
|
|
pred = ReactionPredicate.yes_or_no(msg, ctx.author)
|
|
try:
|
|
await self.bot.wait_for("reaction_add", timeout=30, check=pred)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
if not pred.result:
|
|
await msg.delete()
|
|
suggestions = get(ctx.guild.text_channels, name="suggestions")
|
|
if not suggestions:
|
|
suggestions = await ctx.guild.create_text_channel(
|
|
"suggestions", overwrites=overwrites, reason="Suggestion cog setup"
|
|
)
|
|
await self.config.guild(ctx.guild).suggest_id.set(suggestions.id)
|
|
|
|
msg = await ctx.send(
|
|
"Do you want to use the same channel for approved and rejected suggestions? (If yes, they won't be reposted anywhere, only their title will change accordingly.)"
|
|
)
|
|
start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS)
|
|
pred = ReactionPredicate.yes_or_no(msg, ctx.author)
|
|
try:
|
|
await self.bot.wait_for("reaction_add", timeout=30, check=pred)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
if pred.result:
|
|
await msg.delete()
|
|
await self.config.guild(ctx.guild).same.set(True)
|
|
else:
|
|
await msg.delete()
|
|
approved = get(ctx.guild.text_channels, name="approved-suggestions")
|
|
if not approved:
|
|
msg = await ctx.send("Do you want to have an approved suggestions channel?")
|
|
start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS)
|
|
pred = ReactionPredicate.yes_or_no(msg, ctx.author)
|
|
try:
|
|
await self.bot.wait_for("reaction_add", timeout=30, check=pred)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
if pred.result:
|
|
approved = await ctx.guild.create_text_channel(
|
|
"approved-suggestions",
|
|
overwrites=overwrites,
|
|
reason="Suggestion cog setup",
|
|
)
|
|
await self.config.guild(ctx.guild).approve_id.set(approved.id)
|
|
await msg.delete()
|
|
else:
|
|
await self.config.guild(ctx.guild).approve_id.set(approved.id)
|
|
rejected = get(ctx.guild.text_channels, name="rejected-suggestions")
|
|
if not rejected:
|
|
msg = await ctx.send("Do you want to have a rejected suggestions channel?")
|
|
start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS)
|
|
pred = ReactionPredicate.yes_or_no(msg, ctx.author)
|
|
try:
|
|
await self.bot.wait_for("reaction_add", timeout=30, check=pred)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
if pred.result:
|
|
rejected = await ctx.guild.create_text_channel(
|
|
"rejected-suggestions",
|
|
overwrites=overwrites,
|
|
reason="Suggestion cog setup",
|
|
)
|
|
await self.config.guild(ctx.guild).reject_id.set(rejected.id)
|
|
await msg.delete()
|
|
else:
|
|
await self.config.guild(ctx.guild).reject_id.set(rejected.id)
|
|
else:
|
|
await msg.delete()
|
|
msg = await ctx.send("Mention the channel where you want me to post new suggestions.")
|
|
try:
|
|
await self.bot.wait_for("message", timeout=30, check=predchan)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
suggestion = predchan.result
|
|
await self.config.guild(ctx.guild).suggest_id.set(suggestion.id)
|
|
await msg.delete()
|
|
|
|
msg = await ctx.send(
|
|
"Do you want to use the same channel for approved and rejected suggestions? (If yes, they won't be reposted anywhere, only their title will change accordingly.)"
|
|
)
|
|
start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS)
|
|
pred = ReactionPredicate.yes_or_no(msg, ctx.author)
|
|
try:
|
|
await self.bot.wait_for("reaction_add", timeout=30, check=pred)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
if pred.result:
|
|
await msg.delete()
|
|
await self.config.guild(ctx.guild).same.set(True)
|
|
else:
|
|
await msg.delete()
|
|
msg = await ctx.send("Do you want to have an approved suggestions channel?")
|
|
start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS)
|
|
pred = ReactionPredicate.yes_or_no(msg, ctx.author)
|
|
try:
|
|
await self.bot.wait_for("reaction_add", timeout=30, check=pred)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
if pred.result:
|
|
await msg.delete()
|
|
msg = await ctx.send("Mention the channel where you want me to post approved suggestions.")
|
|
try:
|
|
await self.bot.wait_for("message", timeout=30, check=predchan)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
approved = predchan.result
|
|
await self.config.guild(ctx.guild).approve_id.set(approved.id)
|
|
await msg.delete()
|
|
|
|
msg = await ctx.send("Do you want to have a rejected suggestions channel?")
|
|
start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS)
|
|
pred = ReactionPredicate.yes_or_no(msg, ctx.author)
|
|
try:
|
|
await self.bot.wait_for("reaction_add", timeout=30, check=pred)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
if pred.result:
|
|
await msg.delete()
|
|
msg = await ctx.send("Mention the channel where you want me to post rejected suggestions.")
|
|
try:
|
|
await self.bot.wait_for("message", timeout=30, check=predchan)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
rejected = predchan.result
|
|
await self.config.guild(ctx.guild).reject_id.set(rejected.id)
|
|
await msg.delete()
|
|
|
|
msg = await ctx.send(
|
|
"Do you want to automatically create threads for each suggestion to allow discussion of each suggestion to be seperated?"
|
|
)
|
|
start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS)
|
|
pred = ReactionPredicate.yes_or_no(msg, ctx.author)
|
|
try:
|
|
await self.bot.wait_for("reaction_add", timeout=30, check=pred)
|
|
except asyncio.TimeoutError:
|
|
await msg.delete()
|
|
return await ctx.send("You took too long. Try again, please.")
|
|
if pred.result:
|
|
await self.config.guild(ctx.guild).create_threads.set(True)
|
|
|
|
await ctx.send("You have finished the setup! Please, move your channels to the category you want them in.")
|
|
|
|
@checks.bot_has_permissions(add_reactions=True)
|
|
@setsuggest.command(name="upemoji")
|
|
async def setsuggest_upemoji(self, ctx: commands.Context, up_emoji: discord.Emoji = None):
|
|
"""Set custom reactions emoji instead of ✅."""
|
|
if not up_emoji:
|
|
await self.config.guild(ctx.guild).up_emoji.set(None)
|
|
else:
|
|
try:
|
|
await ctx.message.add_reaction(up_emoji)
|
|
except discord.HTTPException:
|
|
return await ctx.send("Uh oh, I cannot use that emoji.")
|
|
await self.config.guild(ctx.guild).up_emoji.set(up_emoji.id)
|
|
await ctx.tick()
|
|
|
|
@checks.bot_has_permissions(add_reactions=True)
|
|
@setsuggest.command(name="downemoji")
|
|
async def setsuggest_downemoji(self, ctx: commands.Context, down_emoji: discord.Emoji = None):
|
|
"""Set custom reactions emoji instead of ❎."""
|
|
if not down_emoji:
|
|
await self.config.guild(ctx.guild).up_emoji.set(None)
|
|
else:
|
|
try:
|
|
await ctx.message.add_reaction(down_emoji)
|
|
except discord.HTTPException:
|
|
return await ctx.send("Uh oh, I cannot use that emoji.")
|
|
await self.config.guild(ctx.guild).down_emoji.set(down_emoji.id)
|
|
await ctx.tick()
|
|
|
|
@checks.bot_has_permissions(manage_messages=True)
|
|
@setsuggest.command(name="autodelete")
|
|
async def setsuggest_autodelete(self, ctx: commands.Context, on_off: bool = None):
|
|
"""
|
|
Toggle whether after `[p]suggest`, the bot deletes the message.
|
|
"""
|
|
target_state = on_off if on_off else not (await self.config.guild(ctx.guild).delete_suggest())
|
|
await self.config.guild(ctx.guild).delete_suggest.set(target_state)
|
|
if target_state:
|
|
await ctx.send("Auto deletion is now enabled.")
|
|
else:
|
|
await ctx.send("Auto deletion is now disabled.")
|
|
|
|
@setsuggest.group(autohelp=True)
|
|
@checks.is_owner()
|
|
@commands.guild_only()
|
|
async def setglobal(self, ctx: commands.Context):
|
|
"""Global suggestions settings.
|
|
|
|
There is nothing like approved or rejected channels because global suggestions are meant to be for the bot only and will only work if it is sent in a server where normal suggestions are disabled."""
|
|
pass
|
|
|
|
@setglobal.command(name="toggle")
|
|
async def setsuggest_setglobal_toggle(self, ctx: commands.Context, on_off: bool = None):
|
|
"""Toggle global suggestions.
|
|
If `on_off` is not provided, the state will be flipped."""
|
|
target_state = on_off if on_off else not (await self.config.toggle())
|
|
await self.config.toggle.set(target_state)
|
|
if target_state:
|
|
await ctx.send("Global suggestions are now enabled.")
|
|
else:
|
|
await ctx.send("Global suggestions are now disabled.")
|
|
|
|
@setglobal.command(name="channel")
|
|
async def setsuggest_setglobal_channel(
|
|
self,
|
|
ctx: commands.Context,
|
|
server: discord.Guild = None,
|
|
channel: discord.TextChannel = None,
|
|
):
|
|
"""Add channel where global suggestions should be sent."""
|
|
if not server:
|
|
server = ctx.guild
|
|
if not channel:
|
|
channel = ctx.channel
|
|
await self.config.server_id.set(server.id)
|
|
await self.config.channel_id.set(channel.id)
|
|
await ctx.send(f"{channel.mention} has been saved for global suggestions.")
|
|
|
|
@setglobal.command(name="ignore")
|
|
async def setsuggest_setglobal_ignore(self, ctx: commands.Context, server: discord.Guild = None):
|
|
"""Ignore suggestions from the server."""
|
|
if not server:
|
|
server = ctx.guild
|
|
if server.id not in await self.config.ignore():
|
|
async with self.config.ignore() as ignore:
|
|
ignore.append(server.id)
|
|
await ctx.send(f"{server.name} has been added into the ignored list.")
|
|
else:
|
|
await ctx.send(f"{server.name} is already in the ignored list.")
|
|
|
|
@setglobal.command(name="unignore")
|
|
async def setsuggest_setglobal_unignore(self, ctx: commands.Context, server: discord.Guild = None):
|
|
"""Remove server from the ignored list."""
|
|
if not server:
|
|
server = ctx.guild
|
|
if server.id in await self.config.ignore():
|
|
async with self.config.ignore() as ignore:
|
|
ignore.remove(server.id)
|
|
await ctx.send(f"{server.name} has been removed from the ignored list.")
|
|
else:
|
|
await ctx.send(f"{server.name} already isn't in the ignored list.")
|
|
|
|
async def _build_suggestion(self, ctx, author_id, server_id, suggestion_id, is_global):
|
|
if is_global:
|
|
if await self.config.toggle():
|
|
if author_id != self.bot.owner_id:
|
|
return await ctx.send("Uh oh, you're not my owner.")
|
|
server = 1
|
|
if await self.config.custom("SUGGESTION", server, suggestion_id).msg_id() != 0:
|
|
content = f"Global suggestion #{suggestion_id}"
|
|
else:
|
|
return await ctx.send("Uh oh, that suggestion doesn't seem to exist.")
|
|
else:
|
|
return await ctx.send("Global suggestions aren't enabled.")
|
|
if not is_global:
|
|
server = server_id
|
|
if await self.config.custom("SUGGESTION", server, suggestion_id).msg_id() != 0:
|
|
content = f"Suggestion #{suggestion_id}"
|
|
else:
|
|
return await ctx.send("Uh oh, that suggestion doesn't seem to exist.")
|
|
op_info = await self.config.custom("SUGGESTION", server, suggestion_id).author()
|
|
op_id = int(op_info[0])
|
|
op = await self.bot.fetch_user(op_id)
|
|
if op:
|
|
op_name = op.name
|
|
op_discriminator = op.discriminator
|
|
op_avatar = op.avatar_url
|
|
else:
|
|
op_name = str(op_info[1])
|
|
op_discriminator = int(op_info[2])
|
|
op_avatar = ctx.guild.icon_url
|
|
|
|
if not await self.config.custom("SUGGESTION", server, suggestion_id).finished():
|
|
atext = f"Suggestion by {op_name}"
|
|
else:
|
|
if await self.config.custom("SUGGESTION", server, suggestion_id).approved():
|
|
atext = f"Approved suggestion by {op_name}"
|
|
elif await self.config.custom("SUGGESTION", server, suggestion_id).rejected():
|
|
atext = f"Rejected suggestion by {op_name}"
|
|
|
|
embed = discord.Embed(
|
|
color=await ctx.embed_colour(),
|
|
description=await self.config.custom("SUGGESTION", server, suggestion_id).stext(),
|
|
)
|
|
embed.set_author(name=atext, icon_url=op_avatar)
|
|
embed.set_footer(text=f"Suggested by {op_name}#{op_discriminator} ({op_id})")
|
|
|
|
if await self.config.custom("SUGGESTION", server, suggestion_id).reason():
|
|
embed.add_field(
|
|
name="Reason:",
|
|
value=await self.config.custom("SUGGESTION", server, suggestion_id).rtext(),
|
|
inline=False,
|
|
)
|
|
|
|
if await self.config.custom("SUGGESTION", server, suggestion_id).finished():
|
|
num_up = await self.config.custom("SUGGESTION", server, suggestion_id).num_up()
|
|
num_down = await self.config.custom("SUGGESTION", server, suggestion_id).num_down()
|
|
embed.add_field(name="Votes:", value=f"For: `{num_up}`, Against: `{num_down}`", inline=False)
|
|
|
|
return content, embed
|
|
|
|
async def red_delete_data_for_user(
|
|
self,
|
|
*,
|
|
requester: Literal["discord_deleted_user", "owner", "user", "user_strict"],
|
|
user_id: int,
|
|
):
|
|
pass
|