mirror of
https://github.com/nexy7574/LCC-bot.git
synced 2024-09-19 18:16:34 +01:00
Add starboard
This commit is contained in:
parent
9d8a41ee4a
commit
93ca4386fd
5 changed files with 175 additions and 17 deletions
|
@ -370,17 +370,15 @@ class AssignmentsCog(commands.Cog):
|
||||||
else:
|
else:
|
||||||
option = 10080
|
option = 10080
|
||||||
name = textwrap.shorten(modal.create_kwargs["title"], width=100, placeholder="...")
|
name = textwrap.shorten(modal.create_kwargs["title"], width=100, placeholder="...")
|
||||||
tag = discord.utils.get(channel.available_tags, name=modal.create_kwargs['tutor'].name.title())
|
tag = discord.utils.get(channel.available_tags, name=modal.create_kwargs["tutor"].name.title())
|
||||||
await channel.create_thread(
|
await channel.create_thread(
|
||||||
name=name,
|
name=name,
|
||||||
content="Assignment name: {0}\nDue: {1} ({4})\nTutor: {2}\nCreated by: {3}".format(
|
content="Assignment name: {0}\nDue: {1} ({4})\nTutor: {2}\nCreated by: {3}".format(
|
||||||
modal.create_kwargs["title"],
|
modal.create_kwargs["title"],
|
||||||
discord.utils.format_dt(
|
discord.utils.format_dt(due_dt, style="F"),
|
||||||
due_dt, style="F"
|
|
||||||
),
|
|
||||||
modal.create_kwargs["tutor"].name,
|
modal.create_kwargs["tutor"].name,
|
||||||
ctx.user.mention,
|
ctx.user.mention,
|
||||||
discord.utils.format_dt(due_dt, "R")
|
discord.utils.format_dt(due_dt, "R"),
|
||||||
),
|
),
|
||||||
auto_archive_duration=option,
|
auto_archive_duration=option,
|
||||||
applied_tags=[tag] if tag else [],
|
applied_tags=[tag] if tag else [],
|
||||||
|
|
140
cogs/starboard.py
Normal file
140
cogs/starboard.py
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
import asyncio
|
||||||
|
import textwrap
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.db import StarBoardMessage
|
||||||
|
|
||||||
|
|
||||||
|
class StarBoardCog(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
self.lock = asyncio.Lock()
|
||||||
|
|
||||||
|
async def generate_starboard_embed(self, message: discord.Message) -> discord.Embed:
|
||||||
|
star_count = [x for x in message.reactions if str(x.emoji) == "\N{white medium star}"]
|
||||||
|
if not star_count:
|
||||||
|
star_count = 0
|
||||||
|
else:
|
||||||
|
star_count = star_count[0].count
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
|
cap = (message.channel if "thread" in message.channel.type.name else message.guild).member_count * 0.1
|
||||||
|
embed = discord.Embed(colour=discord.Colour.gold(), timestamp=message.created_at, description=message.content)
|
||||||
|
embed.set_author(
|
||||||
|
name=message.author.display_name, url=message.jump_url, icon_url=message.author.display_avatar.url
|
||||||
|
)
|
||||||
|
|
||||||
|
if star_count > 5:
|
||||||
|
stars = "\N{white medium star}x{:,}".format(star_count)
|
||||||
|
else:
|
||||||
|
stars = "\N{white medium star}" * star_count
|
||||||
|
stars = stars or "\N{no entry sign}"
|
||||||
|
|
||||||
|
embed.add_field(
|
||||||
|
name="Info",
|
||||||
|
value=f"Star count: {stars}\n"
|
||||||
|
f"Channel: {message.channel.mention}\n"
|
||||||
|
f"Author: {message.author.mention}\n"
|
||||||
|
f"URL: [jump]({message.jump_url})\n"
|
||||||
|
f"Sent: {discord.utils.format_dt(message.created_at, 'R')}",
|
||||||
|
inline=False,
|
||||||
|
)
|
||||||
|
if message.edited_at:
|
||||||
|
embed.fields[0].value += "\nLast edited: " + discord.utils.format_dt(message.edited_at, "R")
|
||||||
|
|
||||||
|
if message.reference is not None:
|
||||||
|
try:
|
||||||
|
ref: discord.Message = await self.bot.get_channel(message.reference.channel_id).fetch_message(
|
||||||
|
message.reference.message_id
|
||||||
|
)
|
||||||
|
except discord.HTTPException:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
embed.add_field(
|
||||||
|
name="In reply to",
|
||||||
|
value=f"[Message by {ref.author.display_name}]({ref.jump_url}):\n>>> ",
|
||||||
|
inline=False,
|
||||||
|
)
|
||||||
|
field = embed.fields[1]
|
||||||
|
if not ref.content:
|
||||||
|
embed.fields[1].value = field.value.replace(":\n>>> ", "")
|
||||||
|
else:
|
||||||
|
embed.fields[1].value += textwrap.shorten(ref.content, 1024 - len(field.value), placeholder="...")
|
||||||
|
|
||||||
|
if message.attachments:
|
||||||
|
for file in message.attachments:
|
||||||
|
name = f"Attachment #{message.attachments.index(file)}"
|
||||||
|
spoiler = file.is_spoiler()
|
||||||
|
if not spoiler and file.url.lower().endswith(("png", "jpeg", "jpg", "gif", "webp")) and not embed.image:
|
||||||
|
embed.set_image(url=file.url)
|
||||||
|
elif spoiler:
|
||||||
|
embed.add_field(name=name, value=f"||[{file.filename}]({file.url})||", inline=False)
|
||||||
|
else:
|
||||||
|
embed.add_field(name=name, value=f"[{file.filename}]({file.url})", inline=False)
|
||||||
|
|
||||||
|
embed.set_footer(text="Starboard threshold for this message was {:.2f}.".format(cap))
|
||||||
|
return embed
|
||||||
|
|
||||||
|
@commands.Cog.listener("on_raw_reaction_add")
|
||||||
|
@commands.Cog.listener("on_raw_reaction_remove")
|
||||||
|
async def on_star_add(self, payload: discord.RawReactionActionEvent):
|
||||||
|
async with self.lock:
|
||||||
|
if str(payload.emoji) != "\N{white medium star}":
|
||||||
|
return
|
||||||
|
message: discord.Message = await self.bot.get_channel(payload.channel_id).fetch_message(payload.message_id)
|
||||||
|
star_count = [x for x in message.reactions if str(x.emoji) == "\N{white medium star}"]
|
||||||
|
if not star_count:
|
||||||
|
star_count = 0
|
||||||
|
else:
|
||||||
|
star_count = star_count[0].count
|
||||||
|
database: Tuple[StarBoardMessage, bool] = await StarBoardMessage.objects.get_or_create(
|
||||||
|
{"channel": payload.channel_id}, id=payload.message_id
|
||||||
|
)
|
||||||
|
entry, created = database
|
||||||
|
if created:
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
|
cap = message.channel if "thread" in message.channel.type.name else message.guild
|
||||||
|
if self.bot.intents.members and hasattr(cap, "members"):
|
||||||
|
cap = len([x for x in cap.members if not x.bot]) * 0.1
|
||||||
|
else:
|
||||||
|
cap = cap.member_count * 0.1
|
||||||
|
if star_count >= cap:
|
||||||
|
channel = discord.utils.get(message.guild.text_channels, name="starboard")
|
||||||
|
if channel and channel.can_send():
|
||||||
|
msg = await channel.send(embed=await self.generate_starboard_embed(message))
|
||||||
|
await entry.update(starboard_message=msg.id)
|
||||||
|
else:
|
||||||
|
await entry.delete()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
channel = discord.utils.get(message.guild.text_channels, name="starboard")
|
||||||
|
if channel and channel.can_send() and entry.starboard_message:
|
||||||
|
try:
|
||||||
|
msg = await channel.fetch_message(entry.starboard_message)
|
||||||
|
except discord.NotFound:
|
||||||
|
msg = await channel.send(embed=await self.generate_starboard_embed(message))
|
||||||
|
await entry.update(starboard_message=msg.id)
|
||||||
|
except discord.HTTPException:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
await msg.edit(embed=await self.generate_starboard_embed(message))
|
||||||
|
|
||||||
|
@commands.message_command(name="Starboard Info")
|
||||||
|
@discord.guild_only()
|
||||||
|
async def get_starboard_info(self, ctx: discord.ApplicationContext, message: discord.Message):
|
||||||
|
return await ctx.respond(embed=await self.generate_starboard_embed(message))
|
||||||
|
|
||||||
|
@commands.command(name="threshold")
|
||||||
|
@commands.guild_only()
|
||||||
|
async def get_threshold(self, ctx: commands.Context):
|
||||||
|
"""Shows you the current starboard threshold"""
|
||||||
|
if self.bot.intents.members and hasattr(ctx.channel, "members"):
|
||||||
|
cap = len([x for x in ctx.channel.members if not x.bot]) * 0.1
|
||||||
|
else:
|
||||||
|
cap = ctx.channel.member_count * 0.1
|
||||||
|
return await ctx.reply(f"Messages currently need {c:.2f} stars in this channel to be posted to the starboard.")
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(StarBoardCog(bot))
|
11
main.py
11
main.py
|
@ -13,7 +13,16 @@ bot = commands.Bot(
|
||||||
)
|
)
|
||||||
bot.training_lock = Lock()
|
bot.training_lock = Lock()
|
||||||
|
|
||||||
extensions = ["jishaku", "cogs.verify", "cogs.mod", "cogs.events", "cogs.assignments", "cogs.timetable", "cogs.other"]
|
extensions = [
|
||||||
|
"jishaku",
|
||||||
|
"cogs.verify",
|
||||||
|
"cogs.mod",
|
||||||
|
"cogs.events",
|
||||||
|
"cogs.assignments",
|
||||||
|
"cogs.timetable",
|
||||||
|
"cogs.other",
|
||||||
|
"cogs.starboard",
|
||||||
|
]
|
||||||
for ext in extensions:
|
for ext in extensions:
|
||||||
bot.load_extension(ext)
|
bot.load_extension(ext)
|
||||||
console.log(f"Loaded extension [green]{ext}")
|
console.log(f"Loaded extension [green]{ext}")
|
||||||
|
|
17
utils/db.py
17
utils/db.py
|
@ -119,3 +119,20 @@ class Assignments(orm.Model):
|
||||||
submitted: bool
|
submitted: bool
|
||||||
assignees: list[int]
|
assignees: list[int]
|
||||||
# description: Optional[str]
|
# description: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
class StarBoardMessage(orm.Model):
|
||||||
|
tablename = "starboard"
|
||||||
|
registry = registry
|
||||||
|
fields = {
|
||||||
|
"entry_id": orm.UUID(primary_key=True, default=uuid.uuid4),
|
||||||
|
"id": orm.BigInteger(unique=True),
|
||||||
|
"channel": orm.BigInteger(),
|
||||||
|
"starboard_message": orm.BigInteger(default=None, allow_null=True),
|
||||||
|
}
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
entry_id: uuid.UUID
|
||||||
|
id: int
|
||||||
|
channel: int
|
||||||
|
starboard_message: int | None
|
||||||
|
|
|
@ -57,9 +57,7 @@ class VerifyView(View):
|
||||||
f" (originally associated with account {ban.associated_account})"
|
f" (originally associated with account {ban.associated_account})"
|
||||||
)
|
)
|
||||||
await Student.objects.create(
|
await Student.objects.create(
|
||||||
id=existing.student_id,
|
id=existing.student_id, user_id=interaction.user.id, name=existing.name
|
||||||
user_id=interaction.user.id,
|
|
||||||
name=existing.name
|
|
||||||
)
|
)
|
||||||
await existing.delete()
|
await existing.delete()
|
||||||
role = discord.utils.find(lambda r: r.name.lower() == "verified", interaction.guild.roles)
|
role = discord.utils.find(lambda r: r.name.lower() == "verified", interaction.guild.roles)
|
||||||
|
@ -67,10 +65,7 @@ class VerifyView(View):
|
||||||
if role and role < interaction.guild.me.top_role:
|
if role and role < interaction.guild.me.top_role:
|
||||||
await member.add_roles(role, reason="Verified")
|
await member.add_roles(role, reason="Verified")
|
||||||
try:
|
try:
|
||||||
await member.edit(
|
await member.edit(nick=f"{existing.name}", reason="Verified")
|
||||||
nick=f"{existing.name}",
|
|
||||||
reason="Verified"
|
|
||||||
)
|
|
||||||
except discord.HTTPException:
|
except discord.HTTPException:
|
||||||
pass
|
pass
|
||||||
console.log(f"[green]{interaction.user} verified ({interaction.user.id}/{existing.student_id})")
|
console.log(f"[green]{interaction.user} verified ({interaction.user.id}/{existing.student_id})")
|
||||||
|
@ -118,16 +113,15 @@ class VerifyView(View):
|
||||||
return await interaction.followup.send(
|
return await interaction.followup.send(
|
||||||
"\N{cross mark} Invalid student ID - Failed to verify with regex."
|
"\N{cross mark} Invalid student ID - Failed to verify with regex."
|
||||||
" Please try again with a valid student ID. Make sure it is formatted as `BXXXXXX` "
|
" Please try again with a valid student ID. Make sure it is formatted as `BXXXXXX` "
|
||||||
"(e.g. `B{}`)".format(''.join(str(random.randint(0, 9)) for _ in range(6))),
|
"(e.g. `B{}`)".format("".join(str(random.randint(0, 9)) for _ in range(6))),
|
||||||
delete_after=60
|
delete_after=60,
|
||||||
)
|
)
|
||||||
|
|
||||||
ex = await get_or_none(Student, id=st)
|
ex = await get_or_none(Student, id=st)
|
||||||
if ex:
|
if ex:
|
||||||
btn.disabled = False
|
btn.disabled = False
|
||||||
return await interaction.followup.send(
|
return await interaction.followup.send(
|
||||||
"\N{cross mark} Student ID is already associated.",
|
"\N{cross mark} Student ID is already associated.", delete_after=60
|
||||||
delete_after=60
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in a new issue