Skip to content

Commit 87c69f4

Browse files
authored
Suggestion Cog (#52)
Create suggestions cog.
1 parent 8d7dab0 commit 87c69f4

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

config.template.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ webhook_avatar_url = "" # optional
2424
runner = 123456789 # optional: sets the webhook avatar url (will be overridden by the webhook_avatar_url attribute)
2525
level = 20
2626

27+
[SUGGESTIONS] # optional
28+
webhook_url = ""
29+
2730
[SNEKBOX] # optional
2831
url = 'http://snekbox:8060/eval' # default url
2932

modules/suggestions.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"""MIT License
2+
3+
Copyright (c) 2021-Present PythonistaGuild
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+
"""
23+
24+
import logging
25+
from datetime import datetime
26+
from typing import Union
27+
28+
import discord
29+
from discord import ui
30+
from discord.ext import commands
31+
32+
import core
33+
34+
35+
LOGGER = logging.getLogger(__name__)
36+
37+
38+
def get_suggestion_type(value: str) -> str:
39+
options: dict[str, str] = {"1": "the guild", "2": "PythonistaBot", "3": "TwitchIO", "4": "Wavelink"}
40+
return options[value]
41+
42+
43+
class TypeSelect(ui.Select["TypeView"]):
44+
def __init__(
45+
self,
46+
*,
47+
original_author: Union[discord.Member, discord.User],
48+
suggestion: str,
49+
webhook: discord.Webhook,
50+
message: discord.Message | discord.WebhookMessage | None = None,
51+
):
52+
super().__init__()
53+
self.original_author = original_author
54+
self.suggestion = suggestion
55+
self.webhook = webhook
56+
self.message = message
57+
58+
self.add_option(label="Guild", value="1", description="This suggestion applies to the guild.", emoji="\U0001f4c1")
59+
self.add_option(
60+
label="Pythonistabot", value="2", description="This suggestion applies to Pythonistabot.", emoji="\U0001f916"
61+
)
62+
self.add_option(
63+
label="TwitchIO",
64+
value="3",
65+
description="This suggestion applies to TwitchIO.",
66+
emoji="<:twitchio_illegal:1014831894417915984>",
67+
)
68+
self.add_option(
69+
label="Wavelink",
70+
value="4",
71+
description="This suggestion applies to Wavelink.",
72+
emoji="<:wavelink:753851443093438545>",
73+
)
74+
75+
async def callback(self, interaction: discord.Interaction):
76+
if self.original_author != interaction.user:
77+
return await interaction.response.send_message(
78+
f"This menu is not for you. See `{core.CONFIG['prefix']}suggest` to make a suggestion!", ephemeral=True
79+
)
80+
author = self.original_author
81+
suggestion_type = get_suggestion_type(self.values[0])
82+
await interaction.response.send_message("Your suggestion has been sent!")
83+
embed = discord.Embed(
84+
title=f"Suggestion for {suggestion_type}", description=self.suggestion, timestamp=datetime.now(), color=0x7289DA
85+
)
86+
embed.set_author(name=author.name, icon_url=author.display_avatar)
87+
embed.set_footer(text=f"Suggestion sent by {author} (ID: {author.id})")
88+
await self.webhook.send(embed=embed, avatar_url=author.display_avatar, username=author.name)
89+
if self.message:
90+
await self.message.delete()
91+
92+
93+
class TypeView(ui.View):
94+
message: discord.Message | discord.WebhookMessage
95+
96+
def __init__(self, *, original_author: Union[discord.Member, discord.User], suggestion: str, webhook: discord.Webhook):
97+
super().__init__(timeout=180)
98+
self.original_author = original_author
99+
self.add_item(
100+
TypeSelect(original_author=original_author, suggestion=suggestion, webhook=webhook, message=self.message)
101+
)
102+
103+
async def on_timeout(self):
104+
await self.message.delete()
105+
await super().on_timeout()
106+
107+
108+
class Suggestions(core.Cog):
109+
def __init__(self, bot: core.Bot, url: str):
110+
self.bot = bot
111+
self.webhook = discord.Webhook.from_url(url, session=self.bot.session)
112+
113+
@commands.group(name="suggest", brief="Send a suggestion for the server, or a library.", invoke_without_command=True)
114+
async def suggest(self, ctx: core.Context, *, suggestion: str | None = None):
115+
if not suggestion:
116+
return await ctx.reply("Re-execute the command. Make sure to give your suggestion this time!")
117+
view = TypeView(original_author=ctx.author, suggestion=suggestion, webhook=self.webhook)
118+
view.message = await ctx.send(
119+
"Please select the type of suggestion this is. Your suggestion will not be sent until this step is completed.",
120+
view=view,
121+
)
122+
123+
124+
async def setup(bot: core.Bot):
125+
if key := core.CONFIG.get("SUGGESTIONS"):
126+
await bot.add_cog(Suggestions(bot, key["webhook_url"]))
127+
else:
128+
LOGGER.warning("Cannot load the SUGGESTIONS extension due to the `suggestions_webhook_url` config not existing.")

types_/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ class BadBin(TypedDict):
3131
domains: list[str]
3232

3333

34+
class Suggestions(TypedDict):
35+
webhook_url: str
36+
37+
3438
class Config(TypedDict):
3539
prefix: str
3640
owner_ids: NotRequired[list[int]]
@@ -39,3 +43,4 @@ class Config(TypedDict):
3943
LOGGING: Logging
4044
SNEKBOX: NotRequired[Snekbox]
4145
BADBIN: BadBin
46+
SUGGESTIONS: NotRequired[Suggestions]

0 commit comments

Comments
 (0)