Ruby-Cogs/referrals/commands/admin.py
2025-05-23 02:30:00 -04:00

277 lines
12 KiB
Python

import logging
import typing as t
from io import StringIO
import discord
from redbot.core import bank, commands
from redbot.core.i18n import Translator, cog_i18n
from redbot.core.utils.chat_formatting import humanize_timedelta
from ..abc import MixinMeta
from ..common import utils
from ..common.checks import ensure_db_connection
from ..db.tables import GuildSettings, Referral
from ..views.dynamic_menu import DynamicMenu
log = logging.getLogger("red.vrt.referrals.commands.admin")
_ = Translator("Referrals", __file__)
@cog_i18n(_)
class Admin(MixinMeta):
@commands.group(aliases=["refset", "referralset"])
@commands.guild_only()
@commands.admin_or_permissions(manage_guild=True)
async def referset(self, ctx: commands.Context):
"""Settings for the referral system"""
pass
@referset.command()
@ensure_db_connection()
async def view(self, ctx: commands.Context):
"""View the current settings for the guild"""
settings = await self.db_utils.get_create_guild(ctx.guild)
currency_name = await bank.get_currency_name(ctx.guild)
title = _("Referral System Settings")
embed = discord.Embed(title=title, color=await ctx.embed_color())
embed.add_field(
name=_("Status"),
value=_("`Enabled`") if settings.enabled else _("`Disabled`"),
inline=False,
)
embed.add_field(
name=_("Referral Reward"),
value=_("Amount of {} given to the person who referred someone: {}").format(
currency_name, f"`{settings.referral_reward}`"
),
inline=False,
)
embed.add_field(
name=_("Referred Reward"),
value=_("Amount of {} given to the person who was referred: {}").format(
currency_name, f"`{settings.referred_reward}`"
),
inline=False,
)
embed.add_field(
name=_("Referral Log"),
value=_("Channel where referral events are sent: {}").format(
f"<#{settings.referral_channel}>" if settings.referral_channel else _("`Not set`")
),
inline=False,
)
min_age = humanize_timedelta(seconds=settings.min_account_age_minutes * 60)
embed.add_field(
name=_("Minimum Account Age"),
value=_("Account of referred user must be at least {} old to make the claim.").format(f"`{min_age}`")
if settings.min_account_age_minutes
else _("There is no minimum account age requirement for users to claim their referral"),
inline=False,
)
claim_timeout = humanize_timedelta(seconds=settings.claim_timeout_minutes * 60)
embed.add_field(
name=_("Claim Timeout"),
value=_("Referral claims must be done within {} after joining.").format(f"`{claim_timeout}`")
if settings.claim_timeout_minutes
else _("Users have no time limit to claim their referral"),
inline=False,
)
embed.add_field(
name=_("Initialized Users"),
value=_("Users who have been initialized: {}").format(f"`{len(settings.initialized_users)}`"),
inline=False,
)
embed.add_field(
name=_("Referrals Claimed"),
value=_("Total referrals claimed: {}").format(
f"`{await Referral.count().where(Referral.guild == ctx.guild.id)}`"
),
)
await ctx.send(embed=embed)
@referset.command()
@ensure_db_connection()
async def listreferrals(self, ctx: commands.Context):
"""List all referrals made in the server"""
referrals = await Referral.objects().where(Referral.guild == ctx.guild.id)
if not referrals:
return await ctx.send(_("No referrals found in this server"))
color = await self.bot.get_embed_color(ctx)
embeds = []
chunk_size = 5
for idx, chunk in enumerate(utils.chunk(referrals, chunk_size)):
txt = StringIO()
for idxx, referral in enumerate(chunk, start=idx):
referrer = await self.bot.get_or_fetch_user(referral.referrer_id)
referred = await self.bot.get_or_fetch_user(referral.referred_id)
txt.write(f"{idxx + 1}. {referred} referred by {referrer}\n")
embed = discord.Embed(title=_("Referrals"), description=txt.getvalue(), color=color)
embed.set_footer(text=_("Page {}/{}").format(idx + 1, len(referrals)))
embeds.append(embed)
await DynamicMenu(ctx, embeds).refresh()
@referset.command()
@ensure_db_connection()
async def toggle(self, ctx: commands.Context):
"""Toggle the referral system on or off"""
settings = await self.db_utils.get_create_guild(ctx.guild)
settings.enabled = not settings.enabled
await settings.save()
await ctx.send(_("Referral system is now {}").format(_("enabled") if settings.enabled else _("disabled")))
@referset.command()
@ensure_db_connection()
async def reward(self, ctx: commands.Context, reward_type: t.Literal["referral", "referred"], amount: int):
"""Set the reward for referring or being referred
**Arguments:**
- `reward_type` - Either `referral` or `referred`
- `referral` - The reward for referring someone
- `referred` - The reward for being referred
- `amount` - The amount of currency to reward
*Set to 0 to disable the reward*
"""
settings = await self.db_utils.get_create_guild(ctx.guild)
currency_name = await bank.get_currency_name(ctx.guild)
if reward_type == "referral":
settings.referral_reward = amount
txt = _("The person who referred someone will receive {}").format(f"`{amount} {currency_name}`")
elif reward_type == "referred":
settings.referred_reward = amount
txt = _("The person who was referred will receive {}").format(f"`{amount} {currency_name}`")
else:
return await ctx.send_help()
await settings.save([GuildSettings.referral_reward, GuildSettings.referred_reward])
await ctx.send(txt)
@referset.command()
@ensure_db_connection()
async def channel(self, ctx: commands.Context, channel: discord.TextChannel = None):
"""Set the channel where referral events will be sent"""
settings = await self.db_utils.get_create_guild(ctx.guild)
if not channel and not settings.referral_channel:
return await ctx.send(_("Referral events are not being sent to any channel"))
settings.referral_channel = channel.id if channel else 0
await settings.save([GuildSettings.referral_channel])
if channel:
if not channel.permissions_for(ctx.me).send_messages:
return await ctx.send(_("I don't have permission to send messages in that channel"))
if not channel.permissions_for(ctx.me).embed_links:
return await ctx.send(_("I don't have permission to send embeds in that channel"))
await ctx.send(_("Referral events will be sent to {}").format(channel.mention))
else:
await ctx.send(_("Referral events will no longer be sent to a channel"))
@referset.command()
@ensure_db_connection()
async def age(self, ctx: commands.Context, age: str):
"""Set the minimum account age for referred users to be eligible for rewards
- `age` - The minimum account age in the format of `30m`, `1h`, `2d12h`, etc.
"""
settings = await self.db_utils.get_create_guild(ctx.guild)
if "none" in age.lower():
delta = None
else:
try:
delta = commands.parse_timedelta(age)
except ValueError:
delta = None
if delta is None:
settings.min_account_age_minutes = 0
txt = _("Account age restriction removed")
else:
settings.min_account_age_minutes = int(delta.total_seconds() / 60)
txt = _("The minimum account age required to claim a referral is {}").format(
f"`{humanize_timedelta(timedelta=delta)}`"
)
await settings.save([GuildSettings.min_account_age_minutes])
await ctx.send(txt)
@referset.command()
@ensure_db_connection()
async def timeout(self, ctx: commands.Context, timeout: str):
"""Set the time frame for users to claim their reward after joining
- `timeout` - The time frame in the format of `30m`, `1h`, `2d12h`, etc.
"""
settings = await self.db_utils.get_create_guild(ctx.guild)
if "none" in timeout.lower():
delta = None
else:
try:
delta = commands.parse_timedelta(timeout)
except ValueError:
delta = None
if delta is None:
settings.claim_timeout_minutes = 0
txt = _("Claim timeout removed")
else:
settings.claim_timeout_minutes = int(delta.total_seconds() / 60)
txt = _("Users will have {} to claim their referral after joining.").format(
f"`{humanize_timedelta(timedelta=delta)}"
)
await settings.save([GuildSettings.claim_timeout_minutes])
await ctx.send(txt)
@referset.command(aliases=["initialize"])
@ensure_db_connection()
async def init(self, ctx: commands.Context):
"""Initialize all unreferred users in the server so they cannot retroactively claim rewards"""
settings = await self.db_utils.get_create_guild(ctx.guild)
referrals: list[int] = (
await Referral.select(Referral.referred_id).where(Referral.guild == ctx.guild.id).output(as_list=True)
)
guild_members: list[int] = [member.id for member in ctx.guild.members]
unreferred = list(set(guild_members) - set(referrals))
if not unreferred:
return await ctx.send(_("All users have been initialized"))
new_refs = list(set(unreferred + settings.initialized_users))
settings.initialized_users = new_refs
await GuildSettings.raw(
"UPDATE guild_settings SET initialized_users = {} WHERE id = {}", new_refs, ctx.guild.id
)
await ctx.send(_("Initialized {} users").format(len(unreferred)))
@referset.command()
@ensure_db_connection()
async def resetall(self, ctx: commands.Context, confirm: bool):
"""Reset all referral data for the guild"""
if not confirm:
return await ctx.send(_("Rerun this with `True` to comfirm"))
await Referral.delete().where(Referral.guild == ctx.guild.id)
await GuildSettings.delete().where(GuildSettings.id == ctx.guild.id)
await ctx.send(_("All referral data has been reset for this server"))
@referset.command()
@ensure_db_connection()
async def resetreferrals(self, ctx: commands.Context, confirm: bool):
"""Reset all referral data for the guild"""
if not confirm:
return await ctx.send(_("Rerun this with `True` to confirm"))
await Referral.delete().where(Referral.guild == ctx.guild.id)
await ctx.send(_("All referral data has been reset for this server"))
@referset.command()
@ensure_db_connection()
async def resetsettings(self, ctx: commands.Context, confirm: bool):
"""Reset all referral data for the guild"""
if not confirm:
return await ctx.send(_("Rerun this with `True` to confirm"))
await GuildSettings.delete().where(GuildSettings.id == ctx.guild.id)
await ctx.send(_("All referral settings have been reset for this server"))
@referset.command()
@ensure_db_connection()
async def resetinitialized(self, ctx: commands.Context, confirm: bool):
"""Reset all referral data for the guild"""
if not confirm:
return await ctx.send(_("Rerun this with `True` to confirm"))
settings = await self.db_utils.get_create_guild(ctx.guild)
settings.initialized_users = []
await settings.save([GuildSettings.initialized_users])
await ctx.send(_("All initialized users have been reset for this server"))