Skip to content

Commit

Permalink
Moved role and thread gathering to own thread
Browse files Browse the repository at this point in the history
  • Loading branch information
TheCataliasTNT2k committed Oct 1, 2024
1 parent 855b5c3 commit 4df4f63
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 106 deletions.
102 changes: 56 additions & 46 deletions administration/roles/cog.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from typing import Dict, List, Optional, Union

from discord import Embed, Forbidden, Guild, Member, NotFound, Permissions, Role, Status, User
from discord import Embed, Forbidden, Guild, Member, NotFound, Permissions, Role, Status, User, Bot
from discord.ext import commands
from discord.ext.commands import CommandError, Context, Group, UserInputError, guild_only

from PyDrocsid.async_thread import run_as_task
from PyDrocsid.cog import Cog
from PyDrocsid.command import docs, optional_permissions, reply
from PyDrocsid.config import Config
from PyDrocsid.converter import UserMemberConverter
from PyDrocsid.database import db, filter_by, select
from PyDrocsid.database import db, filter_by, select, db_wrapper
from PyDrocsid.embeds import send_long_embed
from PyDrocsid.emojis import name_to_emoji
from PyDrocsid.prefix import get_prefix
Expand All @@ -27,6 +28,57 @@
t = t.roles


@run_as_task
@db_wrapper
async def calculate_role_list(ctx: Context, role: Role, bot: Bot):
await ctx.trigger_typing()
member_ids: set[int] = {member.id for member in role.members}
perma: dict[int, str] = {}

perma_role: PermaRole
async for perma_role in await db.stream(filter_by(PermaRole, role_id=role.id)):
try:
user = await bot.fetch_user(perma_role.member_id)
except NotFound:
continue

member_ids.add(user.id)
perma[user.id] = str(user)

members: list[Member] = []
for member_id in [*member_ids]:
if not (member := ctx.guild.get_member(member_id)):
continue

members.append(member)
member_ids.remove(member_id)

members.sort(
key=lambda m: ([Status.online, Status.idle, Status.dnd, Status.offline].index(m.status), str(m), m.id)
)

out = []
for member in members:
out.append(f"{status_icon(member.status)} {member.mention} (@{member})")
if member.id in perma:
out[-1] += " :shield:"
if role not in member.roles:
out[-1] += " :warning:"

for member_id, member_name in perma.items():
if member_id not in member_ids:
continue

out.append(f":grey_question: <@{member_id}> (@{member_name}) :shield:")

if out:
embed = Embed(title=t.member_list_cnt(role.name, cnt=len(out)), colour=0x256BE6, description="\n".join(out))
else:
embed = Embed(title=t.member_list, colour=0xCF0606, description=t.no_members)
await send_long_embed(ctx, embed, paginate=True)



async def configure_role(ctx: Context, role_name: str, role: Role, check_assignable: bool = False):
if check_assignable:
check_role_assignable(role)
Expand Down Expand Up @@ -350,51 +402,9 @@ async def roles_perma_unset(self, ctx: Context, member: UserMemberConverter, *,
@roles.command(name="list", aliases=["l", "?"])
@RolesPermission.list_members.check
@docs(t.commands.roles_list)
async def roles_list(self, ctx: Context, *, role: Role):
member_ids: set[int] = {member.id for member in role.members}
perma: dict[int, str] = {}
async def roles_list(self, ctx: Context, role: Role):
await calculate_role_list(ctx, role, self.bot)

perma_role: PermaRole
async for perma_role in await db.stream(filter_by(PermaRole, role_id=role.id)):
try:
user = await self.bot.fetch_user(perma_role.member_id)
except NotFound:
continue

member_ids.add(user.id)
perma[user.id] = str(user)

members: list[Member] = []
for member_id in [*member_ids]:
if not (member := ctx.guild.get_member(member_id)):
continue

members.append(member)
member_ids.remove(member_id)

members.sort(
key=lambda m: ([Status.online, Status.idle, Status.dnd, Status.offline].index(m.status), str(m), m.id)
)

out = []
for member in members:
out.append(f"{status_icon(member.status)} {member.mention} (@{member})")
if member.id in perma:
out[-1] += " :shield:"
if role not in member.roles:
out[-1] += " :warning:"

for member_id, member_name in perma.items():
if member_id not in member_ids:
continue

out.append(f":grey_question: <@{member_id}> (@{member_name}) :shield:")

if out:
embed = Embed(title=t.member_list_cnt(role.name, cnt=len(out)), colour=0x256BE6, description="\n".join(out))
else:
embed = Embed(title=t.member_list, colour=0xCF0606, description=t.no_members)
await send_long_embed(ctx, embed, paginate=True)

@roles.command(name="perma_list", aliases=["pl", "ll", "??"])
@RolesPermission.list_members.check
Expand Down
127 changes: 67 additions & 60 deletions moderation/threads/cog.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import asyncio
from datetime import datetime
from datetime import datetime, timedelta
from typing import Optional

from discord import Embed, Forbidden, Role, TextChannel, Thread
from discord.ext import commands
from discord.ext.commands import Context, guild_only
from discord.utils import format_dt, snowflake_time
from discord.utils import format_dt, snowflake_time, utcnow

from PyDrocsid.async_thread import semaphore_gather
from PyDrocsid.async_thread import semaphore_gather, run_as_task
from PyDrocsid.cog import Cog
from PyDrocsid.command import docs
from PyDrocsid.embeds import send_long_embed
Expand All @@ -25,13 +25,76 @@
t = t.threads


@run_as_task
async def work_threads(ctx: Context):
await ctx.trigger_typing()

async def get_threads(channel: TextChannel) -> list[tuple[Thread, bool]]:
out_ = channel.threads.copy()
out_ += await channel.archived_threads(limit=None).flatten()
if channel.permissions_for(ctx.guild.me).manage_threads and not channel.is_news():
out_ += await channel.archived_threads(limit=None, private=True).flatten()
return [
(thread_, any(member.id == ctx.author.id for member in await thread_.fetch_members()))
for thread_ in out_
]

def last_timestamp(thread: Thread) -> datetime:
return snowflake_time(thread.last_message_id)

msg = await ctx.reply(t.gathering_threads)

threads = [
*{
thread
for threads in await semaphore_gather(
5,
*[
get_threads(channel)
for channel in ctx.guild.text_channels
if channel.permissions_for(ctx.guild.me).read_message_history
and channel.permissions_for(ctx.author).view_channel
],
)
for thread in threads
}
]
threads.sort(key=lambda x: last_timestamp(x[0]), reverse=True)

out = []
thread: Thread
for thread, joined in threads:
if not thread.permissions_for(ctx.author).view_channel:
continue

line = f":small_{'blue' if thread.archived else 'orange'}_diamond: "
line += ":white_check_mark: " if joined else ":x: "
if thread.archived:
line += f"[#{thread.name}](https://discord.com/channels/{thread.guild.id}/{thread.id})"
else:
line += f"{thread.mention}"
line += f" ({thread.parent.mention}, {format_dt(last_timestamp(thread), style='R')})"
out.append(line)

embed = Embed(title=t.threads, description="\n".join(out), color=Colors.Threads)
if not out:
embed.description = t.no_threads
embed.colour = Colors.error
await msg.delete()

await send_long_embed(ctx, embed, paginate=True)



class ThreadsCog(Cog, name="Thread Utils"):
CONTRIBUTORS = [Contributor.Defelo]

async def on_thread_create(self, thread: Thread):
await self.on_thread_join(thread)

async def on_thread_join(self, thread: Thread):
if thread.created_at < utcnow() - timedelta(hours=1):
return
if await redis.exists(key := f"thread_created:{thread.id}"):
return
await redis.setex(key, 24 * 3600, "1")
Expand All @@ -52,60 +115,4 @@ async def on_thread_join(self, thread: Thread):
@guild_only()
@docs(t.commands.threads)
async def threads(self, ctx: Context):

await ctx.trigger_typing()

async def get_threads(channel: TextChannel) -> list[tuple[Thread, bool]]:
out_ = channel.threads.copy()
out_ += await channel.archived_threads(limit=None).flatten()
if channel.permissions_for(ctx.guild.me).manage_threads and not channel.is_news():
out_ += await channel.archived_threads(limit=None, private=True).flatten()
return [
(thread_, any(member.id == ctx.author.id for member in await thread_.fetch_members()))
for thread_ in out_
]

def last_timestamp(thread: Thread) -> datetime:
return snowflake_time(thread.last_message_id)

msg = await ctx.reply(t.gathering_threads)

threads = [
*{
thread
for threads in await semaphore_gather(
5,
*[
get_threads(channel)
for channel in ctx.guild.text_channels
if channel.permissions_for(ctx.guild.me).read_message_history
and channel.permissions_for(ctx.author).view_channel
],
)
for thread in threads
}
]
threads.sort(key=lambda x: last_timestamp(x[0]), reverse=True)

out = []
thread: Thread
for thread, joined in threads:
if not thread.permissions_for(ctx.author).view_channel:
continue

line = f":small_{'blue' if thread.archived else 'orange'}_diamond: "
line += ":white_check_mark: " if joined else ":x: "
if thread.archived:
line += f"[#{thread.name}](https://discord.com/channels/{thread.guild.id}/{thread.id})"
else:
line += f"{thread.mention}"
line += f" ({thread.parent.mention}, {format_dt(last_timestamp(thread), style='R')})"
out.append(line)

embed = Embed(title=t.threads, description="\n".join(out), color=Colors.Threads)
if not out:
embed.description = t.no_threads
embed.colour = Colors.error
await msg.delete()

await send_long_embed(ctx, embed, paginate=True)
await work_threads(ctx)

0 comments on commit 4df4f63

Please sign in to comment.