Skip to content

Commit 5507bd2

Browse files
committed
reaction-based AFK check and reminder canceling
1 parent 12a8351 commit 5507bd2

File tree

5 files changed

+101
-26
lines changed

5 files changed

+101
-26
lines changed

TODO.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ Keeping track of what needs to be done c:
3333

3434
### 1/31/2021 → x
3535

36-
- [ ] React-confirmation for servers
37-
- [ ] Require reaction for next timer to go off
38-
- [ ] Stop timer through reaction
36+
- [x] React-confirmation for servers
37+
- [x] Require reaction for next timer to go off
38+
- [x] Stop timer through reaction
3939
- [ ] Command Exceptions
4040
- [ ] Missing requirements per cmd
4141
- [x] Optimizations

run.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def get_prefix(bot, message):
7171
bot = commands.Bot(command_prefix = get_prefix)
7272
bot.remove_command('help')
7373
bot.coroutineList = []
74+
use_screen = True
7475

7576
@bot.event
7677
async def on_ready():
@@ -81,7 +82,10 @@ async def on_ready():
8182
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.playing, name="booting..."))
8283
# start periodic presence update
8384
asyncio.create_task(update_presence())
84-
asyncio.create_task(screen.loop(bot))
85+
if use_screen:
86+
asyncio.create_task(screen.loop(bot))
87+
else:
88+
print("Screen disabled\n\nRunning...")
8589

8690
@bot.event
8791
async def on_guild_join(guild):
@@ -200,7 +204,7 @@ async def reminder_stop(ctx, request):
200204
else:
201205
try:
202206
rq_json = requests.retrieve_json(user.id, files.request_dir(), request)
203-
requests.remove(user.id, files.request_dir(), int(request), bot.coroutineList)
207+
requests.remove(files.request_dir(), rq_json['request'], bot.coroutineList)
204208
embed = embeds.reminder_cancel(ctx, rq_json)
205209
except IndexError:
206210
embed = embeds.reminder_cancel_index(ctx, guild_prefix(ctx), request)
@@ -209,11 +213,13 @@ async def reminder_stop(ctx, request):
209213
# add information for embed
210214
async def timer(ctx, rq_json):
211215
t = rq_json["time"]
212-
user = ctx.message.author
216+
react = None
217+
pfx = guild_prefix(ctx)
213218
while(True):
214219
await asyncio.sleep(t)
215-
embed=embeds.timer_end(ctx=ctx, pfx=guild_prefix(ctx), rq_json=rq_json)
216-
await ctx.send("<@!" + str(user.id) + ">", embed=embed)
220+
if react is not None:
221+
react.cancel()
222+
react = asyncio.create_task(embeds.timer_end(ctx, pfx, rq_json))
217223

218224
async def update_presence():
219225
while(True):

utils/embed_generator.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
from discord import Embed
44
import utils.utils as utils
55
import utils.commands as cmds
6+
import utils.request_manager as requests
7+
import utils.file_manager as files
68

79
empty = Embed.Empty
810
all_control_emoji = ["⏮", "⬅️", "➡️", "⏭"]
11+
confirm_control_emoji = ["✅","❌"]
912

1013
# add aliases
1114
async def help(ctx, pfx, bot):
@@ -77,6 +80,17 @@ def reminder_cancel(ctx, rq_json):
7780
embed.set_footer(text=user.name, icon_url=user.avatar_url)
7881
return embed
7982

83+
84+
def reminder_cancel_timeout(ctx, rq_json):
85+
user = ctx.message.author
86+
embed=discord.Embed(
87+
title="Your reminder for ``" + rq_json["name"] + "`` was cancelled",
88+
description="No reaction was received before the next reminder occurence",
89+
color=0xcc0000
90+
)
91+
embed.set_footer(text=user.name, icon_url=user.avatar_url)
92+
return embed
93+
8094
def reminder_cancel_index(ctx, pfx, rqID):
8195
user = ctx.message.author
8296
embed=discord.Embed(
@@ -144,20 +158,65 @@ async def reminder_list(ctx, rqs):
144158
page_count += 1
145159
await embed_pages(ctx, embed_list)
146160

147-
def timer_end(ctx, pfx, rq_json):
161+
async def timer_end(ctx, pfx, rq_json):
148162
t = rq_json["time"]
149163
rq_name = rq_json["name"]
150164
user = ctx.message.author
151165
embed=discord.Embed(
152166
title=str(int(t/60)) + " minutes have passed!",
153-
description="Your reminder for ``" + rq_name + "`` is up" +
154-
"\nTo cancel further reminders, do ``" + pfx + "reminder|r stop [id]``",
167+
description="Your reminder for ``" + rq_name + "`` is up (id " + str(requests.get_index(user.id, files.request_dir(), rq_json) + 1) + ")"
168+
"\n" +
169+
"``React`` ✅ to confirm you aren't AFK by the next occurence" +
170+
"\n``React`` ❌ to stop or do ``" + pfx + "reminder|r stop [id]``",
155171
color=0xedc707,
156172
timestamp=ctx.message.created_at
157173
)
158174
embed.set_author(name=user.name + "", icon_url=user.avatar_url)
175+
await timer_react(ctx, embed)
176+
177+
def timer_continue(ctx, rq_json):
178+
t = rq_json["time"]
179+
rq_name = rq_json["name"]
180+
user = ctx.message.author
181+
embed=discord.Embed(
182+
title="Your reminder will continue ✅",
183+
description="You'll be reminded for ``" + rq_json["name"] + "`` again",
184+
color=0x00CC66
185+
)
186+
embed.set_footer(text=user.name, icon_url=user.avatar_url)
159187
return embed
160188

189+
async def timer_react(ctx, embed):
190+
bot = ctx.bot
191+
reaction = None
192+
message = await ctx.send("<@!" + str(ctx.message.author.id) + ">", embed=embed)
193+
rq_continue = False
194+
rq_json = requests.retrieve_json_id(files.request_dir(), ctx.author.id, ctx.message.id)
195+
# 5 second grace to ensure it cancels
196+
t = rq_json["time"] - 5
197+
198+
for emoji in confirm_control_emoji:
199+
await message.add_reaction(emoji)
200+
201+
def check(reaction, user):
202+
return reaction.message.id == message.id and user == ctx.author
203+
204+
try:
205+
reaction, user = await bot.wait_for('reaction_add', timeout = t, check = check)
206+
if str(reaction) == '✅':
207+
rq_continue = True
208+
elif str(reaction) == '❌':
209+
#await remove_reactions(ctx, message)
210+
await ctx.send(embed=reminder_cancel(ctx, rq_json))
211+
requests.remove(files.request_dir(), ctx.message.id, bot.coroutineList)
212+
except asyncio.TimeoutError:
213+
requests.remove(files.request_dir(), ctx.message.id, bot.coroutineList)
214+
await ctx.send(embed=reminder_cancel_timeout(ctx, rq_json))
215+
216+
if rq_continue:
217+
await ctx.send(embed=timer_continue(ctx, rq_json))
218+
await remove_reactions(ctx, message)
219+
161220
def prefix_current(ctx, pfx):
162221
embed=discord.Embed(
163222
title="My prefix is ``" + pfx + "`` for this guild",
@@ -227,6 +286,9 @@ def check(reaction, user):
227286
pass
228287
except asyncio.TimeoutError:
229288
break
289+
await remove_reactions(ctx, message)
290+
291+
async def remove_reactions(ctx, message):
230292
try:
231293
if ctx.guild is not None:
232294
await message.clear_reactions()

utils/request_manager.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ def create(loc, userid, request, rqname, time, guild_name):
1212
files.make_json(loc + str(userid) + '_' + str(request) + '.json', data) # ./id_rq.json
1313
return data
1414

15-
def remove(userid, path, request, arr):
16-
# get the request number (chronological)
17-
request = retrieve_json(userid, path, request)['request']
18-
timer_task = arr[utils.return2DIndex(request, arr)][1]
15+
def remove(path, request_id, arr):
16+
timer_task = arr[utils.return2DIndex(request_id, arr)][1]
1917
timer_task.cancel()
20-
del arr[utils.return2DIndex(request, arr)]
21-
files.delete_json(path, request)
18+
del arr[utils.return2DIndex(request_id, arr)]
19+
files.delete_json(path, request_id)
2220

2321
def retrieve_list(userid, path):
2422
request_list = []
@@ -29,6 +27,16 @@ def retrieve_list(userid, path):
2927
request_list.append(request)
3028
return request_list
3129

30+
def retrieve_json_id(path, userid, request_id):
31+
request_json = files.get_json(str(userid) + "_" + str(request_id), path)[0]
32+
with open(request_json, 'r') as r:
33+
rq_json = json.load(r)
34+
return rq_json
35+
36+
def get_index(userid, path, rq_json):
37+
arr = retrieve_list(userid, path)
38+
return arr.index(rq_json)
39+
3240
def retrieve_json(userid, path, request):
3341
request_files = files.get_json(userid, path)
3442
request_json = request_files[request - 1]

utils/screen.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
import curses
33
import discord
44

5-
stdscr = curses.initscr()
6-
75
def print_counts(bot):
8-
stdscr.addstr(0, 0, "Guilds: " + str(len(bot.guilds)))
9-
stdscr.addstr(1, 0, "Requests: " + str(len(bot.coroutineList)))
6+
bot.stdscr.addstr(0, 0, "Guilds: " + str(len(bot.guilds)))
7+
bot.stdscr.addstr(1, 0, "Requests: " + str(len(bot.coroutineList)))
108

11-
stdscr.refresh()
9+
bot.stdscr.refresh()
1210

1311
async def main(bot):
1412
print_counts(bot)
@@ -17,12 +15,12 @@ async def main(bot):
1715
await asyncio.sleep(5)
1816
curses.curs_set(0)
1917
#curses.cbreak()
20-
stdscr.nodelay(True)
21-
await check_interrupt(stdscr)
18+
bot.stdscr.nodelay(True)
19+
await check_interrupt(bot)
2220

23-
async def check_interrupt(stdscr):
21+
async def check_interrupt(bot):
2422
try:
25-
h = stdscr.getch()
23+
h = bot.stdscr.getch()
2624
if h == 3:
2725
raise KeyboardInterrupt
2826
if h == 26:
@@ -31,5 +29,6 @@ async def check_interrupt(stdscr):
3129
quit()
3230

3331
async def loop(bot):
32+
bot.stdscr = curses.initscr()
3433
while True:
3534
await main(bot)

0 commit comments

Comments
 (0)