Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ SENTRY_URL=
PRODUCTION_BOT_TOKEN=
DEVELOPMENT_BOT_TOKEN=
BLOXLINK_API_KEY=
# DO NOT CHANGE, EVEN IF YOU'RE SELF HOSTING
CUSTOM_GUILD_ID=0

# If you want to use a custom DB name (instead of `erm`), uncomment this and enable it
# DB_NAME=

Expand Down
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ Per [documentation/coding-assistants.md](documentation/coding-assistants.md):

## Gotchas

- `CUSTOM_GUILD_ID` must remain `0` — do not change
- `DB_NAME` defaults to `erm`; uncomment in `.env` only if needed
- `GITHUB_TOKEN` is reserved for future use, not used by the bot
- Database schema reference: [documentation/database-schema.md](documentation/database-schema.md)
10 changes: 4 additions & 6 deletions cogs/Search.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ async def mywarnings(
roblox_id=roblox_player.id
)

if member and bot.environment != "CUSTOM":
if member:
try:
discord_member = await guild.fetch_member(member.discord_id)
except discord.NotFound:
Expand All @@ -113,8 +113,7 @@ async def mywarnings(
for role in discord_member.roles
if role.id in magic_flags_reverse
)
elif member and bot.environment == "CUSTOM":
applied_flags.update(["ERM Staff"])


applied_flags = list(applied_flags)
if (
Expand Down Expand Up @@ -356,7 +355,7 @@ async def search(self, ctx, *, query):
roblox_id=roblox_player.id
)

if member and bot.environment != "CUSTOM":
if member:
try:
discord_member = await guild.fetch_member(member.discord_id)
except discord.NotFound:
Expand All @@ -368,8 +367,7 @@ async def search(self, ctx, *, query):
for role in discord_member.roles
if role.id in magic_flags_reverse
)
elif member and bot.environment == "CUSTOM":
applied_flags.update(["ERM Staff"])


applied_flags = list(applied_flags)
if (
Expand Down
2 changes: 0 additions & 2 deletions documentation/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,6 @@ staggered 30-second delay between each to avoid startup load spikes.
`REMINDERS_ENABLED` and `ACTIONS_ENABLED` respectively and will not
start if those are set to `FALSE`.

`change_status` does not run when `ENVIRONMENT=CUSTOM`.

---

## Data Layer
Expand Down
87 changes: 2 additions & 85 deletions erm.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ async def rate_limited_fetch(coro, endpoint_type="default"):
raise

setup = False
accepted_envs = ["PRODUCTION", "DEVELOPMENT", "ALPHA", "CUSTOM"]
accepted_envs = ["PRODUCTION", "DEVELOPMENT", "ALPHA"]


sentry_url = config("SENTRY_URL", "")
Expand Down Expand Up @@ -141,9 +141,6 @@ async def is_owner(self, user: discord.User):
# Else fall back to the original
if user.id == 1394817794427846737:
return True

if environment != "CUSTOM": # let's not allow custom bot owners to use jishaku lol
return await super().is_owner(user)
else:
return False

Expand Down Expand Up @@ -208,13 +205,6 @@ async def setup_hook(self) -> None:

self.accounts = Accounts(self)

if environment == "CUSTOM":
doc = await self.whitelabel.db.find_one({"GuildID": config("CUSTOM_GUILD_ID", default="0")})
if not doc:
raise Exception(
"Custom guild ID not found in the database. This means the whitelabel subscription is overdue."
)

self.roblox = roblox.Client()
self.prc_api = PRCApiClient(
self,
Expand Down Expand Up @@ -279,11 +269,7 @@ async def setup_hook(self) -> None:
if environment == "DEVELOPMENT":
pass
# await bot.tree.sync(guild=discord.Object(id=987798554972143728))
elif environment == "CUSTOM":
await self.tree.sync()
# Prevent auto syncing
# await bot.tree.sync()
# guild specific: leave blank if global (global registration can take 1-24 hours)

bot.is_synced = True
self.saved_latencies = {
"shards": [],
Expand All @@ -310,9 +296,6 @@ async def setup_hook(self) -> None:



if config("ENVIRONMENT") == "CUSTOM":
Bot.__bases__ = (commands.Bot,)

bot = Bot(
command_prefix=get_prefix,
case_insensitive=True,
Expand Down Expand Up @@ -342,38 +325,7 @@ def running():

@bot.before_invoke
async def AutoDefer(ctx: commands.Context):
if (
environment == "CUSTOM"
and config("CUSTOM_GUILD_ID", default="0") != "0"
and not getattr(ctx.bot, "whitelist_disabled", False)
):
if ctx.guild.id != int(config("CUSTOM_GUILD_ID")):
if ctx.interaction:
await ctx.interaction.response.send_message(
embed=discord.Embed(
title="Not Permitted",
description="This bot is not permitted to be used in this server. You can change this in the **Whitelabel Bot Dashboard**.",
color=BLANK_COLOR,
),
ephemeral=True,
)
raise Exception(f"Guild not permitted to use this bot: {ctx.guild.id}")

guild_id = ctx.guild.id
if (environment != "CUSTOM" or int(config("CUSTOM_GUILD_ID", default="0")) != guild_id) and await has_whitelabel(bot, guild_id):
if "jishaku" in ctx.command.qualified_name:
return
if ctx.interaction:
await ctx.interaction.response.send_message(
embed=discord.Embed(
title="Not Permitted",
description="There is a whitelabel bot already in this server.",
color=BLANK_COLOR,
),
ephemeral=True,
)
raise Exception("Whitelabel bot already in use")

bot.internal_command_storage[ctx.message.id] = datetime.datetime.now(tz=pytz.UTC).timestamp()
if ctx.command:
if ctx.command.extras.get("ephemeral") is True:
Expand Down Expand Up @@ -408,41 +360,6 @@ async def loggingCommandExecution(ctx: commands.Context):
"Command could not be found in internal context storage. Please report."
)


@bot.event
async def on_message(
message,
): # DO NOT COG

if not message.guild:
return await bot.process_commands(message)

if (
environment == "CUSTOM"
and config("CUSTOM_GUILD_ID", default=None) != 0
and not getattr(bot, "whitelist_disabled", False)
):
if message.guild.id != int(config("CUSTOM_GUILD_ID")):
ctx = await bot.get_context(message)
if ctx.command is not None:
await message.reply(
embed=discord.Embed(
title="Not Permitted",
description="This bot is not permitted to be used in this server. You can change this in the **Whitelabel Bot Dashboard**.",
color=BLANK_COLOR,
)
)
return

if environment == "PRODUCTION" and await bot.whitelabel.db.find_one({"GuildID": str(message.guild.id)}) is not None:
return

await bot.process_commands(message)


client = roblox.Client()


async def staff_check(bot_obj, guild, member):
guild_settings = await bot_obj.settings.find_by_id(guild.id)
member_role_ids = [r.id for r in member.roles]
Expand Down
2 changes: 0 additions & 2 deletions events/on_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ async def on_message(self, message: discord.Message):
if not message.guild:
return

if await has_whitelabel(bot, message.guild.id) and (bot.environment != "CUSTOM" or int(config("CUSTOM_GUILD_ID", default="0")) != message.guild.id):
return

if not hasattr(bot, "settings"):
return
Expand Down
10 changes: 1 addition & 9 deletions tasks/check_reminders.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ async def process_reminder(bot, guild, item, guild_obj):

async def iterate_reminder(bot, guild_obj):
"""Iterate through all reminders for a guild and process any that are due."""
if await has_whitelabel(bot, guild_obj["_id"]):
return


guild = bot.get_guild(int(guild_obj["_id"]))
if not guild:
Expand All @@ -145,13 +144,6 @@ async def iterate_reminder(bot, guild_obj):
@tasks.loop(minutes=1)
async def check_reminders(bot):
query = {}
if bot.environment != "PRODUCTION":
try:
query = {"_id": int(config("CUSTOM_GUILD_ID"))}
except Exception as e:
logging.warning(f"Reminder task failed: {e}")
return

try:
for guild_obj in await bot.reminders.db.find(query).to_list(None):
try:
Expand Down
45 changes: 45 additions & 0 deletions tasks/check_whitelabel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import discord
from discord.ext import tasks
from erm import Bot
import datetime
import aiohttp



@tasks.loop(hours=2)
async def check_whitelabel(bot: Bot):
async for item in bot.whitelabel.db.find({}):
try:
print(item)
if item["GuildID"] == 0:
await bot.whitelabel.delete(item["_id"])
continue
try:
guild = await bot.fetch_guild(int(item["GuildID"])) # looking at the db, guild ids aren't always ints
except:
return
try:
owner = await guild.fetch_member(int(item["DiscordID"]))
except:
return
bot_member = guild.me or guild.get_member(bot.user.id) or await guild.fetch_member(bot.user.id)

print(bot_member)
time = datetime.datetime.now(tz=datetime.UTC)
expiry = datetime.datetime.fromtimestamp(item["Expiry"], tz=datetime.UTC)
if expiry < time:
await owner.send(embed=discord.Embed(
title="Whitelabel Subscription Expired",
description="Your whitelabel subscription has expired, therefore, the avatar, banner, and bio will be reset. Please renew your subscription through the web dashboard or open a ticket if you need assistance."
))
await bot_member.edit(avatar=None, banner=None, bio=None, reason="Whitelabel subscription expired")
return

session = aiohttp.ClientSession()
av = await (await session.get(item["UserData"]["AvatarURL"])).read()
banner = await (await session.get(item["UserData"]["BannerURL"])).read()
await bot_member.edit(avatar=av, banner=banner, bio=item["UserData"]["Bio"])
except Exception as e:
print(str(e))
continue

2 changes: 1 addition & 1 deletion tasks/iterate_ics.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ async def iterate_ics(bot):
# This will aim to constantly update the Integration Command Storage
# and the relevant storage data.

async for item in bot.ics.db.find({} if bot.environment in ["PRODUCTION", "ALPHA", "DEVELOPMENT"] else {"guild": config("CUSTOM_GUILD_ID")}):
async for item in bot.ics.db.find({}):
guild = bot.get_guild(item["guild"])

if not guild:
Expand Down
46 changes: 23 additions & 23 deletions tasks/iterate_prc_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@

count_aggregate = global_aggregate + [{"$count": "total"}]


async def iterate_prc_logs_global(bot):
@tasks.loop(minutes=5, reconnect=True)
async def iterate_prc_logs(bot):
try:
server_count_list = await (await bot.settings.db.aggregate(count_aggregate)).to_list(length=None)
server_count_list = [i async for i in await bot.settings.db.aggregate(count_aggregate)]
server_count = server_count_list[0]["total"] if server_count_list else 0

logging.warning(f"[ITERATE] Starting iteration for {server_count} servers")
Expand Down Expand Up @@ -78,16 +78,7 @@ async def iterate_prc_logs_global(bot):



async def iterate_prc_logs_custom(bot):
guild_id = config("CUSTOM_GUILD_ID")
if not guild_id:
logging.info("No custom guild ID provided for custom environment")
return

try:
await unprimitive_guild_process({"_id": int(guild_id)}, bot)
except Exception as e:
logging.warning(f"error processing guild: {e}")

async def unprimitive_guild_process(items, bot):
guild = bot.get_guild(items["_id"]) or await bot.fetch_guild(
Expand All @@ -98,9 +89,6 @@ async def unprimitive_guild_process(items, bot):
settings = await bot.settings.find_by_id(guild.id)
erlc_settings = settings.get("ERLC", {})

if await has_whitelabel(bot, guild.id) and not config("CUSTOM_GUILD_ID") == str(guild.id):
logging.warning("Not handling {} due to whitelabel instance existing")
return

channels = {
"kill_logs": erlc_settings.get("kill_logs"),
Expand Down Expand Up @@ -209,6 +197,7 @@ async def unprimitive_guild_process(items, bot):
await asyncio.gather(*subtasks, return_exceptions=True)

await bot.log_tracker.save_guild(guild.id)
await flush_pending_unbans(bot, guild.id)

async def process_guild(bot, items, semaphore):
async with semaphore:
Expand All @@ -221,14 +210,6 @@ async def process_guild(bot, items, semaphore):
logging.warning(f"error processing guild: {e}")


@tasks.loop(minutes=7, reconnect=True)
async def iterate_prc_logs(bot):
if bot.environment == "PRODUCTION":
await iterate_prc_logs_global(bot)
else:
await iterate_prc_logs_custom(
bot
)


async def fetch_logs_with_retry(guild_id, bot, retries=3):
Expand Down Expand Up @@ -535,6 +516,25 @@ async def process_player_logs(bot, settings, guild_id, player_logs, last_timesta
return embeds, latest_timestamp


async def flush_pending_unbans(bot, guild_id: int):
now = int(datetime.datetime.now(tz=pytz.UTC).timestamp())
pending = bot.punishments.db.find({
"Guild": guild_id,
"CheckExecuted": {"$exists": False},
"UntilEpoch": {"$lt": now},
"Type": "Temporary Ban",
"Epoch": {"$gt": 1709164800},
})
async for item in pending:
try:
await bot.prc_api.unban_user(guild_id, item["UserID"])
item["CheckExecuted"] = True
await bot.punishments.update_by_id(item)
await asyncio.sleep(1)
except Exception:
break


async def is_username_found(username: str, members: list[discord.Member]) -> bool:
pattern = re.compile(re.escape(username), re.IGNORECASE)
member_found = False
Expand Down
Loading
Loading