diff --git a/dolly/commands.py b/dolly/commands.py index 8cbf09a..c040639 100644 --- a/dolly/commands.py +++ b/dolly/commands.py @@ -1,6 +1,7 @@ import discord from discord import app_commands from .database import add_project, get_project_id, get_project_name, add_task_to_project, update_task, list_projects, list_tasks_for_project, remove_task, remove_project +from .consent import check_user_consent, store_user_consent, revoke_user_consent from datetime import datetime import logging @@ -108,8 +109,23 @@ class TaskCommands(app_commands.Group): await interaction.response.send_message("Failed to remove the task.", ephemeral=True) logger.error(f"Error in remove_task_command: {e}") +class ConsentCommands(app_commands.Group): + def __init__(self): + super().__init__(name="consent", description="Manage data consent settings.") + + @app_commands.command(name="opt-in", description="Opt-in to data storage and use the bot.") + async def opt_in(self, interaction: discord.Interaction): + await store_user_consent(interaction.user.id) + await interaction.response.send_message("You have opted in to data storage. You can now use the bot.", ephemeral=True) + + @app_commands.command(name="opt-out", description="Opt-out of data storage and stop using the bot.") + async def opt_out(self, interaction: discord.Interaction): + await revoke_user_consent(interaction.user.id) + await interaction.response.send_message("You have opted out of data storage. You will no longer be able to use the bot.", ephemeral=True) + class DollyTracker(app_commands.Group, name="dolly", description="Dolly the Project Tracker."): def __init__(self): super().__init__() self.add_command(ProjectCommands()) - self.add_command(TaskCommands()) \ No newline at end of file + self.add_command(TaskCommands()) + self.add_command(ConsentCommands()) \ No newline at end of file diff --git a/dolly/consent.py b/dolly/consent.py index 2cf99bb..3cd98c5 100644 --- a/dolly/consent.py +++ b/dolly/consent.py @@ -12,22 +12,27 @@ class ConsentView(View): @discord.ui.button(label="Consent to Data Storage", style=discord.ButtonStyle.green) async def confirm(self, interaction: discord.Interaction, button: Button): self.value = True - await interaction.response.send_message("Thank you for consenting to data storage!", ephemeral=True) + await store_user_consent(interaction.user.id) + await interaction.response.edit_message(content="Thank you for consenting to data storage!", view=None) self.stop() - @discord.ui.button(label="Decline", style=discord.ButtonStyle.grey) + @discord.ui.button(label="Decline Data Storage", style=discord.ButtonStyle.grey) async def cancel(self, interaction: discord.Interaction, button: Button): self.value = False - await interaction.response.send_message("You have declined data storage. You cannot use this bot without consenting.", ephemeral=True) + await interaction.response.edit_message(content="You have declined data storage. You cannot use this bot without consenting.", view=None) self.stop() async def check_user_consent(user_id): - """Check if the user has given consent to data storage.""" + """Check if the user has given consent to data storage, default to True.""" async with aiosqlite.connect(DATABASE) as db: cursor = await db.execute("SELECT consent_given FROM user_consents WHERE user_id = ?", (user_id,)) result = await cursor.fetchone() - return result[0] if result else False + if result is None: + # Assume consent given if no record exists + return True + return result[0] + async def store_user_consent(user_id): """Store the user's consent to data storage.""" @@ -35,3 +40,8 @@ async def store_user_consent(user_id): await db.execute("INSERT OR REPLACE INTO user_consents (user_id, consent_given) VALUES (?, TRUE)", (user_id,)) await db.commit() +async def revoke_user_consent(user_id): + """Revoke the user's consent to data storage.""" + async with aiosqlite.connect(DATABASE) as db: + await db.execute("UPDATE user_consents SET consent_given = FALSE WHERE user_id = ?", (user_id,)) + await db.commit() \ No newline at end of file diff --git a/dolly/dolly.py b/dolly/dolly.py index d9044f8..63289d9 100644 --- a/dolly/dolly.py +++ b/dolly/dolly.py @@ -33,7 +33,13 @@ class Dolly(discord.Client): async def on_interaction(self, interaction: discord.Interaction): if interaction.type == discord.InteractionType.application_command: + # Check if the command is about managing consent, which should be allowed regardless + if interaction.command.name in ['opt-in', 'opt-out']: + return # Let these commands process normally + + # Check user consent if not await check_user_consent(interaction.user.id): + # Present the consent view if no consent is recorded view = ConsentView() await interaction.response.send_message( "By using this bot, you consent to the storage of your data necessary for functionality. Please confirm your consent.", @@ -41,9 +47,7 @@ class Dolly(discord.Client): ephemeral=True ) await view.wait() - if view.value: - await store_user_consent(interaction.user.id) - else: - # Optionally, handle the case where the user declines consent + if not view.value: + # If after the view they still haven't consented, halt further processing await interaction.followup.send("You must consent to data storage to use this bot.", ephemeral=True) return # Stop processing if they do not consent