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
51 changes: 51 additions & 0 deletions experiments/test_upvote_pattern.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Test script for the new UPVOTE_PREVIOUS pattern."""
import sys
import os

# Add python directory to path
python_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'python')
sys.path.append(python_dir)

from patterns import UPVOTE_PREVIOUS
from regex import match

def test_upvote_pattern():
"""Test the UPVOTE_PREVIOUS pattern."""

test_cases = [
# Should match
("+", True),
(" + ", True),
(" + ", True),
(" +", True),
("+ ", True),

# Should not match
("++", False),
("+ hello", False),
("hello +", False),
("+5", False),
("+-", False),
("", False),
("hello", False),
]

print("Testing UPVOTE_PREVIOUS pattern...")

all_passed = True
for test_input, expected in test_cases:
result = bool(match(UPVOTE_PREVIOUS, test_input))
status = "PASS" if result == expected else "FAIL"

if result != expected:
all_passed = False

print(f" '{test_input}' -> {result} (expected {expected}) [{status}]")

print(f"\nOverall: {'PASS' if all_passed else 'FAIL'}")
return all_passed

if __name__ == "__main__":
test_upvote_pattern()
15 changes: 15 additions & 0 deletions python/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def __init__(
(patterns.WHAT_IS, self.commands.what_is),
(patterns.WHAT_MEAN, self.commands.what_is),
(patterns.APPLY_KARMA, self.commands.apply_karma),
(patterns.UPVOTE_PREVIOUS, self.commands.upvote_previous),
(patterns.GITHUB_COPILOT, self.commands.github_copilot)
)

Expand Down Expand Up @@ -198,6 +199,20 @@ def get_messages(
reply_message = event.get("reply_message", {})
return [reply_message] if reply_message else event.get("fwd_messages", [])

def get_conversation_messages(
self,
peer_id: int,
count: int = 10
) -> List[Dict[str, Any]]:
"""Returns recent messages from conversation.
"""
response = self.call_method(
'messages.getHistory',
dict(peer_id=peer_id, count=count))
if "error" in response:
return []
return response["response"]["items"]


if __name__ == '__main__':
vk = Bot(token=BOT_TOKEN, group_id=config.BOT_GROUP_ID, debug=True)
Expand Down
92 changes: 92 additions & 0 deletions python/modules/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,98 @@ def github_copilot(self) -> NoReturn:
f'Пожалуйста, подождите {round(config.GITHUB_COPILOT_TIMEOUT - (now - self.now))} секунд', self.peer_id
)

def upvote_previous(self) -> NoReturn:
"""Upvotes the previous non-command message."""
if self.peer_id < 2e9 or not self.karma_enabled:
return

# Get recent conversation messages
recent_messages = self.vk_instance.get_conversation_messages(self.peer_id, 20)

# Find the previous non-command message
current_msg_found = False
for message in recent_messages:
# Skip until we find current message
if not current_msg_found:
if message["conversation_message_id"] == self.msg_id:
current_msg_found = True
continue

# Skip messages from bots or system
if message["from_id"] <= 0:
continue

message_text = message["text"].lstrip("/")

# Check if this message matches any command pattern
is_command = False
for cmd_pattern in Commands.cmds.keys():
if match(cmd_pattern, message_text):
is_command = True
break

# If not a command, this is our target message
if not is_command and message_text.strip():
target_user_id = message["from_id"]
target_user = self.data_service.get_user(target_user_id, self.vk_instance)

# Don't allow self-upvote
if target_user_id == self.from_id:
self.vk_instance.send_msg(
'Нельзя голосовать за свои сообщения.', self.peer_id)
return

# Apply upvote (equivalent to +0 karma - collective vote)
self.user = target_user
utcnow = datetime.utcnow()

# Check if already voted for this user
if self.current_user.uid in target_user.supporters:
self.vk_instance.send_msg(
(f'Вы уже голосовали за [id{target_user.uid}|'
f'{self.vk_instance.get_user_name(target_user.uid, "acc")}].'),
self.peer_id
)
return

# Check collective vote time limit
utclast = datetime.fromtimestamp(
float(self.current_user.last_collective_vote))
difference = utcnow - utclast
hours_difference = difference.total_seconds() / 3600
hours_limit = karma_limit(self.current_user.karma)

if hours_difference < hours_limit:
self.vk_instance.delete_message(self.peer_id, self.msg_id)
self.vk_instance.send_msg(
CommandsBuilder.build_not_enough_hours(
self.current_user, self.data_service,
hours_limit, difference.total_seconds() / 60),
self.peer_id)
return

# Apply the upvote
user_karma_change, selected_user_karma_change, collective_vote_applied, voters = self.apply_karma_change(
"+", 0)

if collective_vote_applied:
self.current_user.last_collective_vote = int(utcnow.timestamp())
self.data_service.save_user(self.current_user)

if user_karma_change:
self.data_service.save_user(target_user)

self.vk_instance.send_msg(
CommandsBuilder.build_karma_change(
user_karma_change, selected_user_karma_change, voters),
self.peer_id)
self.vk_instance.delete_message(self.peer_id, self.msg_id)
return

# No previous non-command message found
self.vk_instance.send_msg(
'Не найдено предыдущее сообщение для голосования.', self.peer_id)

def match_command(
self,
pattern: Pattern
Expand Down
3 changes: 3 additions & 0 deletions python/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,6 @@
GITHUB_COPILOT = recompile(
r'\A\s*(code|код)\s+(?P<lang>(' + COPILOT_LANGUAGES +
r'))(?P<text>[\S\s]+)\Z', IGNORECASE)

UPVOTE_PREVIOUS = recompile(
r'\A\s*\+\s*\Z', IGNORECASE)
Loading