Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions experiments/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Bot Message Auto-Deletion Feature

This document explains the enhanced message deletion functionality for the VK bot.

## Overview

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.

## Configuration

### New Configuration Options

Add these settings to your `config.py`:

```python
# Delete ALL bot messages after certain period (in minutes, set to 0 to disable)
BOT_MESSAGE_DELETE_DELAY_MINUTES = 60 # Delete bot messages after 1 hour

# Chats where bot messages will be auto-deleted (leave empty to use CHATS_DELETING)
BOT_MESSAGE_DELETE_CHATS = []
```

### Configuration Options

1. **BOT_MESSAGE_DELETE_DELAY_MINUTES**
- Set to `0` to disable auto-deletion of bot messages
- Set to any positive number to enable deletion after that many minutes
- Examples: `5` (5 minutes), `60` (1 hour), `1440` (24 hours)

2. **BOT_MESSAGE_DELETE_CHATS**
- List of chat IDs where bot messages should be auto-deleted
- If empty (`[]`), falls back to using `CHATS_DELETING` configuration
- Example: `[2000000001, 2000000006]`

### Required Configuration

For message deletion to work, you must also configure:

1. **USERBOT_CHATS** - Maps VK chat IDs to userbot peer IDs
```python
USERBOT_CHATS = {
2000000001: 477, # VK chat ID: userbot peer ID
2000000006: 423
}
```

2. A working userbot that has permission to delete messages in the target chats

## How It Works

1. **Message Sending**: When the bot sends any message using `send_msg()`, it checks if auto-deletion is enabled
2. **Scheduling**: If enabled and the chat is configured for deletion, the message gets scheduled for deletion
3. **Background Cleanup**: The existing message cleanup mechanism processes scheduled deletions
4. **Deletion**: The userbot deletes messages when their scheduled time arrives

## Backward Compatibility

This enhancement is fully backward compatible:

- Existing karma message deletion (2-second delay) continues to work unchanged
- If `BOT_MESSAGE_DELETE_DELAY_MINUTES = 0`, no bot messages are auto-deleted
- Existing `CHATS_DELETING` configuration is respected as a fallback

## Examples

### Example 1: Delete all bot messages after 30 minutes
```python
BOT_MESSAGE_DELETE_DELAY_MINUTES = 30
BOT_MESSAGE_DELETE_CHATS = [2000000001, 2000000006]
```

### Example 2: Delete all bot messages after 2 hours, use existing chat config
```python
BOT_MESSAGE_DELETE_DELAY_MINUTES = 120
BOT_MESSAGE_DELETE_CHATS = [] # Uses CHATS_DELETING
```

### Example 3: Disable auto-deletion of bot messages
```python
BOT_MESSAGE_DELETE_DELAY_MINUTES = 0
```

## Testing

Run the test script to validate the configuration:
```bash
python3 experiments/test_config_logic.py
```

The test validates:
- Configuration values are properly set
- Message deletion logic works correctly
- Time calculations are accurate
- Chat selection logic functions as expected
112 changes: 112 additions & 0 deletions experiments/test_config_logic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env python3
"""Test the configuration logic for message deletion without external dependencies."""

import sys
import os
from datetime import datetime, timedelta

# Add the parent directory to the path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from python import config


def test_config_values():
"""Test that new configuration values are properly set."""
print("Testing configuration values...")

# Check that new config values exist
assert hasattr(config, 'BOT_MESSAGE_DELETE_DELAY_MINUTES'), "BOT_MESSAGE_DELETE_DELAY_MINUTES not found"
assert hasattr(config, 'BOT_MESSAGE_DELETE_CHATS'), "BOT_MESSAGE_DELETE_CHATS not found"

# Check default values
assert isinstance(config.BOT_MESSAGE_DELETE_DELAY_MINUTES, int), "BOT_MESSAGE_DELETE_DELAY_MINUTES should be integer"
assert isinstance(config.BOT_MESSAGE_DELETE_CHATS, list), "BOT_MESSAGE_DELETE_CHATS should be list"

print(f"✓ BOT_MESSAGE_DELETE_DELAY_MINUTES = {config.BOT_MESSAGE_DELETE_DELAY_MINUTES}")
print(f"✓ BOT_MESSAGE_DELETE_CHATS = {config.BOT_MESSAGE_DELETE_CHATS}")
print("✓ Configuration values are properly set")


def test_deletion_logic():
"""Test the message deletion logic without actual VK integration."""
print("\nTesting message deletion logic...")

# Simulate the logic from _should_delete_bot_message
def should_delete_bot_message(peer_id: int, delete_chats: list, userbot_chats: dict, chats_deleting: list) -> bool:
"""Simulated logic from the actual method."""
effective_delete_chats = delete_chats or chats_deleting
return peer_id in effective_delete_chats and peer_id in userbot_chats

# Test cases
test_cases = [
# (peer_id, delete_chats, userbot_chats, chats_deleting, expected_result, description)
(2000000001, [2000000001], {2000000001: 477}, [], True, "Should delete when in BOT_MESSAGE_DELETE_CHATS and USERBOT_CHATS"),
(2000000001, [], {2000000001: 477}, [2000000001], True, "Should delete using CHATS_DELETING fallback"),
(2000000001, [2000000002], {2000000001: 477}, [2000000001], False, "Should not delete when not in BOT_MESSAGE_DELETE_CHATS"),
(2000000001, [2000000001], {2000000002: 477}, [], False, "Should not delete when not in USERBOT_CHATS"),
(2000000001, [], {2000000001: 477}, [], False, "Should not delete when no delete chats configured"),
]

for peer_id, delete_chats, userbot_chats, chats_deleting, expected, description in test_cases:
result = should_delete_bot_message(peer_id, delete_chats, userbot_chats, chats_deleting)
assert result == expected, f"Failed: {description}. Expected {expected}, got {result}"
print(f"✓ {description}")

print("✓ All deletion logic tests passed")


def test_time_calculation():
"""Test time calculation for message deletion."""
print("\nTesting time calculation...")

# Test different delay configurations
delay_minutes_configs = [0, 5, 60, 1440] # 0, 5min, 1hour, 1day

for delay_minutes in delay_minutes_configs:
if delay_minutes == 0:
print(f"✓ Delay of {delay_minutes} minutes = disabled (no deletion)")
continue

delay_seconds = delay_minutes * 60
current_time = datetime.now()
deletion_time = current_time + timedelta(seconds=delay_seconds)

expected_diff = delay_minutes * 60
actual_diff = (deletion_time - current_time).total_seconds()

assert abs(actual_diff - expected_diff) < 1, f"Time calculation error for {delay_minutes} minutes"
print(f"✓ Delay of {delay_minutes} minutes = {delay_seconds} seconds calculated correctly")

print("✓ All time calculation tests passed")


def main():
"""Run all tests."""
print("🧪 Running message deletion configuration and logic tests...\n")

try:
test_config_values()
test_deletion_logic()
test_time_calculation()

print("\n🎉 All tests passed successfully!")
print(f"\n📋 Summary:")
print(f" - New config option: BOT_MESSAGE_DELETE_DELAY_MINUTES = {config.BOT_MESSAGE_DELETE_DELAY_MINUTES}")
print(f" - New config option: BOT_MESSAGE_DELETE_CHATS = {config.BOT_MESSAGE_DELETE_CHATS}")
print(f" - Logic correctly handles chat selection and userbot requirements")
print(f" - Time calculations work for various delay periods")
print(f"\n💡 To use the feature:")
print(f" 1. Set BOT_MESSAGE_DELETE_DELAY_MINUTES > 0 to enable")
print(f" 2. Configure BOT_MESSAGE_DELETE_CHATS with chat IDs (or leave empty to use CHATS_DELETING)")
print(f" 3. Ensure USERBOT_CHATS contains the chat mappings for deletion to work")

except Exception as e:
print(f"❌ Test failed: {e}")
return 1

return 0


if __name__ == '__main__':
sys.exit(main())
128 changes: 128 additions & 0 deletions experiments/test_message_deletion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env python3
"""Test script for the enhanced message deletion functionality."""

import sys
import os
import datetime
from unittest.mock import Mock, patch

# Add the parent directory to the path so we can import the bot modules
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from python import config
from python.__main__ import Bot


def test_bot_message_deletion():
"""Test that bot messages are scheduled for deletion when configured."""
print("Testing bot message deletion functionality...")

# Mock the VK API calls
with patch('saya.Vk.__init__'), \
patch('saya.Vk.call_method') as mock_call_method:

# Mock the API response for message sending
mock_call_method.return_value = {'response': 12345}

# Create bot instance
bot = Bot(token="test_token", group_id=12345, debug=False)

# Configure test settings
original_delay = config.BOT_MESSAGE_DELETE_DELAY_MINUTES
original_delete_chats = config.BOT_MESSAGE_DELETE_CHATS
original_userbot_chats = config.USERBOT_CHATS

config.BOT_MESSAGE_DELETE_DELAY_MINUTES = 60 # 1 hour
config.BOT_MESSAGE_DELETE_CHATS = [2000000001]
config.USERBOT_CHATS = {2000000001: 477}

try:
# Test 1: Message should be scheduled for deletion in configured chat
peer_id = 2000000001
msg_id = bot.send_msg("Test message", peer_id)

print(f"✓ Sent message with ID {msg_id}")

# Check if message was scheduled for deletion
assert peer_id in bot.messages_to_delete, "Message was not scheduled for deletion"
assert len(bot.messages_to_delete[peer_id]) > 0, "No messages scheduled for deletion"

scheduled_msg = bot.messages_to_delete[peer_id][-1]
assert scheduled_msg['id'] == msg_id, "Wrong message ID scheduled for deletion"

# Check that the deletion is scheduled for the correct time
expected_time = datetime.datetime.now() + datetime.timedelta(minutes=60)
actual_time = scheduled_msg['date']
time_diff = abs((expected_time - actual_time).total_seconds())
assert time_diff < 5, f"Deletion time is off by {time_diff} seconds"

print("✓ Message correctly scheduled for deletion after 60 minutes")

# Test 2: Message should NOT be scheduled for deletion in non-configured chat
bot.messages_to_delete.clear()
peer_id_no_delete = 2000000002
msg_id2 = bot.send_msg("Test message 2", peer_id_no_delete)

assert peer_id_no_delete not in bot.messages_to_delete, "Message was incorrectly scheduled for deletion"
print("✓ Message correctly NOT scheduled for deletion in non-configured chat")

# Test 3: Disable deletion and verify no scheduling occurs
config.BOT_MESSAGE_DELETE_DELAY_MINUTES = 0
bot.messages_to_delete.clear()
msg_id3 = bot.send_msg("Test message 3", 2000000001)

assert len(bot.messages_to_delete) == 0, "Message was scheduled for deletion when disabled"
print("✓ Message deletion correctly disabled when delay is 0")

finally:
# Restore original config
config.BOT_MESSAGE_DELETE_DELAY_MINUTES = original_delay
config.BOT_MESSAGE_DELETE_CHATS = original_delete_chats
config.USERBOT_CHATS = original_userbot_chats

print("All tests passed! ✓")


def test_should_delete_bot_message():
"""Test the helper method that determines if messages should be deleted."""
print("Testing _should_delete_bot_message helper method...")

with patch('saya.Vk.__init__'):
bot = Bot(token="test_token", group_id=12345, debug=False)

# Configure test settings
original_delete_chats = config.BOT_MESSAGE_DELETE_CHATS
original_userbot_chats = config.USERBOT_CHATS
original_chats_deleting = config.CHATS_DELETING

config.BOT_MESSAGE_DELETE_CHATS = [2000000001]
config.USERBOT_CHATS = {2000000001: 477, 2000000002: 478}
config.CHATS_DELETING = [2000000002]

try:
# Test with BOT_MESSAGE_DELETE_CHATS configured
assert bot._should_delete_bot_message(2000000001), "Should delete in BOT_MESSAGE_DELETE_CHATS"
assert not bot._should_delete_bot_message(2000000002), "Should not delete when not in BOT_MESSAGE_DELETE_CHATS"

# Test fallback to CHATS_DELETING when BOT_MESSAGE_DELETE_CHATS is empty
config.BOT_MESSAGE_DELETE_CHATS = []
assert bot._should_delete_bot_message(2000000002), "Should delete using CHATS_DELETING fallback"
assert not bot._should_delete_bot_message(2000000001), "Should not delete when not in CHATS_DELETING"

# Test that chat must be in USERBOT_CHATS
config.BOT_MESSAGE_DELETE_CHATS = [2000000003]
assert not bot._should_delete_bot_message(2000000003), "Should not delete when not in USERBOT_CHATS"

finally:
# Restore original config
config.BOT_MESSAGE_DELETE_CHATS = original_delete_chats
config.USERBOT_CHATS = original_userbot_chats
config.CHATS_DELETING = original_chats_deleting

print("Helper method tests passed! ✓")


if __name__ == '__main__':
test_should_delete_bot_message()
test_bot_message_deletion()
print("\n🎉 All message deletion tests completed successfully!")
Loading
Loading