-
-
Notifications
You must be signed in to change notification settings - Fork 717
Patreon #1917
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Patreon #1917
Changes from all commits
6ca77ac
a44e798
526ce5f
380dd5c
b38ec72
9abea85
feb1b47
b1f31da
241c27b
3f32352
24c549f
0502044
0b8e507
8705488
6cf0f6d
ccc2767
68b382a
2b916ce
0b83f58
bc2c8c5
12308ee
c360365
02a02bf
95a07ba
af50cc4
f3aa56a
051bc5c
0c52dbf
0d4d6b9
f9a4fb1
1af289d
d470a18
b923b52
00330f6
3a2b576
7fe0d60
7e6e3ca
e93a949
228deaf
1fbe38b
1784014
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import datetime | ||
|
||
import arrow | ||
import discord | ||
from discord.ext import commands, tasks | ||
|
||
from bot import constants | ||
from bot.bot import Bot | ||
from bot.constants import Channels, Guild, Roles, STAFF_PARTNERS_COMMUNITY_ROLES | ||
from bot.decorators import in_whitelist | ||
from bot.log import get_logger | ||
from bot.utils.channel import get_or_fetch_channel | ||
|
||
log = get_logger(__name__) | ||
|
||
PATREON_INFORMATION = ( | ||
"Python Discord is a volunteer run non-profit organization, so we rely on Patreon donations to do what we do. " | ||
"We use the money we get to offer excellent prizes for all of our events. These include t-shirts, " | ||
"stickers, and sometimes even Raspberry Pis!\n\n" | ||
"You can read more about how Patreon donations help us, and consider donating yourself, on our patreon page " | ||
"[here](https://pydis.com/patreon)!" | ||
) | ||
NO_PATRONS_MESSAGE = "*There are currently no patrons at this tier.*" | ||
|
||
# List of tuples containing tier number and Discord role ID. | ||
# Ordered from highest tier to lowest. | ||
PATREON_TIERS: list[tuple[int, int]] = [ | ||
(3, Roles.patreon_tier_3), | ||
(2, Roles.patreon_tier_2), | ||
(1, Roles.patreon_tier_1), | ||
] | ||
|
||
|
||
def get_patreon_tier(member: discord.Member) -> int: | ||
""" | ||
Get the patreon tier of `member`. | ||
|
||
A patreon tier of 0 indicates the user is not a patron. | ||
""" | ||
for tier, role_id in PATREON_TIERS: | ||
if member.get_role(role_id): | ||
return tier | ||
return 0 | ||
|
||
|
||
class Patreon(commands.Cog): | ||
"""Cog that shows patreon supporters.""" | ||
|
||
def __init__(self, bot: Bot) -> None: | ||
self.bot = bot | ||
|
||
self.current_monthly_supporters.start() | ||
|
||
@commands.Cog.listener() | ||
async def on_member_update(self, before: discord.Member, after: discord.Member) -> None: | ||
"""Send a message when someone receives a patreon role.""" | ||
old_patreon_tier = get_patreon_tier(before) | ||
new_patreon_tier = get_patreon_tier(after) | ||
Comment on lines
+54
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This has an inherent dependency on how the patreon bot works. If the patreon bot decided to take away and giveth the new role in two seperate api requests, this would cease to work. Or, if the patreon bot were to take the old role away and then give the new role, this would also cease to work. This all hinges on the patreon bot making a single api request, and would lead to funky behaviour if their bot used more than one request--and I believe it does. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this should be an issue. Whatever order things happen there will still only be one member_update that involves the tier increasing, which is all that this checks. The only slightly unintended case would be if a user moves down a tier (e.g. from 3 to 2), and the bot does this by removing 3 and then adding 2. In this case the message would be sent, although it still wouldn't be incorrect (Just saying they are now a tier 2 patron). Fixing this would probably require waiting for other role changes to see if they change things, although this could be fairly complicated so I think it would be best to see how what we have currently works out. |
||
|
||
if new_patreon_tier <= old_patreon_tier: | ||
return | ||
|
||
message = ( | ||
f":tada: {after.mention} just became a **tier {new_patreon_tier}** patron!\n" | ||
"Support us on Patreon: https://pydis.com/patreon" | ||
) | ||
channel = await get_or_fetch_channel(Channels.meta) | ||
await channel.send(message) | ||
|
||
async def send_current_supporters(self, channel: discord.abc.Messageable, automatic: bool = False) -> None: | ||
"""Send the current list of patreon supporters, sorted by tier level.""" | ||
guild = self.bot.get_guild(Guild.id) | ||
|
||
embed_list = [] | ||
for tier, role_id in PATREON_TIERS: | ||
role = guild.get_role(role_id) | ||
|
||
# Filter out any members where this is not their highest tier. | ||
patrons = [member for member in role.members if get_patreon_tier(member) == tier] | ||
TizzySaurus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
patron_names = [f"• {patron}" for patron in patrons] | ||
wookie184 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
embed = discord.Embed( | ||
title=role.name, | ||
description="\n".join(patron_names) if patron_names else NO_PATRONS_MESSAGE, | ||
colour=role.colour | ||
) | ||
embed_list.append(embed) | ||
|
||
main_embed = discord.Embed( | ||
title="Patreon Supporters - Monthly Update" if automatic else "Patreon Supporters", | ||
description=( | ||
wookie184 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
PATREON_INFORMATION + | ||
"\n\nThank you to the users listed below who are already supporting us!" | ||
), | ||
) | ||
|
||
await channel.send(embeds=(main_embed, *embed_list)) | ||
TizzySaurus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
@commands.group("patreon", aliases=("patron",), invoke_without_command=True) | ||
async def patreon_info(self, ctx: commands.Context) -> None: | ||
TizzySaurus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"""Send information about how Python Discord uses Patreon.""" | ||
embed = discord.Embed( | ||
title="Patreon", | ||
description=( | ||
PATREON_INFORMATION + | ||
"\n\nTo see our current supporters, run " + | ||
f"`{constants.Bot.prefix}patreon supporters` in <#{Channels.bot_commands}>" | ||
) | ||
) | ||
await ctx.send(embed=embed) | ||
|
||
@patreon_info.command("supporters", aliases=("patrons",)) | ||
@in_whitelist(channels=(Channels.bot_commands,), roles=STAFF_PARTNERS_COMMUNITY_ROLES) | ||
async def patreon_supporters(self, ctx: commands.Context) -> None: | ||
"""Sends the current list of patreon supporters, sorted by tier level.""" | ||
await self.send_current_supporters(ctx.channel) | ||
|
||
@tasks.loop(time=datetime.time(hour=17)) | ||
async def current_monthly_supporters(self) -> None: | ||
"""A loop running daily to see if it's the first of the month. If so call `self.send_current_supporters()`.""" | ||
now = arrow.utcnow() | ||
if now.day == 1: | ||
meta_channel = await get_or_fetch_channel(Channels.meta) | ||
await self.send_current_supporters(meta_channel, automatic=True) | ||
|
||
|
||
async def setup(bot: Bot) -> None: | ||
"""Load the Patreon cog.""" | ||
await bot.add_cog(Patreon(bot)) |
Uh oh!
There was an error while loading. Please reload this page.