-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbot.py
More file actions
192 lines (157 loc) · 8.51 KB
/
bot.py
File metadata and controls
192 lines (157 loc) · 8.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
import discord
from discord import Option
from discord.ext import tasks
import asyncio
import todos
from todos import ToDoException
from functools import wraps
import os
TOKEN = os.environ['DISCORD_TOKEN']
todo_commands = discord.SlashCommandGroup("todo", "Commands to manage to-do lists")
reminder_commands = discord.SlashCommandGroup("reminder", "Commands to manage reminders")
intents = discord.Intents.default()
intents.message_content = True
bot = discord.Bot(intents=intents)
GREEN = 0x7bb586
BROWN = 0x6a4441
RED = 0xd34322
EPHEMERAL_MESSAGES=False # Sets whether most bot responses are emphemeral.
# Todo list and Reminder list will are not affected by this, and remain visible to everyone
# Error messages are also not affected, they remain ephemeral
def catch_errors(command):
""" This ensures errors are caught and reported to the user """
@wraps(command)
async def wrapper(ctx, *args, **kwargs):
try:
await command(ctx, *args, **kwargs)
except ToDoException as e:
embed = discord.Embed(title="Error", description=f"❌ {e.msg}", color=RED)
await ctx.respond(embed=embed, ephemeral=True)
except Exception as e:
embed = discord.Embed(title="Error", description=f"❌ Command failed for unknown reason.", color=RED)
await ctx.respond(embed=embed, ephemeral=True)
raise e
return wrapper
def parse_person(ctx, name:str):
if name:
person = todos.Person.from_name(name)
if not person:
raise ToDoException(f"No person with name `{name}` is known. Add them using `/todo newperson`.")
else:
person = todos.Person.from_id(str(ctx.author.id))
if not person:
raise ToDoException(f"You are not yet known to the system. Use `/todo newperson` to get started.")
return person
@bot.event
async def on_ready():
print('Logged in as')
print(bot.user.name)
print(bot.user.id)
print('------')
update_reminders.start()
@bot.command(name="newperson", description="Initializes a person into the to-do system")
@catch_errors
async def newperson(ctx,
name: Option(str, "Enter name with which to refer to the user", required = True),
pretty_name: Option(str, "This is the name which will be used in printing the to-do list", required = True),
id: Option(str, "The user id (leave empty to add yourself)", required = False, default="")
):
if not id:
id = str(ctx.author.id)
if existing_person:=todos.Person.from_id(id):
raise ToDoException(f"Your id (`{id}`) is already known under the name {existing_person.pretty_name} (`{existing_person.name}`),\
please provide a specific id for another person.")
person = todos.Person.new_person(name, pretty_name, id)
embed = discord.Embed(title="Created user", description=f"✅ Successfully initialized user {person.pretty_name} (<@{person.id}>)\
\nto refer to this user in commands, use `{person.name}`", color=GREEN)
await ctx.respond(embed=embed, ephemeral=EPHEMERAL_MESSAGES)
@todo_commands.command(name="add", description="Adds a task to someone's to-do list")
@catch_errors
async def todo_add(ctx,
task: Option(str, "The task to add to the to-do list", required = True),
name: Option(str, "The user whose list you want to add to (leave empty for your own list)", required = False, default=""),
deadline: Option(str, "The task's deadline (leave empty if there is none)", required = False, default="")
):
person = parse_person(ctx, name)
task = person.add_task(task, deadline)
embed = discord.Embed(title="Added task", description=f"✅ Successfully added the following task for **{person.pretty_name}**:\
\n>>> {task}", color=GREEN)
await ctx.respond(embed=embed, ephemeral=EPHEMERAL_MESSAGES)
@todo_commands.command(name="remove", description="Marks a task as completed")
@catch_errors
async def todo_remove(ctx,
task_id: Option(int, "The numerical task id to remove", required = True),
):
task = todos.Task.remove_task(task_id)
if not task:
raise ToDoException(f"There is no task with id `{task_id}`.")
person = todos.Person.from_name(task.name)
embed = discord.Embed(title="Removed task", description=f"✅ Marked the following task as completed (owned by **{person.pretty_name}**):\
\n>>> {task}", color=GREEN)
await ctx.respond(embed=embed, ephemeral=EPHEMERAL_MESSAGES)
@todo_commands.command(name="list", description="Lists a person's to-do list")
@catch_errors
async def todo_list(ctx,
name: Option(str, "The user whose list you want to inspect (leave empty for your own list)", required = False, default=""),
):
person = parse_person(ctx, name)
todo_list = person.todo_list()
if not todo_list:
todo_list = "Wow, such empty..."
embed = discord.Embed(title=f"{person.pretty_name}'s to-do's", description=f">>> {todo_list}", color=GREEN)
await ctx.respond(embed=embed)
@reminder_commands.command(name="add", description="Schedules a reminder")
@catch_errors
async def reminder_add(ctx,
time: Option(str, "The date and/or time at which you want to set the reminder", required = False, default=None),
names: Option(str, "The user(s) who you want to remind of someting (comma-separated)", required = False, default=""),
recurring: Option(str, "How often to recur the reminder (leave empty for non-recurring)", required = False, choices=todos.Reminder.recurring_options),
content: Option(str, "The content of the reminder (if empty, this is a copy of the task)", required = False, default=None),
task_id: Option(int, name="task", description="The task that is linked to the reminder", required = False, default=None),
):
names = names.split(",")
if names == [""] and not task_id:
person = parse_person(ctx, None)
names = [person.name]
reminder = todos.Reminder.new_reminder(time, names, recurring, content, task_id)
people = [todos.Person.from_name(name).pretty_name for name in reminder.names]
people_str = ", ".join(people)
embed = discord.Embed(title="Added task", description=f"✅ Successfully created the following reminder for **{people_str}** :\
\n>>> {reminder}", color=GREEN)
await ctx.respond(embed=embed, ephemeral=EPHEMERAL_MESSAGES)
@reminder_commands.command(name="remove", description="Deletes a remider")
@catch_errors
async def reminder_remove(ctx,
reminder_id: Option(int, "The numerical reminder id to remove", required = True),
):
reminder = todos.Reminder.remove_reminder(reminder_id)
if not reminder:
raise ToDoException(f"There is no reminder with id `{reminder_id}`.")
people = [todos.Person.from_name(name).pretty_name for name in reminder.names]
people_str = ", ".join(people)
embed = discord.Embed(title="Removed task", description=f"✅ Removed the following reminder for **{people_str}**:\
\n>>> {reminder}", color=GREEN)
await ctx.respond(embed=embed, ephemeral=EPHEMERAL_MESSAGES)
@reminder_commands.command(name="list", description="Lists a person's to-do list")
@catch_errors
async def reminder_list(ctx,
name: Option(str, "The user whose list you want to inspect (leave empty for your own list)", required = False, default=""),
):
person = parse_person(ctx, name)
reminder_list = person.reminder_list()
if not reminder_list:
reminder_list = "Wow, such empty..."
embed = discord.Embed(title=f"{person.pretty_name}'s reminders (some may be shared with other people)", description=f">>> {reminder_list}", color=GREEN)
await ctx.respond(embed=embed)
@tasks.loop(seconds=60)
async def update_reminders():
reminders_to_show = todos.Reminder.update_reminders()
for reminder in reminders_to_show:
embed = discord.Embed(title="Reminder", description=str(reminder), color=BROWN)
for name in reminder.names:
person = todos.Person.from_name(name)
user = await bot.fetch_user(person.id)
await user.send(embed=embed)
bot.add_application_command(todo_commands)
bot.add_application_command(reminder_commands)
bot.run(TOKEN)