Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit 298dde9

Browse files
authored
feat(notifications): add toggle and expiry (#63)
1 parent bacfdab commit 298dde9

File tree

6 files changed

+218
-72
lines changed

6 files changed

+218
-72
lines changed

poetry.lock

Lines changed: 86 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ uvloop = "^0.16.0"
1515
beautifulsoup4 = "^4.11.1"
1616
nextcord-ext-ipc = "^2.2.1"
1717
matplotlib = "^3.6.0"
18+
humanfriendly = "^10.0"
1819

1920
[tool.poetry.dev-dependencies]
2021
black = "^22.3.0"

vibr/__main__.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,15 @@
1111
import uvloop
1212
from botbase import BotBase
1313
from dotenv import load_dotenv
14-
from nextcord import Activity, ActivityType, StageChannel, VoiceChannel
14+
from nextcord import (
15+
Activity,
16+
ActivityType,
17+
SlashApplicationCommand,
18+
SlashApplicationSubcommand,
19+
StageChannel,
20+
VoiceChannel,
21+
)
22+
from nextcord.abc import Snowflake
1523
from nextcord.ext.ipc import Server
1624
from orjson import dumps, loads
1725
from pomice import NodeConnectionFailure, NodePool
@@ -213,6 +221,17 @@ async def on_error(self, event_method: str, *args, **kwargs):
213221
except Exception:
214222
log.warning("Failed to send to logchannel %d", self.logchannel)
215223

224+
def get_mention(self, name: str, *, guild: Snowflake | None = None) -> str:
225+
"""Get a slash command mention from the name, space separated."""
226+
227+
for slash in self.get_all_application_commands():
228+
if isinstance(slash, (SlashApplicationCommand, SlashApplicationSubcommand)):
229+
for item in list(slash.children.values()) + [slash]:
230+
if item.qualified_name == name:
231+
return item.get_mention(guild=guild)
232+
233+
return f"`/{name}`"
234+
216235

217236
intents = nextcord.Intents.none()
218237
intents.guilds = True

vibr/cogs/events.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,25 +124,19 @@ async def on_voice_state_update(
124124
@Cog.listener()
125125
async def on_application_command_completion(self, inter: MyInter):
126126
if inter.user.id not in self.bot.notified_users:
127-
is_notified = await self.bot.db.fetchval(
128-
"SELECT notified FROM users WHERE id=$1", inter.user.id
127+
row = await self.bot.db.fetchrow(
128+
"SELECT notified, notifications FROM users WHERE id=$1", inter.user.id
129129
)
130130

131131
# They were not notified, notify them.
132-
if not is_notified:
132+
if not row or (row["notifications"] and not row["notified"]):
133133
latest = await self.bot.db.fetchrow(
134-
"SELECT * FROM notifications ORDER BY id DESC LIMIT 1"
134+
"""SELECT * FROM notifications WHERE expiry > CURRENT_TIMESTAMP
135+
ORDER BY id DESC LIMIT 1"""
135136
)
136137

137138
if latest:
138-
notifs_command = get(
139-
self.bot.get_all_application_commands(), name="notifications"
140-
)
141-
notifs_mention = (
142-
notifs_command.get_mention() # type: ignore[member-access]
143-
if notifs_command
144-
else "`/notifications`"
145-
)
139+
notifs_mention = self.bot.get_mention("notifications list")
146140

147141
await inter.send(
148142
f"{inter.user.mention} You have a new notification "

vibr/cogs/misc.py

Lines changed: 101 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,81 @@
11
from __future__ import annotations
22

33
from asyncio import sleep
4+
from datetime import timedelta
45
from logging import getLogger
56
from os import getenv
67
from typing import TYPE_CHECKING
78

8-
from nextcord import Embed, Message, slash_command
9-
from nextcord.ext.commands import Cog, command, is_owner
9+
from humanfriendly import parse_timespan
10+
from nextcord import Embed, Message, Permissions, TextInputStyle, slash_command
11+
from nextcord.ext.application_checks import is_owner
12+
from nextcord.ext.commands import Cog, Converter
1013
from nextcord.ext.tasks import loop
14+
from nextcord.ui import Modal, TextInput
15+
from nextcord.utils import utcnow
1116

1217
from .extras.types import MyContext, MyInter, Notification
1318
from .extras.views import NotificationSource, NotificationView
1419

1520
if TYPE_CHECKING:
21+
1622
from ..__main__ import Vibr
1723

1824

19-
TEST = [802586580766162964, 939509053623795732]
2025
log = getLogger(__name__)
26+
TEST_IDS = [939509053623795732]
27+
28+
29+
class NotificationCreate(Modal):
30+
def __init__(self):
31+
super().__init__(title="Create a Notification")
32+
33+
self._title = TextInput(
34+
label="Enter a title for the notification.", max_length=256, required=True
35+
)
36+
self.time = TextInput(
37+
label="Enter an expiry time for the notification",
38+
required=True,
39+
default_value="7d",
40+
)
41+
self.description = TextInput(
42+
label="Enter a description for the notification",
43+
required=True,
44+
style=TextInputStyle.paragraph,
45+
)
46+
47+
self.add_item(self._title)
48+
self.add_item(self.time)
49+
self.add_item(self.description)
50+
51+
async def callback(self, inter: MyInter):
52+
title = self._title.value
53+
notification = self.description.value
54+
55+
try:
56+
if self.time.value is None:
57+
raise ValueError
58+
59+
expiry = timedelta(seconds=parse_timespan(self.time.value))
60+
except ValueError:
61+
await inter.response.send_message(
62+
"Invalid time, please try again.", ephemeral=True
63+
)
64+
return
65+
66+
await inter.client.db.execute(
67+
"""INSERT INTO notifications(title, notification, expiry)
68+
VALUES ($1, $2, $3)""",
69+
title,
70+
notification,
71+
utcnow() + expiry,
72+
)
73+
await inter.send("Saved in db")
74+
75+
await inter.client.db.execute("UPDATE users SET notified=false")
76+
inter.client.notified_users.clear()
77+
await inter.send("Set all users to un-notified")
78+
log.info("Distributing notification %s", title)
2179

2280

2381
class Misc(Cog):
@@ -120,22 +178,50 @@ async def vote(self, inter: MyInter):
120178
)
121179
await inter.send(embed=embed)
122180

123-
@command(hidden=True)
181+
@slash_command(
182+
name="create-notification",
183+
default_member_permissions=Permissions(8),
184+
guild_ids=TEST_IDS,
185+
)
124186
@is_owner()
125-
async def notif_create(self, ctx: MyContext, title: str, *, notification: str):
187+
async def create_notification(self, inter: MyInter):
188+
"""Create a notification."""
189+
190+
await inter.response.send_modal(NotificationCreate())
191+
192+
@slash_command()
193+
async def notifications(self, _: MyInter):
194+
...
195+
196+
@notifications.subcommand(name="toggle")
197+
async def notifications_toggle(self, inter: MyInter):
198+
"""Toggle notification messages for you."""
199+
200+
enabled = await self.bot.db.fetchval(
201+
"SELECT notifications FROM users WHERE id=$1", inter.user.id
202+
)
203+
204+
if enabled is None:
205+
enabled = True
206+
207+
new = not enabled
208+
126209
await self.bot.db.execute(
127-
"INSERT INTO notifications(title, notification) VALUES ($1, $2)",
128-
title,
129-
notification,
210+
"""INSERT INTO users (id, notifications)
211+
VALUES ($1, $2)
212+
ON CONFLICT (id) DO UPDATE
213+
SET notifications=$2""",
214+
inter.user.id,
215+
new,
130216
)
131-
await ctx.send("Saved in db")
132-
await self.bot.db.execute("UPDATE users SET notified=false")
133-
self.bot.notified_users.clear()
134-
await ctx.send("Set all users to un-notified")
135-
log.info("Distributing notification %s", title)
136217

137-
@slash_command()
138-
async def notifications(self, inter: MyInter):
218+
await inter.send(
219+
f"Notifications are now {'enabled' if new else 'disabled'} for you.",
220+
ephemeral=True,
221+
)
222+
223+
@notifications.subcommand(name="list")
224+
async def notifications_list(self, inter: MyInter):
139225
"""Recent announcements/notifications."""
140226

141227
notifs = await self.bot.db.fetch("SELECT * FROM notifications ORDER BY id DESC")

vibr/init.sql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ CREATE TABLE IF NOT EXISTS notifications (
33
id SERIAL PRIMARY KEY,
44
notification TEXT NOT NULL,
55
datetime TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
6-
title TEXT NOT NULL
6+
title TEXT NOT NULL,
7+
expiry TIMESTAMPTZ NOT NULL
78
);
89
CREATE TABLE IF NOT EXISTS songs (
910
id VARCHAR NOT NULL PRIMARY KEY,
@@ -17,7 +18,8 @@ CREATE TABLE IF NOT EXISTS users (
1718
spotify VARCHAR,
1819
notified BOOLEAN NOT NULL DEFAULT FALSE,
1920
vote TIMESTAMPTZ,
20-
total_time INT
21+
total_time INT,
22+
notifications BOOLEAN NOT NULL DEFAULT TRUE
2123
);
2224
CREATE TABLE IF NOT EXISTS players (
2325
channel BIGINT PRIMARY KEY,

0 commit comments

Comments
 (0)