feat: naive authorization
This commit is contained in:
parent
4a4fd5492d
commit
f68eac7381
7 changed files with 70 additions and 179 deletions
|
@ -15,16 +15,17 @@ handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(me
|
|||
logger.addHandler(handler)
|
||||
|
||||
logger.info("Loading config")
|
||||
|
||||
with open(os.path.join(KRUHOBOT_FOLDER, 'config.json'), 'r', encoding='utf-8') as f:
|
||||
config = json.load(f)
|
||||
|
||||
logger.info("Loading cogs")
|
||||
|
||||
bot = commands.Bot()
|
||||
bot.load_extension('kruhobot.cogs.auth')
|
||||
bot.load_extension('kruhobot.cogs.utils')
|
||||
|
||||
bot.config = config
|
||||
bot.logger = logger
|
||||
|
||||
@bot.listen('on_interaction')
|
||||
async def statistics(interaction):
|
||||
logger.info(f"{interaction.user} ({interaction.user.id}) used command {interaction.data['name']}.")
|
||||
|
|
|
@ -6,7 +6,7 @@ After=network.target
|
|||
Type=exec
|
||||
ExecStartPre=mkdir -p /data/kruhobot
|
||||
ExecStart=/srv/kruhobot/bin/kruhobot
|
||||
Environment=KRUHOBOT_FOLDER=/kruhobot
|
||||
Environment=KRUHOBOT_FOLDER=/data/kruhobot
|
||||
Restart=on-failure
|
||||
RestartSec=5min
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"server_ID": 0,
|
||||
"guild_ID": 0,
|
||||
"token": "token",
|
||||
"kruhove_role": {
|
||||
"kruh-XX": 0
|
|
@ -7,13 +7,10 @@ import discord
|
|||
from discord.ext import commands
|
||||
|
||||
|
||||
TOKEN = "MTQxOTQxNDM4OTIyODA0ODQyNA.GXr4xn.x5WWZHcRtjoY8MswVluzJp-e8ndC-tU1fyUJRw"
|
||||
TOKEN = ""
|
||||
AUTHORIZED_USERS = {
|
||||
251710204238888960,
|
||||
}
|
||||
AUTHORIZED_GUILDS = [
|
||||
1419405238951088210, # TEST
|
||||
1275128046906773601, # KRUHY
|
||||
]
|
||||
KRUH_ROLE_PATTERN = r"^Kruh [0-9]{2}$"
|
||||
MIGRATED_KRUH_ROLE_PATTERN = r"^Loňský Kruh [0-9]{2}$"
|
||||
|
@ -31,7 +28,7 @@ def _build_category_mapping(guild: discord.Guild) -> dict[str, discord.Guild]:
|
|||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
guild = bot.get_guild(1419405238951088210)
|
||||
guild = bot.get_guild(0)
|
||||
if guild is None:
|
||||
print("Guild not found.")
|
||||
return
|
||||
|
|
|
@ -1,6 +1,65 @@
|
|||
import re
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
|
||||
def setup(bot):
|
||||
...
|
||||
class Authorization(commands.Cog):
|
||||
kruh_pattern = r"kruh-[0-9]{2}"
|
||||
ukco_pattern = r"[0-9]{8}"
|
||||
help_message = \
|
||||
"""Usage: `!grant_role kruh-## UKCO`
|
||||
- Replace `##` with your study group number
|
||||
- Replace `UKCO` with your UKCO (8-digit personal number)."""
|
||||
|
||||
def __init__(self, bot: commands.Bot):
|
||||
super().__init__()
|
||||
self.bot = bot
|
||||
self.logger = bot.logger
|
||||
self.guild = bot.get_guild(bot.config["guild_ID"])
|
||||
self.kruh_roles = bot.config["kruhove_role"]
|
||||
|
||||
@commands.slash_command()
|
||||
async def grant_role(self, ctx: discord.ApplicationContext, kruh: str, ukco: str):
|
||||
kruh = kruh.lower()
|
||||
|
||||
if not re.fullmatch(self.kruh_pattern, kruh):
|
||||
await self.error(ctx, "Invalid Kruh format")
|
||||
await self.help(ctx)
|
||||
return
|
||||
|
||||
if not re.fullmatch(self.ukco_pattern, ukco):
|
||||
await self.error(ctx, 'Invalid UKCO format')
|
||||
await self.help(ctx)
|
||||
return
|
||||
|
||||
if not kruh in self.kruh_roles:
|
||||
await self.error(ctx, "Unrecognized Kruh")
|
||||
return
|
||||
|
||||
kruh_role_id = self.kruh_roles[kruh]
|
||||
|
||||
guild: discord.Guild = self.guild
|
||||
kruh_role = guild.get_role(kruh_role_id)
|
||||
if kruh_role is None:
|
||||
self.log(f"Role with id [{kruh_role_id}] not found!")
|
||||
await self.error(ctx, "Error while assigning role")
|
||||
return
|
||||
|
||||
await ctx.author.add_roles(kruh_role)
|
||||
|
||||
self.log(f'Granted role [{kruh_role.name}] to [{ctx.author.mention}] in [{guild.name}] corresponding to the study group [{kruh}].')
|
||||
await ctx.respond(f"{ctx.author.mention} has been granted the [{kruh_role.name}] role on the [{guild.name}] server.")
|
||||
|
||||
async def error(self, ctx: discord.ApplicationContext, message: str):
|
||||
await ctx.respond(f'**Error:** {message}')
|
||||
|
||||
async def help(self, ctx: discord.ApplicationContext):
|
||||
await ctx.respond(self.help_message)
|
||||
|
||||
async def log(self, message: str):
|
||||
self.logger.info(message)
|
||||
|
||||
|
||||
def setup(bot: commands.Bot):
|
||||
bot.add_cog(Authorization(bot))
|
||||
|
|
|
@ -2,7 +2,7 @@ import discord
|
|||
from discord.ext import commands
|
||||
|
||||
|
||||
class Basic(commands.Cog):
|
||||
class Utils(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
|
@ -16,4 +16,4 @@ class Basic(commands.Cog):
|
|||
|
||||
|
||||
def setup(bot: commands.Bot):
|
||||
bot.add_cog(Basic(bot))
|
||||
bot.add_cog(Utils(bot))
|
||||
|
|
166
main.py
166
main.py
|
@ -1,166 +0,0 @@
|
|||
from configparser import ConfigParser
|
||||
import logging
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
TOKEN = 'MTE1NDc0ODQ3MzE4MzMwNTc4OQ.Gz_Q7u.02sb2YNV_QQy7Bs19roXlB62mjoMKA6y8aubHU' # Bot token (replace with your own)
|
||||
DEFAULT_CONFIG_FILE = 'config.ini' # Configuration file with server IDs and study group roles
|
||||
DEFAULT_LOG_FILE = 'kruhobot.log' # Log file for the bot
|
||||
HELP_MESSAGE = """Usage: `!grant_role kruh-## UKCO`
|
||||
- Replace `##` with your study group number
|
||||
- Replace `UKCO` with your UKCO (8-digit personal number)."""
|
||||
|
||||
# Create an instance of the bot
|
||||
intents = discord.Intents.default()
|
||||
intents.members = True
|
||||
intents.message_content = True
|
||||
|
||||
bot = commands.Bot(command_prefix='!', intents=intents)
|
||||
|
||||
logging.basicConfig(filename=DEFAULT_LOG_FILE, level=logging.INFO)
|
||||
logger = logging.getLogger("Kruhobot")
|
||||
|
||||
config = ConfigParser()
|
||||
config.read(DEFAULT_CONFIG_FILE)
|
||||
|
||||
|
||||
async def reply_error(ctx, message: str):
|
||||
"""
|
||||
Reply to the user with an error message.
|
||||
:param ctx: The context of the command.
|
||||
:param message: The error message.
|
||||
"""
|
||||
await reply(ctx, f'**Error:** {message}')
|
||||
|
||||
|
||||
async def reply(ctx, message: str):
|
||||
"""
|
||||
Reply to the user.
|
||||
:param ctx: The context of the command or the channel from the event handler.
|
||||
:param message: The message to reply with.
|
||||
"""
|
||||
await ctx.send(message)
|
||||
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
logger.info(f'Logged in as {bot.user.name}')
|
||||
|
||||
|
||||
@bot.command()
|
||||
async def grant_role(ctx, study_group_name: str, ukco: str):
|
||||
"""
|
||||
Grant a role to the user based on the study group and UKCO.
|
||||
:param ctx: The context of the command.
|
||||
:param study_group_name: The name of the study group.
|
||||
:param ukco: The UKCO of the user.
|
||||
"""
|
||||
# Check study group format
|
||||
if not study_group_name.startswith('kruh-') or not study_group_name[5:].isdigit():
|
||||
await reply_error(ctx, 'Invalid study group format.')
|
||||
await reply(ctx, HELP_MESSAGE)
|
||||
return
|
||||
|
||||
# Check UKCO format
|
||||
if not ukco.isdigit() or not len(ukco) == 8:
|
||||
await reply_error(ctx, 'Invalid UKCO format.')
|
||||
await reply(ctx, HELP_MESSAGE)
|
||||
return
|
||||
|
||||
for guild_id in server_ids:
|
||||
if study_group_name not in study_groups[guild_id]: # Check if the study group is valid for the server
|
||||
continue
|
||||
|
||||
guild = bot.get_guild(guild_id)
|
||||
if guild is None: # Check if the guild exists
|
||||
continue
|
||||
|
||||
role = discord.utils.get(guild.roles, id=study_groups[guild_id][study_group_name])
|
||||
if role is None: # Check if the role exists
|
||||
continue
|
||||
|
||||
author = guild.get_member(ctx.author.id)
|
||||
if author is None: # Check if the author is a member of the guild
|
||||
continue
|
||||
|
||||
await author.add_roles(role)
|
||||
await reply(ctx, f'{author.mention} has been granted the [{role.name}] role on the [{guild.name}] server.')
|
||||
logger.info(f'Granted role [{role.name}] to [{author.mention}] in [{guild.name}] corresponding to the study group [{study_group_name}].')
|
||||
return
|
||||
|
||||
await reply_error(ctx, 'Something went wrong. Please check your command and try again.')
|
||||
logger.error(f'Failed to grant a role to [{author.mention}] corresponding to the study group [{study_group_name}].')
|
||||
return
|
||||
|
||||
|
||||
async def check_command(message):
|
||||
# Split the message content into words
|
||||
words = message.content.split()
|
||||
|
||||
if len(words) == 0:
|
||||
return False
|
||||
|
||||
# Check if the message is a command
|
||||
if not words[0].startswith('!'):
|
||||
await reply(message.channel, HELP_MESSAGE)
|
||||
return False
|
||||
|
||||
# Check if the command is recognized
|
||||
if not words[0] == '!grant_role':
|
||||
await reply_error(message.channel, 'Unrecognized command.')
|
||||
await reply(message.channel, HELP_MESSAGE)
|
||||
return False
|
||||
|
||||
# Check if the number of arguments is correct
|
||||
if not len(words) == 3:
|
||||
await reply_error(message.channel, 'Invalid number of arguments.')
|
||||
await reply(message.channel, HELP_MESSAGE)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@bot.event
|
||||
async def on_message(message):
|
||||
# Check if the message is a private message and not from the bot itself
|
||||
if not isinstance(message.channel, discord.DMChannel) or message.author == bot.user:
|
||||
return
|
||||
|
||||
is_valid_command = await check_command(message)
|
||||
if not is_valid_command:
|
||||
return
|
||||
|
||||
await bot.process_commands(message)
|
||||
|
||||
|
||||
def init(config):
|
||||
"""
|
||||
Initialize the server IDs and study groups from the configuration file.
|
||||
:param config: The configuration file.
|
||||
:return: A tuple with server IDs and study groups.
|
||||
"""
|
||||
def get_section_server_id(section):
|
||||
return int(config[section]["server_ID"])
|
||||
|
||||
server_ids = {get_section_server_id(section) for section in config.sections() if "server_ID" in config[section]}
|
||||
study_groups = {server_id: dict() for server_id in server_ids}
|
||||
|
||||
for section in config.sections():
|
||||
server_id = get_section_server_id(section)
|
||||
if server_id is None:
|
||||
continue
|
||||
|
||||
# Study group names are in style "kruh-XX", where XX is a two-digit number
|
||||
# Iterate over all from top to bottom
|
||||
for (key, value) in config.items(section):
|
||||
if key.startswith('kruh-'):
|
||||
study_groups[server_id][key] = int(value)
|
||||
|
||||
return server_ids, study_groups
|
||||
|
||||
|
||||
server_ids, study_groups = init(config)
|
||||
|
||||
# Run the bot
|
||||
bot.run(TOKEN)
|
Loading…
Reference in a new issue