Skip to content

Commit f9fba31

Browse files
committedAug 6, 2024·
Add inbox actions, including dumping config to local file and force reloading config
1 parent 91807a1 commit f9fba31

7 files changed

+113
-4
lines changed
 

‎example_rules.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ general_settings:
1212
# Create posterity comments on new posts
1313
enable_create_posterity_comments: true
1414

15+
# Watch the private message inbox for commands from moderators
16+
enable_inbox_actions: true
17+
1518
posterity_comment_settings:
1619
# When these users post, don't create a posterity comment
1720
ignore_users:

‎pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "rflying_tower_bot"
3-
version = "0.4.0"
3+
version = "0.5.0"
44
description = ""
55
authors = ["Kris Knigga <kris@knigga.com>"]
66

‎rflying_tower_bot/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""rflying_tower_bot package."""
22

3-
__version__ = "0.4.0"
3+
__version__ = "0.5.0"

‎rflying_tower_bot/__main__.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import asyncpraw
77

88
from rflying_tower_bot.config import BotConfig, PRAWConfig
9+
from rflying_tower_bot.inbox import Inbox
910
from rflying_tower_bot.modlog import ModLog
1011
from rflying_tower_bot.post_stream import PostStream
1112

@@ -34,8 +35,11 @@ async def main() -> None:
3435

3536
modlog = ModLog(bot_config)
3637
post_stream = PostStream(bot_config)
38+
inbox = Inbox(bot_config)
3739

38-
await asyncio.gather(modlog.watch_modlog(), post_stream.watch_poststream())
40+
await asyncio.gather(
41+
modlog.watch_modlog(), post_stream.watch_poststream(), inbox.watch_inbox()
42+
)
3943

4044

4145
try:

‎rflying_tower_bot/inbox.py

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""A module to react to private messages."""
2+
3+
import logging
4+
from os import PathLike
5+
6+
from asyncpraw.models import Subreddit
7+
8+
from rflying_tower_bot.config import BotConfig, dump_current_settings
9+
from rflying_tower_bot.utilities import Utilities
10+
11+
12+
class Inbox:
13+
"""A class to react to new posts."""
14+
15+
def __init__(self, config: BotConfig) -> None:
16+
"""
17+
Create an instance of Inbox.
18+
19+
Args:
20+
----
21+
config (BotConfig): See config.BotConfig
22+
23+
"""
24+
self.log: logging.Logger = logging.getLogger(
25+
f"{__name__}.{self.__class__.__name__}"
26+
)
27+
self.config = config
28+
self.utilities = Utilities(config)
29+
30+
@staticmethod
31+
async def do_dump_current_config(subreddit: Subreddit, path: PathLike) -> None:
32+
"""
33+
Dump the current settings of the subreddit to a file.
34+
35+
Args:
36+
----
37+
subreddit (Subreddit): The subreddit object.
38+
path (PathLike): The path to the file where the settings will be dumped.
39+
40+
Returns:
41+
-------
42+
None
43+
44+
"""
45+
await dump_current_settings(subreddit, str(path))
46+
47+
async def watch_inbox(self) -> None:
48+
"""Watch the private message inbox and react to new messages."""
49+
self.log.info("Watching the inbox for new messages")
50+
subreddit = await self.config.reddit.subreddit(self.config.subreddit_name)
51+
moderators = [moderator async for moderator in subreddit.moderator]
52+
while True:
53+
try:
54+
# Skip existing messages to avoid processing the same message multiple times
55+
# This is different from other streams, which do not skip existing items
56+
# The idea is that commands are more timely than other events, so commands sent
57+
# while the bot is offline probably shouldn't be done when the bot comes back online
58+
async for message in self.config.reddit.inbox.stream(
59+
skip_existing=True
60+
):
61+
if (
62+
not self.config.rules
63+
or not self.config.rules.general_settings.enable_inbox_actions
64+
):
65+
self.log.debug("Inbox actions disabled, skipping message")
66+
continue
67+
68+
if message.author not in moderators:
69+
self.log.info(
70+
"Message from non-moderator %s: %s", message.author, message
71+
)
72+
continue
73+
74+
self.log.info(
75+
"Message from moderator %s: %s", message.author, message
76+
)
77+
78+
match message.subject:
79+
case "dump_current_config":
80+
self.log.info("Dumping config to file: %s", message.body)
81+
try:
82+
await self.do_dump_current_config(
83+
subreddit, message.body
84+
)
85+
except Exception as e:
86+
self.log.error("Error dumping config: %s", e)
87+
await message.mark_read()
88+
89+
case "reload_config":
90+
self.log.info("Reloading config")
91+
await self.config.update_rules()
92+
await message.mark_read()
93+
94+
case _:
95+
self.log.warning("Unknown command: %s", message.subject)
96+
97+
except KeyboardInterrupt:
98+
self.log.info("Caught keyboard interrupt, exiting inbox watcher")
99+
break
100+
except Exception as e:
101+
self.log.error("Error in inbox watcher: %s", e)

‎rflying_tower_bot/ruleset_schemas.py

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class GeneralSettings(BaseModel):
1515
enable_sync_post_flair: bool = True
1616
enable_flair_actions: bool = True
1717
enable_create_posterity_comments: bool = True
18+
enable_inbox_actions: bool = True
1819

1920

2021
class PosterityCommentSettings(BaseModel):

‎tests/test_rflying_tower_bot.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55

66
def test_version():
77
"""Test the version of the rflying_tower_bot package."""
8-
assert __version__ == "0.4.0"
8+
assert __version__ == "0.5.0"

0 commit comments

Comments
 (0)
Please sign in to comment.