Files
Nessa/dolly/commands.py

145 lines
8.7 KiB
Python

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
from dotenv import load_dotenv
import os
load_dotenv()
contact_user_id = int(os.getenv("AUTHORIZED_USER_ID"))
logger = logging.getLogger('Dolly')
class ProjectCommands(app_commands.Group):
def __init__(self):
super().__init__(name="project", description="Manage projects.")
@app_commands.command(name="create", description="Create a new project.")
async def create_project(self, interaction: discord.Interaction, name: str, description: str):
try:
project_id = await add_project(name, description)
await interaction.response.send_message(f"Project '{name}' created successfully with ID: {project_id}.")
except Exception as e:
await interaction.response.send_message("An error occurred while creating the project.", ephemeral=True)
logger.error(f"Error in create_project: {e}")
@app_commands.command(name="list", description="List all projects.")
async def list_projects(self, interaction: discord.Interaction):
try:
projects = await list_projects()
if projects:
message = "\n".join([f"ID: {id}, Name: {name}, Description: {description}" for id, name, description in projects])
await interaction.response.send_message(f"Projects:\n{message}")
else:
await interaction.response.send_message("No projects found.")
except Exception as e:
await interaction.response.send_message("Failed to retrieve projects.", ephemeral=True)
logger.error(f"Error in list_projects: {e}")
@app_commands.command(name="remove", description="Remove a specific project and all its tasks.")
async def remove_project_command(self, interaction: discord.Interaction, project_id: int):
try:
await remove_project(project_id)
await interaction.response.send_message(f"Project ID {project_id} and all associated tasks have been successfully removed.")
logger.info(f"Project ID {project_id} and all associated tasks removed successfully.")
except Exception as e:
await interaction.response.send_message("Failed to remove the project.", ephemeral=True)
logger.error(f"Error in remove_project_command: {e}")
class TaskCommands(app_commands.Group):
def __init__(self):
super().__init__(name="task", description="Manage tasks.")
@app_commands.command(name="add", description="Add a new task to a project.")
async def add_task(self, interaction: discord.Interaction, project_name: str, description: str, assignee: str, deadline: str, status: str, priority: str):
try:
datetime.strptime(deadline, "%m/%d/%Y") # Validate date format
project_id = await get_project_id(project_name)
if project_id:
await add_task_to_project(project_id, description, assignee, deadline, status, priority)
await interaction.response.send_message(f"Task '{description}' added to project '{project_name}'.")
logger.info(f"Task added to project {project_name}: {description}")
else:
await interaction.response.send_message(f"Project '{project_name}' not found.", ephemeral=True)
logger.warning(f"Attempted to add task to non-existent project: {project_name}")
except ValueError:
await interaction.response.send_message("Invalid date format. Please use MM/DD/YYYY format.", ephemeral=True)
logger.error(f"Invalid date format provided by user: {deadline}")
except Exception as e:
await interaction.response.send_message("An error occurred while adding the task.", ephemeral=True)
logger.error(f"Unexpected error in add_task: {e}")
@app_commands.command(name="update", description="Update an existing task.")
async def update_task_command(self, interaction: discord.Interaction, task_id: int, description: str, assignee: str, deadline: str, status: str, priority: str):
try:
datetime.strptime(deadline, "%m/%d/%Y") # Validate date format
await update_task(task_id, description, assignee, deadline, status, priority)
await interaction.response.send_message(f"Task ID {task_id} updated successfully.")
logger.info(f"Task ID {task_id} updated: {description}")
except ValueError:
await interaction.response.send_message("Invalid date format. Please use MM/DD/YYYY format.", ephemeral=True)
logger.error(f"Invalid date format provided by user for task update: {deadline}")
except Exception as e:
await interaction.response.send_message("An error occurred while updating the task.", ephemeral=True)
logger.error(f"Unexpected error in update_task_command: {e}")
@app_commands.command(name="list", description="List tasks for a project.")
async def list_tasks(self, interaction: discord.Interaction, project_id: int):
try:
project_name = await get_project_name(project_id)
if not project_name:
await interaction.response.send_message(f"No project found with ID {project_id}.", ephemeral=True)
return
tasks = await list_tasks_for_project(project_id)
if tasks:
message = "\n".join([f"ID: {id}, Description: {description}, Assignee: {assignee}, Deadline: {deadline}, Status: {status}, Priority: {priority}"
for id, description, assignee, deadline, status, priority in tasks])
await interaction.response.send_message(f"Tasks for Project '{project_name}':\n{message}")
else:
await interaction.response.send_message(f"No tasks found for project '{project_name}'.")
except Exception as e:
await interaction.response.send_message(f"Failed to retrieve tasks for project ID {project_id}.", ephemeral=True)
logger.error(f"Error in list_tasks: {e}")
@app_commands.command(name="remove", description="Remove a specific task.")
async def remove_task_command(self, interaction: discord.Interaction, task_id: int):
try:
await remove_task(task_id)
await interaction.response.send_message(f"Task ID {task_id} has been successfully removed.")
logger.info(f"Task ID {task_id} removed successfully.")
except Exception as e:
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)
@app_commands.command(name="privacy-policy", description="View the bot's data handling policy.")
async def privacy_policy(self, interaction: discord.Interaction):
# Replace 'YOUR_USER_ID' with the actual numeric ID of the user 'advtech'
policy_details = f"""Your data, including your Discord ID, task entries, and other related data, is collected for the purpose of providing task management functionalities. All data is stored securely and is not shared with third parties. You can withdraw your consent at any time by using the `/opt-out` command. For any data requests or inquiries, please contact <@{contact_user_id}> on Discord."""
await interaction.response.send_message(policy_details, 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())
self.add_command(ConsentCommands())