Skip to content

Commit 3a0bbb7

Browse files
committed
Merge upstream main
1 parent 539e9de commit 3a0bbb7

19 files changed

+613
-272
lines changed

.github/ISSUE_TEMPLATE/bug_report.yml

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: Bug Report
2+
description: Report broken or incorrect behaviour
3+
labels: [unconfirmed bug]
4+
body:
5+
- type: markdown
6+
attributes:
7+
value: >
8+
Thanks for taking the time to fill out a bug.
9+
If you want real-time support, consider reaching out to the development team on Discord.
10+
11+
Please note that this form is for bugs only!
12+
- type: input
13+
attributes:
14+
label: Summary
15+
description: A simple summary of your bug report
16+
validations:
17+
required: true
18+
- type: textarea
19+
attributes:
20+
label: Reproduction Steps
21+
description: >
22+
What you did to make it happen.
23+
validations:
24+
required: true
25+
- type: textarea
26+
attributes:
27+
label: Minimal Reproducible Code
28+
description: >
29+
A short snippet of code that showcases the bug.
30+
render: Python
31+
- type: textarea
32+
attributes:
33+
label: Expected Results
34+
description: >
35+
What did you expect to happen?
36+
validations:
37+
required: true
38+
- type: textarea
39+
attributes:
40+
label: Actual Results
41+
description: >
42+
What actually happened?
43+
validations:
44+
required: true
45+
- type: textarea
46+
attributes:
47+
label: System Information
48+
description: >
49+
Run `python -m discord -v` and paste this information below.
50+
51+
This command required v1.1.0 or higher of the library. If this errors out then show some basic
52+
information involving your system such as operating system and Python version.
53+
validations:
54+
required: true
55+
- type: checkboxes
56+
attributes:
57+
label: Checklist
58+
description: >
59+
Let's make sure you've properly done due diligence when reporting this issue!
60+
options:
61+
- label: I have searched the open issues for duplicates.
62+
required: true
63+
- label: I have shown the entire traceback, if possible.
64+
required: true
65+
- type: textarea
66+
attributes:
67+
label: Additional Context
68+
description: If there is anything else to say, please do so here.
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Feature Request
2+
description: Suggest a feature for Rodhaj
3+
labels: [feature request]
4+
body:
5+
- type: input
6+
attributes:
7+
label: Summary
8+
description: >
9+
A short summary of what your feature request is.
10+
validations:
11+
required: true
12+
- type: dropdown
13+
attributes:
14+
multiple: false
15+
label: What is the feature request for?
16+
options:
17+
- Rodhaj
18+
- The documentation
19+
validations:
20+
required: true
21+
- type: textarea
22+
attributes:
23+
label: The Problem
24+
description: >
25+
What problem is your feature trying to solve?
26+
What becomes easier or possible when this feature is implemented?
27+
validations:
28+
required: true
29+
- type: textarea
30+
attributes:
31+
label: The Ideal Solution
32+
description: >
33+
What is your ideal solution to the problem?
34+
What would you like this feature to do?
35+
validations:
36+
required: true
37+
- type: textarea
38+
attributes:
39+
label: The Current Solution
40+
description: >
41+
What is the current solution to the problem, if any?
42+
validations:
43+
required: false
44+
- type: textarea
45+
attributes:
46+
label: Additional Context
47+
description: If there is anything else to say, please do so here.

.github/PULL_REQUEST_TEMPLATE.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Summary
2+
3+
<!-- What is this pull request for? Does it fix any issues? -->
4+
5+
## Types of changes
6+
7+
What types of changes does your code introduce to Rodhaj
8+
_Put an `x` in the boxes that apply_
9+
10+
- [ ] Bugfix (non-breaking change which fixes an issue)
11+
- [ ] New feature (non-breaking change which adds functionality)
12+
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
13+
- [ ] Documentation Update (Updates to README.md, the documentation, etc)
14+
- [ ] Other (if none of the other choices apply)
15+
16+
17+
## Checklist
18+
19+
<!-- Put an x inside [ ] to check it, like so: [x] -->
20+
21+
_Put an `x` in the boxes that apply_
22+
23+
- [ ] If code changes were made then they have been tested.
24+
- [ ] I have updated the documentation to reflect the changes. (if appropriate)
25+
- [ ] All workflows (except pre-commit.ci) pass with my new changes
26+
- [ ] This PR does **not** address a duplicate issue or PR

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ repos:
3030
stages: [commit]
3131

3232
- repo: https://github.com/astral-sh/ruff-pre-commit
33-
rev: v0.1.13
33+
rev: v0.1.14
3434
hooks:
3535
- id: ruff
3636
name: Ruff

bot/cogs/admin.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from discord.ext import commands
1111
from discord.ext.commands import Greedy
1212
from libs.utils import RoboContext
13+
1314
from rodhaj import Rodhaj
1415

1516
GIT_PULL_REGEX = re.compile(r"\s+(?P<filename>.*)\b\s+\|\s+[\d]")
@@ -104,7 +105,7 @@ def reload_lib_modules(self, module: str) -> list[tuple[str, str]]:
104105
# To learn more about it, see the link below (and ?tag ass on the dpy server):
105106
# https://about.abstractumbra.dev/discord.py/2023/01/29/sync-command-example.html
106107
@commands.guild_only()
107-
@commands.command(name="sync")
108+
@commands.command(name="sync", hidden=True)
108109
async def sync(
109110
self,
110111
ctx: RoboContext,

bot/cogs/config.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
import msgspec
88
from async_lru import alru_cache
99
from discord.ext import commands
10-
from libs.utils import GuildContext, is_manager
10+
from libs.utils import GuildContext
11+
from libs.utils.checks import bot_check_permissions, check_permissions
1112

1213
if TYPE_CHECKING:
1314
from rodhaj import Rodhaj
@@ -119,14 +120,16 @@ async def get_guild_config(self, guild_id: int) -> Optional[GuildConfig]:
119120
config = GuildConfig(bot=self.bot, **dict(rows))
120121
return config
121122

122-
@is_manager()
123+
@check_permissions(manage_guild=True)
124+
@bot_check_permissions(manage_channels=True, manage_webhooks=True)
123125
@commands.guild_only()
124126
@commands.hybrid_group(name="config")
125127
async def config(self, ctx: GuildContext) -> None:
126128
"""Commands to configure, setup, or delete Rodhaj"""
127129
if ctx.invoked_subcommand is None:
128130
await ctx.send_help(ctx.command)
129131

132+
@commands.cooldown(1, 20, commands.BucketType.guild)
130133
@config.command(name="setup", usage="ticket_name: <str> log_name: <str>")
131134
async def setup(self, ctx: GuildContext, *, flags: SetupFlags) -> None:
132135
"""First-time setup for Rodhaj
@@ -252,8 +255,8 @@ async def setup(self, ctx: GuildContext, *, flags: SetupFlags) -> None:
252255
return
253256

254257
query = """
255-
INSERT INTO guild_config (id, category_id, ticket_channel_id, logging_channel_id, logging_broadcast_url, ticket_broadcast_url)
256-
VALUES ($1, $2, $3, $4, $5, $6);
258+
INSERT INTO guild_config (id, category_id, ticket_channel_id, logging_channel_id, logging_broadcast_url, ticket_broadcast_url, prefix)
259+
VALUES ($1, $2, $3, $4, $5, $6, $7);
257260
"""
258261
try:
259262
await self.pool.execute(
@@ -264,6 +267,7 @@ async def setup(self, ctx: GuildContext, *, flags: SetupFlags) -> None:
264267
logging_channel.id,
265268
lgc_webhook.url,
266269
tc_webhook.url,
270+
[],
267271
)
268272
except asyncpg.UniqueViolationError:
269273
await ticket_channel.delete(reason=delete_reason)
@@ -278,6 +282,7 @@ async def setup(self, ctx: GuildContext, *, flags: SetupFlags) -> None:
278282
msg = f"Rodhaj channels successfully created! The ticket channel can be found under {ticket_channel.mention}"
279283
await ctx.send(msg)
280284

285+
@commands.cooldown(1, 20, commands.BucketType.guild)
281286
@config.command(name="delete")
282287
async def delete(self, ctx: GuildContext) -> None:
283288
"""Permanently deletes Rodhaj channels and tickets."""

bot/cogs/tickets.py

+20-22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
from functools import lru_cache
43
from typing import TYPE_CHECKING, Annotated, NamedTuple, Optional, Union
54

65
import asyncpg
@@ -14,16 +13,17 @@
1413
get_partial_ticket,
1514
safe_content,
1615
)
16+
from libs.utils.checks import bot_check_permissions
1717
from libs.utils.embeds import Embed, LoggingEmbed
1818

1919
from .config import GuildWebhookDispatcher
2020

2121
if TYPE_CHECKING:
2222
from libs.utils import GuildContext, RoboContext
23+
2324
from rodhaj import Rodhaj
2425

2526

26-
STAFF_ROLE = 1184257456419913798
2727
TICKET_EMOJI = "\U0001f3ab" # U+1F3AB Ticket
2828

2929

@@ -101,15 +101,6 @@ def add_status_checklist(
101101
) -> StatusChecklist:
102102
return self.in_progress_tickets.setdefault(author_id, status)
103103

104-
#### Determining staff
105-
106-
@lru_cache(maxsize=64)
107-
def get_staff(self, guild: discord.Guild) -> Optional[list[discord.Member]]:
108-
mod_role = guild.get_role(STAFF_ROLE)
109-
if mod_role is None:
110-
return None
111-
return [member for member in mod_role.members]
112-
113104
### Conditions for closing tickets
114105

115106
async def can_close_ticket(self, ctx: RoboContext):
@@ -128,22 +119,17 @@ async def can_close_ticket(self, ctx: RoboContext):
128119
return False
129120

130121
async def can_admin_close_ticket(self, ctx: RoboContext) -> bool:
131-
guild_id = self.bot.transprogrammer_guild_id
132-
guild = self.bot.get_guild(guild_id) or (await self.bot.fetch_guild(guild_id))
133-
staff_members = self.get_staff(guild)
134-
135-
if staff_members is None:
136-
return False
137-
138-
# TODO: Add the hierarchy system here
139-
staff_ids = [member.id for member in staff_members]
122+
# More than likely it will be closed through the threads
123+
# That means, it must be done in a guild. Thus, we know that
124+
# it will always be discord.Member
125+
perms = ctx.channel.permissions_for(ctx.author) # type: ignore
140126
from_ticket_channel = (
141127
isinstance(ctx.channel, discord.Thread)
142128
and ctx.partial_config is not None
143129
and ctx.channel.parent_id == ctx.partial_config.ticket_channel_id
144130
)
145131

146-
if ctx.author.id in staff_ids and from_ticket_channel is True:
132+
if perms.manage_threads and from_ticket_channel is True:
147133
return True
148134
return False
149135

@@ -319,10 +305,18 @@ def get_solved_tag(
319305

320306
### Feature commands
321307

308+
# This command requires the manage_threads permissions for the bot
322309
@is_ticket_or_dm()
310+
@bot_check_permissions(manage_threads=True)
311+
@commands.cooldown(1, 20, commands.BucketType.channel)
323312
@commands.hybrid_command(name="close", aliases=["solved", "closed", "resolved"])
324313
async def close(self, ctx: RoboContext) -> None:
325-
"""Closes the thread"""
314+
"""Closes a ticket
315+
316+
If someone requests to close the ticket
317+
and has Manage Threads permissions, then they can
318+
also close the ticket.
319+
"""
326320
query = """
327321
DELETE FROM tickets
328322
WHERE thread_id = $1 AND owner_id = $2;
@@ -356,7 +350,11 @@ async def close(self, ctx: RoboContext) -> None:
356350
self.get_ticket_owner_id.cache_invalidate(closed_ticket.id)
357351
await self.notify_finished_ticket(ctx, owner_id)
358352

353+
# 10 command invocations per 12 seconds for each member
354+
# These values should not be tripped unless someone is spamming
355+
# https://github.com/Rapptz/RoboDanny/blob/rewrite/cogs/mod.py#L524C9-L524C74
359356
@is_ticket_thread()
357+
@commands.cooldown(10, 12, commands.BucketType.member)
360358
@commands.command(name="reply", aliases=["r"])
361359
async def reply(
362360
self, ctx: GuildContext, *, message: Annotated[str, commands.clean_content]

0 commit comments

Comments
 (0)