Skip to content

Commit cd9d44e

Browse files
konardclaude
andcommitted
Implement automatic deletion of bot messages after configurable period
- Added BOT_MESSAGE_DELETE_DELAY_MINUTES config to control deletion timing - Added BOT_MESSAGE_DELETE_CHATS config for per-chat control - Extended send_msg() to automatically schedule deletion of all bot messages - Enhanced delete_message() to handle both karma and bot message deletions - Maintained backward compatibility with existing karma deletion system - Added comprehensive tests and usage documentation Resolves #38 by allowing bot administrators to configure automatic cleanup of bot messages to reduce chat clutter. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent ee70748 commit cd9d44e

File tree

5 files changed

+383
-11
lines changed

5 files changed

+383
-11
lines changed

experiments/USAGE.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Bot Message Auto-Deletion Feature
2+
3+
This document explains the enhanced message deletion functionality for the VK bot.
4+
5+
## Overview
6+
7+
The bot now supports automatically deleting all bot messages after a configurable period, not just karma-related messages. This helps keep chats clean and reduces clutter from bot responses.
8+
9+
## Configuration
10+
11+
### New Configuration Options
12+
13+
Add these settings to your `config.py`:
14+
15+
```python
16+
# Delete ALL bot messages after certain period (in minutes, set to 0 to disable)
17+
BOT_MESSAGE_DELETE_DELAY_MINUTES = 60 # Delete bot messages after 1 hour
18+
19+
# Chats where bot messages will be auto-deleted (leave empty to use CHATS_DELETING)
20+
BOT_MESSAGE_DELETE_CHATS = []
21+
```
22+
23+
### Configuration Options
24+
25+
1. **BOT_MESSAGE_DELETE_DELAY_MINUTES**
26+
- Set to `0` to disable auto-deletion of bot messages
27+
- Set to any positive number to enable deletion after that many minutes
28+
- Examples: `5` (5 minutes), `60` (1 hour), `1440` (24 hours)
29+
30+
2. **BOT_MESSAGE_DELETE_CHATS**
31+
- List of chat IDs where bot messages should be auto-deleted
32+
- If empty (`[]`), falls back to using `CHATS_DELETING` configuration
33+
- Example: `[2000000001, 2000000006]`
34+
35+
### Required Configuration
36+
37+
For message deletion to work, you must also configure:
38+
39+
1. **USERBOT_CHATS** - Maps VK chat IDs to userbot peer IDs
40+
```python
41+
USERBOT_CHATS = {
42+
2000000001: 477, # VK chat ID: userbot peer ID
43+
2000000006: 423
44+
}
45+
```
46+
47+
2. A working userbot that has permission to delete messages in the target chats
48+
49+
## How It Works
50+
51+
1. **Message Sending**: When the bot sends any message using `send_msg()`, it checks if auto-deletion is enabled
52+
2. **Scheduling**: If enabled and the chat is configured for deletion, the message gets scheduled for deletion
53+
3. **Background Cleanup**: The existing message cleanup mechanism processes scheduled deletions
54+
4. **Deletion**: The userbot deletes messages when their scheduled time arrives
55+
56+
## Backward Compatibility
57+
58+
This enhancement is fully backward compatible:
59+
60+
- Existing karma message deletion (2-second delay) continues to work unchanged
61+
- If `BOT_MESSAGE_DELETE_DELAY_MINUTES = 0`, no bot messages are auto-deleted
62+
- Existing `CHATS_DELETING` configuration is respected as a fallback
63+
64+
## Examples
65+
66+
### Example 1: Delete all bot messages after 30 minutes
67+
```python
68+
BOT_MESSAGE_DELETE_DELAY_MINUTES = 30
69+
BOT_MESSAGE_DELETE_CHATS = [2000000001, 2000000006]
70+
```
71+
72+
### Example 2: Delete all bot messages after 2 hours, use existing chat config
73+
```python
74+
BOT_MESSAGE_DELETE_DELAY_MINUTES = 120
75+
BOT_MESSAGE_DELETE_CHATS = [] # Uses CHATS_DELETING
76+
```
77+
78+
### Example 3: Disable auto-deletion of bot messages
79+
```python
80+
BOT_MESSAGE_DELETE_DELAY_MINUTES = 0
81+
```
82+
83+
## Testing
84+
85+
Run the test script to validate the configuration:
86+
```bash
87+
python3 experiments/test_config_logic.py
88+
```
89+
90+
The test validates:
91+
- Configuration values are properly set
92+
- Message deletion logic works correctly
93+
- Time calculations are accurate
94+
- Chat selection logic functions as expected

experiments/test_config_logic.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env python3
2+
"""Test the configuration logic for message deletion without external dependencies."""
3+
4+
import sys
5+
import os
6+
from datetime import datetime, timedelta
7+
8+
# Add the parent directory to the path
9+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
10+
11+
from python import config
12+
13+
14+
def test_config_values():
15+
"""Test that new configuration values are properly set."""
16+
print("Testing configuration values...")
17+
18+
# Check that new config values exist
19+
assert hasattr(config, 'BOT_MESSAGE_DELETE_DELAY_MINUTES'), "BOT_MESSAGE_DELETE_DELAY_MINUTES not found"
20+
assert hasattr(config, 'BOT_MESSAGE_DELETE_CHATS'), "BOT_MESSAGE_DELETE_CHATS not found"
21+
22+
# Check default values
23+
assert isinstance(config.BOT_MESSAGE_DELETE_DELAY_MINUTES, int), "BOT_MESSAGE_DELETE_DELAY_MINUTES should be integer"
24+
assert isinstance(config.BOT_MESSAGE_DELETE_CHATS, list), "BOT_MESSAGE_DELETE_CHATS should be list"
25+
26+
print(f"✓ BOT_MESSAGE_DELETE_DELAY_MINUTES = {config.BOT_MESSAGE_DELETE_DELAY_MINUTES}")
27+
print(f"✓ BOT_MESSAGE_DELETE_CHATS = {config.BOT_MESSAGE_DELETE_CHATS}")
28+
print("✓ Configuration values are properly set")
29+
30+
31+
def test_deletion_logic():
32+
"""Test the message deletion logic without actual VK integration."""
33+
print("\nTesting message deletion logic...")
34+
35+
# Simulate the logic from _should_delete_bot_message
36+
def should_delete_bot_message(peer_id: int, delete_chats: list, userbot_chats: dict, chats_deleting: list) -> bool:
37+
"""Simulated logic from the actual method."""
38+
effective_delete_chats = delete_chats or chats_deleting
39+
return peer_id in effective_delete_chats and peer_id in userbot_chats
40+
41+
# Test cases
42+
test_cases = [
43+
# (peer_id, delete_chats, userbot_chats, chats_deleting, expected_result, description)
44+
(2000000001, [2000000001], {2000000001: 477}, [], True, "Should delete when in BOT_MESSAGE_DELETE_CHATS and USERBOT_CHATS"),
45+
(2000000001, [], {2000000001: 477}, [2000000001], True, "Should delete using CHATS_DELETING fallback"),
46+
(2000000001, [2000000002], {2000000001: 477}, [2000000001], False, "Should not delete when not in BOT_MESSAGE_DELETE_CHATS"),
47+
(2000000001, [2000000001], {2000000002: 477}, [], False, "Should not delete when not in USERBOT_CHATS"),
48+
(2000000001, [], {2000000001: 477}, [], False, "Should not delete when no delete chats configured"),
49+
]
50+
51+
for peer_id, delete_chats, userbot_chats, chats_deleting, expected, description in test_cases:
52+
result = should_delete_bot_message(peer_id, delete_chats, userbot_chats, chats_deleting)
53+
assert result == expected, f"Failed: {description}. Expected {expected}, got {result}"
54+
print(f"✓ {description}")
55+
56+
print("✓ All deletion logic tests passed")
57+
58+
59+
def test_time_calculation():
60+
"""Test time calculation for message deletion."""
61+
print("\nTesting time calculation...")
62+
63+
# Test different delay configurations
64+
delay_minutes_configs = [0, 5, 60, 1440] # 0, 5min, 1hour, 1day
65+
66+
for delay_minutes in delay_minutes_configs:
67+
if delay_minutes == 0:
68+
print(f"✓ Delay of {delay_minutes} minutes = disabled (no deletion)")
69+
continue
70+
71+
delay_seconds = delay_minutes * 60
72+
current_time = datetime.now()
73+
deletion_time = current_time + timedelta(seconds=delay_seconds)
74+
75+
expected_diff = delay_minutes * 60
76+
actual_diff = (deletion_time - current_time).total_seconds()
77+
78+
assert abs(actual_diff - expected_diff) < 1, f"Time calculation error for {delay_minutes} minutes"
79+
print(f"✓ Delay of {delay_minutes} minutes = {delay_seconds} seconds calculated correctly")
80+
81+
print("✓ All time calculation tests passed")
82+
83+
84+
def main():
85+
"""Run all tests."""
86+
print("🧪 Running message deletion configuration and logic tests...\n")
87+
88+
try:
89+
test_config_values()
90+
test_deletion_logic()
91+
test_time_calculation()
92+
93+
print("\n🎉 All tests passed successfully!")
94+
print(f"\n📋 Summary:")
95+
print(f" - New config option: BOT_MESSAGE_DELETE_DELAY_MINUTES = {config.BOT_MESSAGE_DELETE_DELAY_MINUTES}")
96+
print(f" - New config option: BOT_MESSAGE_DELETE_CHATS = {config.BOT_MESSAGE_DELETE_CHATS}")
97+
print(f" - Logic correctly handles chat selection and userbot requirements")
98+
print(f" - Time calculations work for various delay periods")
99+
print(f"\n💡 To use the feature:")
100+
print(f" 1. Set BOT_MESSAGE_DELETE_DELAY_MINUTES > 0 to enable")
101+
print(f" 2. Configure BOT_MESSAGE_DELETE_CHATS with chat IDs (or leave empty to use CHATS_DELETING)")
102+
print(f" 3. Ensure USERBOT_CHATS contains the chat mappings for deletion to work")
103+
104+
except Exception as e:
105+
print(f"❌ Test failed: {e}")
106+
return 1
107+
108+
return 0
109+
110+
111+
if __name__ == '__main__':
112+
sys.exit(main())
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/env python3
2+
"""Test script for the enhanced message deletion functionality."""
3+
4+
import sys
5+
import os
6+
import datetime
7+
from unittest.mock import Mock, patch
8+
9+
# Add the parent directory to the path so we can import the bot modules
10+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
11+
12+
from python import config
13+
from python.__main__ import Bot
14+
15+
16+
def test_bot_message_deletion():
17+
"""Test that bot messages are scheduled for deletion when configured."""
18+
print("Testing bot message deletion functionality...")
19+
20+
# Mock the VK API calls
21+
with patch('saya.Vk.__init__'), \
22+
patch('saya.Vk.call_method') as mock_call_method:
23+
24+
# Mock the API response for message sending
25+
mock_call_method.return_value = {'response': 12345}
26+
27+
# Create bot instance
28+
bot = Bot(token="test_token", group_id=12345, debug=False)
29+
30+
# Configure test settings
31+
original_delay = config.BOT_MESSAGE_DELETE_DELAY_MINUTES
32+
original_delete_chats = config.BOT_MESSAGE_DELETE_CHATS
33+
original_userbot_chats = config.USERBOT_CHATS
34+
35+
config.BOT_MESSAGE_DELETE_DELAY_MINUTES = 60 # 1 hour
36+
config.BOT_MESSAGE_DELETE_CHATS = [2000000001]
37+
config.USERBOT_CHATS = {2000000001: 477}
38+
39+
try:
40+
# Test 1: Message should be scheduled for deletion in configured chat
41+
peer_id = 2000000001
42+
msg_id = bot.send_msg("Test message", peer_id)
43+
44+
print(f"✓ Sent message with ID {msg_id}")
45+
46+
# Check if message was scheduled for deletion
47+
assert peer_id in bot.messages_to_delete, "Message was not scheduled for deletion"
48+
assert len(bot.messages_to_delete[peer_id]) > 0, "No messages scheduled for deletion"
49+
50+
scheduled_msg = bot.messages_to_delete[peer_id][-1]
51+
assert scheduled_msg['id'] == msg_id, "Wrong message ID scheduled for deletion"
52+
53+
# Check that the deletion is scheduled for the correct time
54+
expected_time = datetime.datetime.now() + datetime.timedelta(minutes=60)
55+
actual_time = scheduled_msg['date']
56+
time_diff = abs((expected_time - actual_time).total_seconds())
57+
assert time_diff < 5, f"Deletion time is off by {time_diff} seconds"
58+
59+
print("✓ Message correctly scheduled for deletion after 60 minutes")
60+
61+
# Test 2: Message should NOT be scheduled for deletion in non-configured chat
62+
bot.messages_to_delete.clear()
63+
peer_id_no_delete = 2000000002
64+
msg_id2 = bot.send_msg("Test message 2", peer_id_no_delete)
65+
66+
assert peer_id_no_delete not in bot.messages_to_delete, "Message was incorrectly scheduled for deletion"
67+
print("✓ Message correctly NOT scheduled for deletion in non-configured chat")
68+
69+
# Test 3: Disable deletion and verify no scheduling occurs
70+
config.BOT_MESSAGE_DELETE_DELAY_MINUTES = 0
71+
bot.messages_to_delete.clear()
72+
msg_id3 = bot.send_msg("Test message 3", 2000000001)
73+
74+
assert len(bot.messages_to_delete) == 0, "Message was scheduled for deletion when disabled"
75+
print("✓ Message deletion correctly disabled when delay is 0")
76+
77+
finally:
78+
# Restore original config
79+
config.BOT_MESSAGE_DELETE_DELAY_MINUTES = original_delay
80+
config.BOT_MESSAGE_DELETE_CHATS = original_delete_chats
81+
config.USERBOT_CHATS = original_userbot_chats
82+
83+
print("All tests passed! ✓")
84+
85+
86+
def test_should_delete_bot_message():
87+
"""Test the helper method that determines if messages should be deleted."""
88+
print("Testing _should_delete_bot_message helper method...")
89+
90+
with patch('saya.Vk.__init__'):
91+
bot = Bot(token="test_token", group_id=12345, debug=False)
92+
93+
# Configure test settings
94+
original_delete_chats = config.BOT_MESSAGE_DELETE_CHATS
95+
original_userbot_chats = config.USERBOT_CHATS
96+
original_chats_deleting = config.CHATS_DELETING
97+
98+
config.BOT_MESSAGE_DELETE_CHATS = [2000000001]
99+
config.USERBOT_CHATS = {2000000001: 477, 2000000002: 478}
100+
config.CHATS_DELETING = [2000000002]
101+
102+
try:
103+
# Test with BOT_MESSAGE_DELETE_CHATS configured
104+
assert bot._should_delete_bot_message(2000000001), "Should delete in BOT_MESSAGE_DELETE_CHATS"
105+
assert not bot._should_delete_bot_message(2000000002), "Should not delete when not in BOT_MESSAGE_DELETE_CHATS"
106+
107+
# Test fallback to CHATS_DELETING when BOT_MESSAGE_DELETE_CHATS is empty
108+
config.BOT_MESSAGE_DELETE_CHATS = []
109+
assert bot._should_delete_bot_message(2000000002), "Should delete using CHATS_DELETING fallback"
110+
assert not bot._should_delete_bot_message(2000000001), "Should not delete when not in CHATS_DELETING"
111+
112+
# Test that chat must be in USERBOT_CHATS
113+
config.BOT_MESSAGE_DELETE_CHATS = [2000000003]
114+
assert not bot._should_delete_bot_message(2000000003), "Should not delete when not in USERBOT_CHATS"
115+
116+
finally:
117+
# Restore original config
118+
config.BOT_MESSAGE_DELETE_CHATS = original_delete_chats
119+
config.USERBOT_CHATS = original_userbot_chats
120+
config.CHATS_DELETING = original_chats_deleting
121+
122+
print("Helper method tests passed! ✓")
123+
124+
125+
if __name__ == '__main__':
126+
test_should_delete_bot_message()
127+
test_bot_message_deletion()
128+
print("\n🎉 All message deletion tests completed successfully!")

0 commit comments

Comments
 (0)