make docstrings consistent
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a4b889cf54
commit
4d58d33063
13 files changed
+185
-85
No files matched your search
@@ -31,7 +31,7 @@ class BotInfo(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Memory usage
|
# Memory usage
|
||||||
@@ -99,7 +99,7 @@ class BotInfo(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
embed = discord.Embed(color=interaction.client.user.color)
|
embed = discord.Embed(color=interaction.client.user.color)
|
||||||
@@ -115,7 +115,7 @@ class BotInfo(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
embed = discord.Embed(color=interaction.client.user.color)
|
embed = discord.Embed(color=interaction.client.user.color)
|
||||||
@@ -128,7 +128,7 @@ class BotInfo(commands.Cog):
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
----------
|
----------
|
||||||
(int) The bot's ping in milliseconds
|
(int): The bot's ping in milliseconds
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return int(self.bot.latency * 1000)
|
return int(self.bot.latency * 1000)
|
||||||
@@ -139,7 +139,7 @@ class BotInfo(commands.Cog):
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
----------
|
----------
|
||||||
(str) The bot's uptime in human readable format
|
(str): The bot's uptime in human readable format
|
||||||
"""
|
"""
|
||||||
|
|
||||||
now = time()
|
now = time()
|
||||||
@@ -157,7 +157,7 @@ async def setup(bot: commands.Bot):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
bot (commands.Bot): Bot instance
|
bot (commands.Bot): The bot instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await bot.add_cog(BotInfo(bot))
|
await bot.add_cog(BotInfo(bot))
|
||||||
@@ -29,7 +29,7 @@ class DevTools(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Context object
|
ctx (commands.Context): The command context
|
||||||
activity_type (str): The type of activity to set the bot's status to
|
activity_type (str): The type of activity to set the bot's status to
|
||||||
message (str): The message to set the bot's status to
|
message (str): The message to set the bot's status to
|
||||||
status_type (str): The type of status to set the bot's status to
|
status_type (str): The type of status to set the bot's status to
|
||||||
@@ -60,7 +60,7 @@ class DevTools(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Context object
|
ctx (commands.Context): The command context
|
||||||
guild_id (int): The ID of the guild to leave
|
guild_id (int): The ID of the guild to leave
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ class DevTools(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Context object
|
ctx (commands.Context): The command context
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not ctx.invoked_subcommand:
|
if not ctx.invoked_subcommand:
|
||||||
@@ -117,7 +117,7 @@ class DevTools(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Context object
|
ctx (commands.Context): The command context
|
||||||
cog (str): The name of the cog to disable
|
cog (str): The name of the cog to disable
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ class DevTools(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Context object
|
ctx (commands.Context): The command context
|
||||||
cog (str): The name of the cog to enable
|
cog (str): The name of the cog to enable
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ class DevTools(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Context object
|
ctx (commands.Context): The command context
|
||||||
cog (str): The name of the cog to reload
|
cog (str): The name of the cog to reload
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ class DevTools(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Context object
|
ctx (commands.Context): The command context
|
||||||
"""
|
"""
|
||||||
|
|
||||||
extensions = [f"cogs.{file[:-3]}" for file in listdir("./src/cogs") if file.endswith(".py")]
|
extensions = [f"cogs.{file[:-3]}" for file in listdir("./src/cogs") if file.endswith(".py")]
|
||||||
@@ -205,7 +205,7 @@ class DevTools(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Context object
|
ctx (commands.Context): The command context
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Only loaded cogs can be reloaded. Copied to a list since reloading modifies bot.extensions
|
# Only loaded cogs can be reloaded. Copied to a list since reloading modifies bot.extensions
|
||||||
@@ -267,7 +267,7 @@ async def setup(bot: commands.Bot):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
bot (commands.Bot): Bot instance
|
bot (commands.Bot): The bot instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await bot.add_cog(DevTools(bot))
|
await bot.add_cog(DevTools(bot))
|
||||||
@@ -27,7 +27,7 @@ class Errors(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Context object
|
ctx (commands.Context): The command context
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.bot.logger.info(
|
self.bot.logger.info(
|
||||||
@@ -45,7 +45,7 @@ class Errors(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
command (app_commands.Command | app_commands.ContextMenu): Command object
|
command (app_commands.Command | app_commands.ContextMenu): Command object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -62,8 +62,8 @@ class Errors(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Context object
|
ctx (commands.Context): The command context
|
||||||
error (commands.CommandError): Eror context object
|
error (commands.CommandError): The error the command raised
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Failed commands don't count towards the cooldown, unless the failure is the cooldown itself.
|
# Failed commands don't count towards the cooldown, unless the failure is the cooldown itself.
|
||||||
@@ -133,8 +133,8 @@ class Errors(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
error (app_commands.AppCommandError): Eror context object
|
error (app_commands.AppCommandError): The error the command raised
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The command may have deferred or responded before it failed
|
# The command may have deferred or responded before it failed
|
||||||
@@ -196,7 +196,7 @@ async def setup(bot: commands.Bot):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
bot (commands.Bot): Bot instance
|
bot (commands.Bot): The bot instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await bot.add_cog(Errors(bot))
|
await bot.add_cog(Errors(bot))
|
||||||
+33
-5
@@ -42,6 +42,10 @@ class Galtinn(commands.Cog):
|
|||||||
self.session: aiohttp.ClientSession | None = None
|
self.session: aiohttp.ClientSession | None = None
|
||||||
|
|
||||||
async def cog_load(self):
|
async def cog_load(self):
|
||||||
|
"""
|
||||||
|
Open the Galtinn session, set up the database listener and start the background tasks
|
||||||
|
"""
|
||||||
|
|
||||||
# One session for all Galtinn requests, so connections are reused
|
# One session for all Galtinn requests, so connections are reused
|
||||||
self.session = aiohttp.ClientSession(
|
self.session = aiohttp.ClientSession(
|
||||||
headers={"Authorization": f"Token {self.bot.galtinn['auth_token']}"},
|
headers={"Authorization": f"Token {self.bot.galtinn['auth_token']}"},
|
||||||
@@ -55,6 +59,10 @@ class Galtinn(commands.Cog):
|
|||||||
self.verification_cleanup.start()
|
self.verification_cleanup.start()
|
||||||
|
|
||||||
async def cog_unload(self):
|
async def cog_unload(self):
|
||||||
|
"""
|
||||||
|
Stop the background tasks and close the database listener and the Galtinn session
|
||||||
|
"""
|
||||||
|
|
||||||
self.bot.logger.info("Unloading cog")
|
self.bot.logger.info("Unloading cog")
|
||||||
self.membership_check.cancel()
|
self.membership_check.cancel()
|
||||||
self.verification_cleanup.cancel()
|
self.verification_cleanup.cancel()
|
||||||
@@ -122,6 +130,10 @@ class Galtinn(commands.Cog):
|
|||||||
def on_listen_conn_terminated(self, conn: asyncpg.Connection):
|
def on_listen_conn_terminated(self, conn: asyncpg.Connection):
|
||||||
"""
|
"""
|
||||||
Starts reconnecting the listener if its connection is lost, e.g. on a database restart
|
Starts reconnecting the listener if its connection is lost, e.g. on a database restart
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
conn (asyncpg.Connection): The connection that was lost
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Connections closed on cog unload are detached before closing
|
# Connections closed on cog unload are detached before closing
|
||||||
@@ -153,6 +165,13 @@ class Galtinn(commands.Cog):
|
|||||||
async def process_notification(self, conn: asyncpg.Connection, pid: int, channel: str, payload: str):
|
async def process_notification(self, conn: asyncpg.Connection, pid: int, channel: str, payload: str):
|
||||||
"""
|
"""
|
||||||
Applies Galtinn roles to a user that has just completed verification
|
Applies Galtinn roles to a user that has just completed verification
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
conn (asyncpg.Connection): The connection that received the notification
|
||||||
|
pid (int): The ID of the database process that sent the notification
|
||||||
|
channel (str): The notification channel
|
||||||
|
payload (str): The Discord user ID and the Galtinn user ID, separated by a space
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.bot.logger.info("Received galtinn_auth_complete event from database")
|
self.bot.logger.info("Received galtinn_auth_complete event from database")
|
||||||
@@ -242,6 +261,10 @@ class Galtinn(commands.Cog):
|
|||||||
async def fetch_galtinn_users(self, discord_id: int | None = None) -> Users | None:
|
async def fetch_galtinn_users(self, discord_id: int | None = None) -> Users | None:
|
||||||
"""
|
"""
|
||||||
Attempts to fetch user(s) from Galtinn. If no Discord ID is given, all users are fetched
|
Attempts to fetch user(s) from Galtinn. If no Discord ID is given, all users are fetched
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
discord_id (int | None): The Discord ID of the user to fetch
|
||||||
"""
|
"""
|
||||||
|
|
||||||
params = {"no_discord_id": False}
|
params = {"no_discord_id": False}
|
||||||
@@ -255,6 +278,11 @@ class Galtinn(commands.Cog):
|
|||||||
) -> DiscordProfiles | None:
|
) -> DiscordProfiles | None:
|
||||||
"""
|
"""
|
||||||
Attempts to fetch discord profile(s) from Galtinn. If no parameters are given, all profiles are fetched
|
Attempts to fetch discord profile(s) from Galtinn. If no parameters are given, all profiles are fetched
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
galtinn_user_id (int | None): Only fetch the profile of this Galtinn user
|
||||||
|
discord_id (int | None): Only fetch the profile with this Discord ID
|
||||||
"""
|
"""
|
||||||
|
|
||||||
params = {}
|
params = {}
|
||||||
@@ -278,7 +306,7 @@ class Galtinn(commands.Cog):
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
----------
|
----------
|
||||||
set(int): Set of role ids
|
(set[int]): Set of role ids
|
||||||
"""
|
"""
|
||||||
|
|
||||||
all_roles = {self.bot.galtinn_roles["volunteer"], self.bot.galtinn_roles["member"]}
|
all_roles = {self.bot.galtinn_roles["volunteer"], self.bot.galtinn_roles["member"]}
|
||||||
@@ -493,7 +521,7 @@ class Galtinn(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await interaction.response.defer(ephemeral=True)
|
await interaction.response.defer(ephemeral=True)
|
||||||
@@ -566,7 +594,7 @@ class Galtinn(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: add confirmation button
|
# TODO: add confirmation button
|
||||||
@@ -627,7 +655,7 @@ class Galtinn(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Discord ignores guild_only on subcommands, and the rest of the group has to work in DMs
|
# Discord ignores guild_only on subcommands, and the rest of the group has to work in DMs
|
||||||
@@ -686,7 +714,7 @@ async def setup(bot: commands.Bot):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
bot (commands.Bot): Bot instance
|
bot (commands.Bot): The bot instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await bot.add_cog(Galtinn(bot))
|
await bot.add_cog(Galtinn(bot))
|
||||||
+24
-24
@@ -31,7 +31,7 @@ class Info(commands.Cog):
|
|||||||
roles (list[discord.Role]): List of roles
|
roles (list[discord.Role]): List of roles
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
----------
|
||||||
(str): String of roles
|
(str): String of roles
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -50,11 +50,11 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
join_method (callable): Function to join the boosters with
|
join_method (callable): Function to join the boosters with
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
----------
|
||||||
(str): String of boosters
|
(str): String of boosters
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ class Info(commands.Cog):
|
|||||||
members (list[discord.Member]): List of members
|
members (list[discord.Member]): List of members
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
----------
|
||||||
(str): String of members
|
(str): String of members
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Days since guild was created
|
# Days since guild was created
|
||||||
@@ -254,7 +254,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
roles = self.construct_role_string(interaction.guild.roles)
|
roles = self.construct_role_string(interaction.guild.roles)
|
||||||
@@ -277,7 +277,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if len(interaction.guild.premium_subscribers) == 0:
|
if len(interaction.guild.premium_subscribers) == 0:
|
||||||
@@ -302,7 +302,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not interaction.guild.icon:
|
if not interaction.guild.icon:
|
||||||
@@ -323,7 +323,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not interaction.guild.splash:
|
if not interaction.guild.splash:
|
||||||
@@ -344,7 +344,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not interaction.guild.banner:
|
if not interaction.guild.banner:
|
||||||
@@ -367,7 +367,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
role (discord.Role): Role to fetch information about
|
role (discord.Role): Role to fetch information about
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -413,7 +413,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
channel (discord.TextChannel): Text channel to fetch information about
|
channel (discord.TextChannel): Text channel to fetch information about
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -447,7 +447,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
channel (discord.VoiceChannel): Voice channel to fetch information about
|
channel (discord.VoiceChannel): Voice channel to fetch information about
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -472,7 +472,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
roles = sorted(
|
roles = sorted(
|
||||||
@@ -501,7 +501,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ctx (commands.Context): Command context object
|
ctx (commands.Context): The command context
|
||||||
emoji (discord.Emoji): Emoji to fetch information about
|
emoji (discord.Emoji): Emoji to fetch information about
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -534,7 +534,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Sort members by creation date
|
# Sort members by creation date
|
||||||
@@ -566,7 +566,7 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Sort members by creation date
|
# Sort members by creation date
|
||||||
@@ -597,8 +597,8 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
user (discord.Member, optional): User to get information about. Defaults to None (invoker).
|
user (discord.Member | None): User to get information about. Defaults to the invoking user
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
@@ -693,8 +693,8 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
user (discord.Member, optional): User to get roles of. Defaults to None (invoker).
|
user (discord.Member | None): User to get roles of. Defaults to the invoking user
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
@@ -724,8 +724,8 @@ class Info(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
user (discord.User, optional): User to get avatar of. Defaults to None (invoker).
|
user (discord.User | None): User to get avatar of. Defaults to the invoking user
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
@@ -743,7 +743,7 @@ async def setup(bot: commands.Bot):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
bot (commands.Bot): Bot instance
|
bot (commands.Bot): The bot instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await bot.add_cog(Info(bot))
|
await bot.add_cog(Info(bot))
|
||||||
@@ -12,7 +12,7 @@ async def send_as_txt_file(interaction: discord.Interaction, content: str, filen
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
content (str): String that's too long to send
|
content (str): String that's too long to send
|
||||||
filename (str): Name of the file shown in Discord
|
filename (str): Name of the file shown in Discord
|
||||||
"""
|
"""
|
||||||
@@ -27,7 +27,7 @@ async def get_discord_guild(bot: commands.Bot, id: int) -> discord.Guild | None:
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
bot (commands.Bot): Bot instance
|
bot (commands.Bot): The bot instance
|
||||||
id (int): ID of the object
|
id (int): ID of the object
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@@ -56,7 +56,7 @@ async def get_guild_member(bot: commands.Bot, guild: discord.Guild, user_id: int
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
bot (commands.Bot): Bot instance
|
bot (commands.Bot): The bot instance
|
||||||
guild (discord.Guild): The discord guild to fetch the member from
|
guild (discord.Guild): The discord guild to fetch the member from
|
||||||
user_id (int): ID of the user
|
user_id (int): ID of the user
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ async def get_guild_roles(bot: commands.Bot, guild: discord.Guild, role_ids: set
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
bot (commands.Bot): Bot instance
|
bot (commands.Bot): The bot instance
|
||||||
guild (discord.Guild): The discord guild to fetch the roles from
|
guild (discord.Guild): The discord guild to fetch the roles from
|
||||||
role_ids (set[int]): IDs of the roles
|
role_ids (set[int]): IDs of the roles
|
||||||
|
|
||||||
@@ -123,11 +123,13 @@ class ScrollerButton(discord.ui.Button):
|
|||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
----------
|
||||||
paginator (Paginator): The paginator object that contains the data to be paginated
|
paginator (Paginator): The paginator object that contains the data to be paginated
|
||||||
button_action (callable): The function that returns the requested page
|
button_action (callable): The function that returns the requested page
|
||||||
content_constructor (callable): A function that takes a paginator object and a page number and returns an embed
|
content_constructor (callable): A function that takes a paginator object and a page number and returns an embed
|
||||||
owner (discord.User|discord.Member): The user that invoked the paginator. Only this user can use the button
|
owner (discord.User | discord.Member): The user that invoked the paginator. Only this user can use the button
|
||||||
|
label (str): The text on the button
|
||||||
|
disabled (bool): Whether the button is greyed out
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__(label=label, disabled=disabled)
|
super().__init__(label=label, disabled=disabled)
|
||||||
@@ -141,8 +143,8 @@ class ScrollerButton(discord.ui.Button):
|
|||||||
What to do when the button is pressed
|
What to do when the button is pressed
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The interaction that triggered this
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if interaction.user.id != self.owner.id:
|
if interaction.user.id != self.owner.id:
|
||||||
@@ -163,20 +165,20 @@ class Scroller(discord.ui.View):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
paginatior: misc_utils.Paginator,
|
paginator: misc_utils.Paginator,
|
||||||
owner: discord.User | discord.Member,
|
owner: discord.User | discord.Member,
|
||||||
content_constructor: callable = None,
|
content_constructor: callable = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
----------
|
||||||
paginator (Paginator): The paginator object that contains the data to be paginated
|
paginator (Paginator): The paginator object that contains the data to be paginated
|
||||||
owner (discord.User|discord.Member): The user that invoked the paginator. Only this user can use the buttons
|
owner (discord.User | discord.Member): The user that invoked the paginator. Only this user can use the buttons
|
||||||
content_constructor (callable): A function that takes a paginator object and a page number and returns an embed
|
content_constructor (callable): A function that takes a paginator object and a page number and returns an embed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.paginator = paginatior
|
self.paginator = paginator
|
||||||
self.content_constructor = content_constructor if content_constructor else self.__default_content_constructor
|
self.content_constructor = content_constructor if content_constructor else self.__default_content_constructor
|
||||||
|
|
||||||
self.add_item(
|
self.add_item(
|
||||||
@@ -225,7 +227,7 @@ class Scroller(discord.ui.View):
|
|||||||
Constructs the embed to be displayed
|
Constructs the embed to be displayed
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
----------
|
||||||
base_embed (discord.Embed): The base embed to add fields to
|
base_embed (discord.Embed): The base embed to add fields to
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -237,8 +239,7 @@ class Scroller(discord.ui.View):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
paginator (Paginator): Paginator dataclass
|
page (list): The items to show on the page
|
||||||
page (list): List of streaks to display on a page
|
|
||||||
embed (discord.Embed): Embed to add fields to
|
embed (discord.Embed): Embed to add fields to
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ def error_warning(text: str) -> discord.Embed:
|
|||||||
Creates an embed with a specified error message based on a warning template
|
Creates an embed with a specified error message based on a warning template
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
----------
|
||||||
text (str): The error message
|
text (str): The error message
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-----------
|
----------
|
||||||
(discord.Embed): An embed object based on the template with the specified text
|
(discord.Embed): An embed object based on the template with the specified text
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -23,11 +23,11 @@ def error_fatal(text: str) -> discord.Embed:
|
|||||||
Creates an embed with a specified error message based on a warning template
|
Creates an embed with a specified error message based on a warning template
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
----------
|
||||||
text (str): The error message
|
text (str): The error message
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-----------
|
----------
|
||||||
(discord.Embed): An embed object based on the template with the specified text
|
(discord.Embed): An embed object based on the template with the specified text
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -40,12 +40,12 @@ def success(text: str) -> discord.Embed:
|
|||||||
Creates an embed with a specified message using a template signifying success.
|
Creates an embed with a specified message using a template signifying success.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
----------
|
||||||
text (str): The message
|
text (str): The message
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-----------
|
----------
|
||||||
discord.Embed: An embed object based on the template with the specified text
|
(discord.Embed): An embed object based on the template with the specified text
|
||||||
"""
|
"""
|
||||||
|
|
||||||
embed = discord.Embed(color=discord.Color.green(), description=f"✅ {text}")
|
embed = discord.Embed(color=discord.Color.green(), description=f"✅ {text}")
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class Paginator:
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
----------
|
----------
|
||||||
(list|None): The page you requested
|
(list | None): The page you requested
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if page < 1 or page > self.total_page_count:
|
if page < 1 or page > self.total_page_count:
|
||||||
|
|||||||
+11
-11
@@ -26,7 +26,7 @@ async def query_api(session: aiohttp.ClientSession, params: dict) -> dict:
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
----------
|
----------
|
||||||
dict: The JSON response
|
(dict): The JSON response
|
||||||
|
|
||||||
Raises
|
Raises
|
||||||
----------
|
----------
|
||||||
@@ -53,7 +53,7 @@ async def fetch_article(session: aiohttp.ClientSession, title: str):
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
----------
|
----------
|
||||||
tuple: The title, url, text and image of the article
|
(tuple): The title, url, text and image of the article
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The wiki renders the article to HTML for us, so templates are already expanded
|
# The wiki renders the article to HTML for us, so templates are already expanded
|
||||||
@@ -194,7 +194,7 @@ def viteboka_embed(title: str, url: str, text: str, image: str):
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
----------
|
----------
|
||||||
discord.Embed: The embed
|
(discord.Embed): The embed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
embed = discord.Embed(color=discord.Color.orange(), title=title, url=url, description=text)
|
embed = discord.Embed(color=discord.Color.orange(), title=title, url=url, description=text)
|
||||||
@@ -205,7 +205,7 @@ def viteboka_embed(title: str, url: str, text: str, image: str):
|
|||||||
|
|
||||||
|
|
||||||
class VitebokaException(Exception):
|
class VitebokaException(Exception):
|
||||||
pass
|
"""Raised when an article can't be fetched. The message is shown to the user"""
|
||||||
|
|
||||||
|
|
||||||
class Viteboka(commands.Cog):
|
class Viteboka(commands.Cog):
|
||||||
@@ -233,7 +233,7 @@ class Viteboka(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
query (str): The search query
|
query (str): The search query
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -292,7 +292,7 @@ class Viteboka(commands.Cog):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The slash command interaction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await interaction.response.defer()
|
await interaction.response.defer()
|
||||||
@@ -336,8 +336,8 @@ class ArticleButton(discord.ui.Button):
|
|||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
----------
|
||||||
owner (discord.User|discord.Member): The user that invoked the paginator. Only this user can use the button
|
owner (discord.User | discord.Member): The user that invoked the paginator. Only this user can use the button
|
||||||
label (str): The label of the button
|
label (str): The label of the button
|
||||||
article_title (str): The title of the article the button is associated with
|
article_title (str): The title of the article the button is associated with
|
||||||
"""
|
"""
|
||||||
@@ -351,8 +351,8 @@ class ArticleButton(discord.ui.Button):
|
|||||||
What to do when the button is pressed
|
What to do when the button is pressed
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
----------
|
||||||
interaction (discord.Interaction): Slash command context object
|
interaction (discord.Interaction): The interaction that triggered this
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await interaction.response.defer()
|
await interaction.response.defer()
|
||||||
@@ -378,7 +378,7 @@ async def setup(bot: commands.Bot):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
bot (commands.Bot): Bot instance
|
bot (commands.Bot): The bot instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await bot.add_cog(Viteboka(bot))
|
await bot.add_cog(Viteboka(bot))
|
||||||
@@ -8,6 +8,10 @@ class BotLogger:
|
|||||||
"""Logging config for the bot"""
|
"""Logging config for the bot"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
Log to the console and to a file that rotates at midnight
|
||||||
|
"""
|
||||||
|
|
||||||
logger = logging.getLogger("")
|
logger = logging.getLogger("")
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
formatter = logging.Formatter(
|
formatter = logging.Formatter(
|
||||||
|
|||||||
@@ -5,12 +5,16 @@ from pydantic import Field
|
|||||||
|
|
||||||
|
|
||||||
class GroupDiscordRole(BaseModel):
|
class GroupDiscordRole(BaseModel):
|
||||||
|
"""A Discord role connected to a Galtinn group"""
|
||||||
|
|
||||||
id: int
|
id: int
|
||||||
discord_id: int
|
discord_id: int
|
||||||
description: str
|
description: str
|
||||||
|
|
||||||
|
|
||||||
class GroupProfile(BaseModel):
|
class GroupProfile(BaseModel):
|
||||||
|
"""Extra information about a Galtinn group, including its Discord roles"""
|
||||||
|
|
||||||
id: int
|
id: int
|
||||||
posix_name: str
|
posix_name: str
|
||||||
description: str
|
description: str
|
||||||
@@ -19,18 +23,24 @@ class GroupProfile(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class Group(BaseModel):
|
class Group(BaseModel):
|
||||||
|
"""A Galtinn group"""
|
||||||
|
|
||||||
id: int
|
id: int
|
||||||
name: str
|
name: str
|
||||||
profile: Optional[GroupProfile]
|
profile: Optional[GroupProfile]
|
||||||
|
|
||||||
|
|
||||||
class UserDiscordProfile(BaseModel):
|
class UserDiscordProfile(BaseModel):
|
||||||
|
"""The link between a Galtinn user and a Discord user"""
|
||||||
|
|
||||||
id: int
|
id: int
|
||||||
discord_id: int
|
discord_id: int
|
||||||
user: int
|
user: int
|
||||||
|
|
||||||
|
|
||||||
class DuskenUser(BaseModel):
|
class DuskenUser(BaseModel):
|
||||||
|
"""A Galtinn user"""
|
||||||
|
|
||||||
id: int
|
id: int
|
||||||
username: str
|
username: str
|
||||||
is_volunteer: bool
|
is_volunteer: bool
|
||||||
@@ -40,6 +50,8 @@ class DuskenUser(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class BasicResponse(BaseModel):
|
class BasicResponse(BaseModel):
|
||||||
|
"""A page of results from a paginated Galtinn endpoint"""
|
||||||
|
|
||||||
count: int
|
count: int
|
||||||
next: Optional[str]
|
next: Optional[str]
|
||||||
previous: Optional[str]
|
previous: Optional[str]
|
||||||
@@ -47,12 +59,18 @@ class BasicResponse(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class Users(BasicResponse):
|
class Users(BasicResponse):
|
||||||
|
"""A page of Galtinn users"""
|
||||||
|
|
||||||
results: list[DuskenUser]
|
results: list[DuskenUser]
|
||||||
|
|
||||||
|
|
||||||
class DiscordProfiles(BasicResponse):
|
class DiscordProfiles(BasicResponse):
|
||||||
|
"""A page of Discord profiles"""
|
||||||
|
|
||||||
results: list[UserDiscordProfile]
|
results: list[UserDiscordProfile]
|
||||||
|
|
||||||
|
|
||||||
class Groups(BasicResponse):
|
class Groups(BasicResponse):
|
||||||
|
"""A page of Galtinn groups"""
|
||||||
|
|
||||||
results: list[Group]
|
results: list[Group]
|
||||||
@@ -16,7 +16,13 @@ load_dotenv()
|
|||||||
|
|
||||||
|
|
||||||
class Bot(commands.Bot):
|
class Bot(commands.Bot):
|
||||||
|
"""The bot, configured from environment variables"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
Read the configuration from the environment
|
||||||
|
"""
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
command_prefix=commands.when_mentioned_or(os.environ["BOT_PREFIX"]),
|
command_prefix=commands.when_mentioned_or(os.environ["BOT_PREFIX"]),
|
||||||
case_insensitive=True,
|
case_insensitive=True,
|
||||||
@@ -48,6 +54,10 @@ class Bot(commands.Bot):
|
|||||||
}
|
}
|
||||||
|
|
||||||
async def setup_hook(self):
|
async def setup_hook(self):
|
||||||
|
"""
|
||||||
|
Open the HTTP session and database pool, load the cogs and sync the slash commands
|
||||||
|
"""
|
||||||
|
|
||||||
self.http_session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=15))
|
self.http_session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=15))
|
||||||
|
|
||||||
# DB needs to be setup here because contructor is not async
|
# DB needs to be setup here because contructor is not async
|
||||||
@@ -97,6 +107,10 @@ class Bot(commands.Bot):
|
|||||||
"""
|
"""
|
||||||
Close the HTTP session and database pool after the bot has shut down. This isn't done in close(),
|
Close the HTTP session and database pool after the bot has shut down. This isn't done in close(),
|
||||||
because bot.run doesn't wait for a close() started by the SIGTERM handler to finish
|
because bot.run doesn't wait for a close() started by the SIGTERM handler to finish
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
*args (tuple): The exception type, value and traceback if the bot stopped because of an error
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await super().__aexit__(*args)
|
await super().__aexit__(*args)
|
||||||
@@ -112,6 +126,10 @@ bot = Bot()
|
|||||||
|
|
||||||
@bot.event
|
@bot.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
|
"""
|
||||||
|
Print the bot's info and set its presence once it's connected
|
||||||
|
"""
|
||||||
|
|
||||||
if not hasattr(bot, "uptime"):
|
if not hasattr(bot, "uptime"):
|
||||||
bot.uptime = time()
|
bot.uptime = time()
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ GALTINN_AUTH_TOKEN = os.environ["GALTINN_AUTH_TOKEN"]
|
|||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
|
"""
|
||||||
|
Open the database pool and HTTP session on startup, and close them on shutdown
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
app (FastAPI): The app
|
||||||
|
"""
|
||||||
|
|
||||||
credentials = {
|
credentials = {
|
||||||
"host": os.environ["DATABASE_HOST"],
|
"host": os.environ["DATABASE_HOST"],
|
||||||
"database": os.environ["DATABASE_NAME"],
|
"database": os.environ["DATABASE_NAME"],
|
||||||
@@ -45,11 +53,25 @@ templates = Jinja2Templates(directory="src/templates")
|
|||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def index():
|
async def index():
|
||||||
|
"""
|
||||||
|
Tell visitors there's nothing to see here
|
||||||
|
"""
|
||||||
|
|
||||||
return "Hei du! Her skal ikke du drive og luske!"
|
return "Hei du! Her skal ikke du drive og luske!"
|
||||||
|
|
||||||
|
|
||||||
@app.get("/callback")
|
@app.get("/callback")
|
||||||
async def callback(request: Request, state: str, code: str | None = None):
|
async def callback(request: Request, state: str, code: str | None = None):
|
||||||
|
"""
|
||||||
|
Finish a Galtinn login: link the Galtinn user to the Discord user and tell the bot
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
request (Request): The request
|
||||||
|
state (str): Identifies the pending verification
|
||||||
|
code (str | None): The authorization code from Galtinn. Missing if the login was cancelled or failed
|
||||||
|
"""
|
||||||
|
|
||||||
# Claim the pending verification. Deleting it up front makes the state single use
|
# Claim the pending verification. Deleting it up front makes the state single use
|
||||||
verification = await app.state.pool.fetchrow(
|
verification = await app.state.pool.fetchrow(
|
||||||
"""
|
"""
|
||||||
@@ -175,4 +197,13 @@ async def callback(request: Request, state: str, code: str | None = None):
|
|||||||
|
|
||||||
@app.get("/success/{name}")
|
@app.get("/success/{name}")
|
||||||
async def success(request: Request, name: str):
|
async def success(request: Request, name: str):
|
||||||
|
"""
|
||||||
|
Show the success page after a verification
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
request (Request): The request
|
||||||
|
name (str): The Galtinn username to show
|
||||||
|
"""
|
||||||
|
|
||||||
return templates.TemplateResponse(request, "success.html", {"name": name})
|
return templates.TemplateResponse(request, "success.html", {"name": name})
|
||||||
Reference in new issue
Block a user