From 7fe2ff5d00f555fe5df68042c02c9a9549d4ee82 Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 13 Sep 2025 07:15:34 +0300 Subject: [PATCH 1/3] Initial commit with task details for issue #106 Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/linksplatform/Bot/issues/106 --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..5772bd7c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/linksplatform/Bot/issues/106 +Your prepared branch: issue-106-4cca6719 +Your prepared working directory: /tmp/gh-issue-solver-1757736930200 + +Proceed. \ No newline at end of file From 073c8e39108ce5d11b16511164bed59e2d89904d Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 13 Sep 2025 07:24:25 +0300 Subject: [PATCH 2/3] Implement VK Bot Questions Desk feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implementation adds a comprehensive questions desk system to the VK bot as requested in issue #106. Features: - Question submission with karma rewards using 'ask [question] [reward]' - Question resolution with karma distribution using 'resolve [ID]' - Automatic pinned message updates with top questions - Questions sorted by karma reward amount - Full documentation and help integration - Comprehensive test coverage The system allows users to: 1. Submit questions with optional karma rewards 2. Resolve questions and receive karma rewards 3. View the questions desk with 'questions' command 4. Automatically maintain a pinned message with top questions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- python/README.md | 37 ++++++ python/__main__.py | 54 +++++++- python/modules/commands.py | 171 ++++++++++++++++++++++++ python/modules/commands_builder.py | 6 +- python/modules/questions_service.py | 193 ++++++++++++++++++++++++++++ python/patterns.py | 10 ++ python/tests.py | 174 ++++++++++++++++++++++++- 7 files changed, 642 insertions(+), 3 deletions(-) create mode 100644 python/modules/questions_service.py diff --git a/python/README.md b/python/README.md index a50c2d69..d0c15832 100644 --- a/python/README.md +++ b/python/README.md @@ -32,6 +32,9 @@ | ⭐ | += [ССЫЛКА] | Добавить ссылку на профиль github в свой профиль. | | ⭐ | -= [ССЫЛКА] | Убрать ссылку на профиль github из своего профиля. | | ⭐ | what is [] | Искать в википедии | +| ✔️ | ask [ВОПРОС] [НАГРАДА] | Добавить вопрос на доску с наградой в карме. | +| ✔️ | resolve [ID] | Решить вопрос и получить награду. | +| ✔️ | questions | Показать доску вопросов. | Так же возможно использование альтернативных названий команд. @@ -45,6 +48,9 @@ | info | инфо | | update | обновить | | what is | что такое | +| ask | спросить | +| resolve | решить | +| questions | вопросы | desk | доска | ![image](https://user-images.githubusercontent.com/1431904/146941784-670f052c-7b4e-4367-89c5-00466dfc92c9.png) @@ -162,6 +168,37 @@ Если нужного языка нет в списке, о его добавлении можно попросить [здесь](https://github.com/linksplatform/Bot/issues/15) +## 📋 Доска вопросов + +Доска вопросов позволяет участникам беседы задавать вопросы и получать на них ответы с системой кармических наград. + +### Как это работает + +1. **Задать вопрос**: Используйте команду `ask [вопрос] [награда]` + - Вопрос будет добавлен на доску + - Можно указать награду в карме за решение (необязательно) + - Карма за награду будет списана с вашего счета + +2. **Решить вопрос**: Используйте команду `resolve [ID]` + - Вопрос будет помечен как решенный + - Вы получите награду в карме (если была указана) + +3. **Просмотр доски**: Используйте команду `questions` + - Показывает все открытые вопросы + - Вопросы сортируются по размеру награды + +### Автоматическое закрепление + +Доска вопросов автоматически закрепляется в чате и обновляется при изменениях. Закрепленное сообщение содержит топ-10 вопросов с наибольшими наградами. + +### Примеры использования + +``` +ask Как работает декоратор @property в Python? 5 +resolve 123 +questions +``` + ## Prerequisites * [Git](https://git-scm.com/downloads) * [Python 3](https://www.python.org/downloads) diff --git a/python/__main__.py b/python/__main__.py index cdcbf7f6..3d77796a 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -63,7 +63,10 @@ def __init__( (patterns.WHAT_IS, self.commands.what_is), (patterns.WHAT_MEAN, self.commands.what_is), (patterns.APPLY_KARMA, self.commands.apply_karma), - (patterns.GITHUB_COPILOT, self.commands.github_copilot) + (patterns.GITHUB_COPILOT, self.commands.github_copilot), + (patterns.ASK_QUESTION, self.commands.ask_question), + (patterns.RESOLVE_QUESTION, self.commands.resolve_question), + (patterns.QUESTIONS_DESK, self.commands.show_questions_desk) ) def message_new( @@ -168,6 +171,55 @@ def send_msg( message=msg, peer_id=peer_id, disable_mentions=1, random_id=0)) + def pin_message( + self, + peer_id: int, + message_id: int + ) -> Dict[str, Any]: + """Pins a message in chat. + + :param peer_id: chat ID + :param message_id: message ID to pin + """ + return self.call_method( + 'messages.pin', + dict(peer_id=peer_id, message_id=message_id)) + + def unpin_message( + self, + peer_id: int + ) -> Dict[str, Any]: + """Unpins current pinned message in chat. + + :param peer_id: chat ID + """ + return self.call_method( + 'messages.unpin', + dict(peer_id=peer_id)) + + def send_and_pin_msg( + self, + msg: str, + peer_id: int + ) -> int: + """Sends a message and pins it, returning the message ID. + + :param msg: message text + :param peer_id: chat ID + :return: message ID of the sent message + """ + response = self.call_method( + 'messages.send', + dict( + message=msg, peer_id=peer_id, + disable_mentions=1, random_id=0)) + + if 'response' in response: + message_id = response['response'] + self.pin_message(peer_id, message_id) + return message_id + return 0 + def get_user_name( self, uid: int, diff --git a/python/modules/commands.py b/python/modules/commands.py index 93d99817..54c148d5 100644 --- a/python/modules/commands.py +++ b/python/modules/commands.py @@ -13,6 +13,7 @@ from .commands_builder import CommandsBuilder from .data_service import BetterBotBaseDataService from .data_builder import DataBuilder +from .questions_service import QuestionsService from .utils import ( get_default_programming_language, contains_all_strings, @@ -43,6 +44,7 @@ def __init__( self.selected_message: Dict[str, Any] = {} self.vk_instance: Vk = vk_instance self.data_service: BetterBotBaseDataService = data_service + self.questions_service: QuestionsService = QuestionsService() self.matched: Match = None wikipedia.set_lang('en') @@ -379,6 +381,175 @@ def github_copilot(self) -> NoReturn: f'Пожалуйста, подождите {round(config.GITHUB_COPILOT_TIMEOUT - (now - self.now))} секунд', self.peer_id ) + def ask_question(self) -> NoReturn: + """Submit a new question to the questions desk.""" + if not self.karma_enabled: + self.vk_instance.send_msg( + "Вопросы доступны только в чатах с включенной кармой.", + self.peer_id + ) + return + + question = self.matched.group('question').strip() + reward_str = self.matched.group('reward') + reward = 0 + + if reward_str: + try: + reward = int(reward_str) + if reward < 0: + self.vk_instance.send_msg( + "Награда не может быть отрицательной.", + self.peer_id + ) + return + if reward > self.current_user.karma: + self.vk_instance.send_msg( + f"У вас недостаточно кармы. Доступно: {self.current_user.karma}", + self.peer_id + ) + return + except ValueError: + reward = 0 + + # Deduct karma if reward is specified + if reward > 0: + self.current_user.karma -= reward + self.data_service.save_user(self.current_user) + + # Add question to the desk + question_id = self.questions_service.add_question( + question=question, + user_id=self.current_user.uid, + user_name=self.current_user.name, + peer_id=self.peer_id, + reward=reward + ) + + # Send confirmation + reward_text = f" с наградой {reward} кармы" if reward > 0 else "" + self.vk_instance.send_msg( + f"Вопрос #{question_id} добавлен на доску{reward_text}.\n\n" + f"Вопрос: {question}", + self.peer_id + ) + + # Update pinned message + self.update_questions_desk() + + def resolve_question(self) -> NoReturn: + """Resolve a question and award karma to resolver.""" + if not self.karma_enabled: + self.vk_instance.send_msg( + "Вопросы доступны только в чатах с включенной кармой.", + self.peer_id + ) + return + + question_id = int(self.matched.group('question_id')) + question = self.questions_service.get_question_by_id(question_id) + + if not question: + self.vk_instance.send_msg( + f"Вопрос #{question_id} не найден.", + self.peer_id + ) + return + + if question['status'] != 'open': + self.vk_instance.send_msg( + f"Вопрос #{question_id} уже решен.", + self.peer_id + ) + return + + if question['peer_id'] != self.peer_id: + self.vk_instance.send_msg( + f"Вопрос #{question_id} из другого чата.", + self.peer_id + ) + return + + # Resolve the question + resolved_question = self.questions_service.resolve_question( + question_id=question_id, + resolver_id=self.current_user.uid, + resolver_name=self.current_user.name + ) + + if resolved_question: + # Award karma to resolver + reward = resolved_question['reward'] + if reward > 0: + self.current_user.karma += reward + self.data_service.save_user(self.current_user) + + # Send confirmation + reward_text = f" и получил {reward} кармы" if reward > 0 else "" + self.vk_instance.send_msg( + f"{self.current_user.name} решил вопрос #{question_id}{reward_text}!\n\n" + f"Вопрос: {resolved_question['question']}", + self.peer_id + ) + + # Update pinned message + self.update_questions_desk() + + def show_questions_desk(self) -> NoReturn: + """Display the current questions desk.""" + open_questions = self.questions_service.get_open_questions(self.peer_id) + + if not open_questions: + self.vk_instance.send_msg( + "📋 Доска вопросов пуста.\n\n" + "Используйте 'ask [вопрос] [награда]' чтобы добавить вопрос.", + self.peer_id + ) + return + + message = "📋 Доска вопросов:\n\n" + + for i, question in enumerate(open_questions[:10], 1): # Show top 10 + reward_text = f" (🏆 {question['reward']})" if question['reward'] > 0 else "" + message += f"{i}. #{question['id']}: {question['question']}{reward_text}\n" + message += f" от {question['user_name']}\n\n" + + if len(open_questions) > 10: + message += f"... и еще {len(open_questions) - 10} вопросов\n\n" + + message += "Используйте 'resolve [ID]' чтобы решить вопрос." + + self.vk_instance.send_msg(message, self.peer_id) + + def update_questions_desk(self) -> NoReturn: + """Update the pinned message with current questions.""" + if not self.karma_enabled: + return + + # Generate the questions desk message + desk_message = self.questions_service.generate_questions_desk_message(self.peer_id) + + # Get current pinned message ID + current_pinned = self.questions_service.get_pinned_message(self.peer_id) + + try: + # If there's already a pinned message, unpin it first + if current_pinned: + self.vk_instance.unpin_message(self.peer_id) + + # Send and pin the new message + if hasattr(self.vk_instance, 'send_and_pin_msg'): + message_id = self.vk_instance.send_and_pin_msg(desk_message, self.peer_id) + if message_id: + self.questions_service.set_pinned_message(self.peer_id, message_id) + else: + # Fallback if method doesn't exist + self.vk_instance.send_msg(desk_message, self.peer_id) + except Exception as e: + # If pinning fails, just send the message normally + print(f"Pinning failed: {e}") + self.vk_instance.send_msg(desk_message, self.peer_id) + def match_command( self, pattern: Pattern diff --git a/python/modules/commands_builder.py b/python/modules/commands_builder.py index 29dc739f..4fe461b5 100644 --- a/python/modules/commands_builder.py +++ b/python/modules/commands_builder.py @@ -25,8 +25,12 @@ def build_help_message( f"Документация — {documentation_link}") elif peer_id > 2e9: if karma: + questions_help = ("\n\n📋 Доска вопросов:\n" + "• ask [вопрос] [награда] — добавить вопрос с кармой в награду\n" + "• resolve [ID] — решить вопрос и получить награду\n" + "• questions — показать доску вопросов") return ("Вы находитесь в беседе с включённой кармой.\n" - f"Документация — {documentation_link}") + f"Документация — {documentation_link}{questions_help}") else: return (f"Вы находитесь в беседе (#{peer_id}) с выключенной кармой.\n" f"Документация — {documentation_link}") diff --git a/python/modules/questions_service.py b/python/modules/questions_service.py new file mode 100644 index 00000000..6e56df87 --- /dev/null +++ b/python/modules/questions_service.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- +"""Questions service for managing the questions desk.""" +import json +import os +from typing import List, Dict, Any, Optional +from datetime import datetime + + +class QuestionsService: + """Service for managing questions desk functionality.""" + + def __init__(self, data_file: str = "questions.json", pinned_file: str = "pinned_messages.json"): + self.data_file = data_file + self.pinned_file = pinned_file + self.questions = self._load_questions() + self.pinned_messages = self._load_pinned_messages() + self.next_id = self._get_next_id() + + def _load_questions(self) -> List[Dict[str, Any]]: + """Load questions from file.""" + if os.path.exists(self.data_file): + try: + with open(self.data_file, 'r', encoding='utf-8') as f: + return json.load(f) + except (json.JSONDecodeError, FileNotFoundError): + return [] + return [] + + def _save_questions(self) -> None: + """Save questions to file.""" + with open(self.data_file, 'w', encoding='utf-8') as f: + json.dump(self.questions, f, ensure_ascii=False, indent=2) + + def _load_pinned_messages(self) -> Dict[str, int]: + """Load pinned message IDs from file.""" + if os.path.exists(self.pinned_file): + try: + with open(self.pinned_file, 'r', encoding='utf-8') as f: + return json.load(f) + except (json.JSONDecodeError, FileNotFoundError): + return {} + return {} + + def _save_pinned_messages(self) -> None: + """Save pinned message IDs to file.""" + with open(self.pinned_file, 'w', encoding='utf-8') as f: + json.dump(self.pinned_messages, f, ensure_ascii=False, indent=2) + + def _get_next_id(self) -> int: + """Get next available question ID.""" + if not self.questions: + return 1 + return max(q.get('id', 0) for q in self.questions) + 1 + + def add_question( + self, + question: str, + user_id: int, + user_name: str, + peer_id: int, + reward: int = 0 + ) -> int: + """Add a new question to the desk. + + Args: + question: The question text + user_id: ID of the user asking + user_name: Name of the user asking + peer_id: Chat ID where question was asked + reward: Karma reward for solving this question + + Returns: + ID of the created question + """ + question_data = { + 'id': self.next_id, + 'question': question, + 'user_id': user_id, + 'user_name': user_name, + 'peer_id': peer_id, + 'reward': reward, + 'status': 'open', + 'created_at': datetime.now().isoformat(), + 'resolved_at': None, + 'resolved_by': None, + 'resolved_by_name': None + } + + self.questions.append(question_data) + self.next_id += 1 + self._save_questions() + return question_data['id'] + + def resolve_question( + self, + question_id: int, + resolver_id: int, + resolver_name: str + ) -> Optional[Dict[str, Any]]: + """Mark a question as resolved. + + Args: + question_id: ID of the question to resolve + resolver_id: ID of the user resolving + resolver_name: Name of the user resolving + + Returns: + The resolved question data or None if not found + """ + for question in self.questions: + if question['id'] == question_id and question['status'] == 'open': + question['status'] = 'resolved' + question['resolved_at'] = datetime.now().isoformat() + question['resolved_by'] = resolver_id + question['resolved_by_name'] = resolver_name + self._save_questions() + return question + return None + + def get_open_questions(self, peer_id: Optional[int] = None) -> List[Dict[str, Any]]: + """Get all open questions, optionally filtered by chat. + + Args: + peer_id: Optional chat ID to filter by + + Returns: + List of open questions sorted by reward (descending) + """ + open_questions = [ + q for q in self.questions + if q['status'] == 'open' and (peer_id is None or q['peer_id'] == peer_id) + ] + return sorted(open_questions, key=lambda x: x['reward'], reverse=True) + + def get_question_by_id(self, question_id: int) -> Optional[Dict[str, Any]]: + """Get a specific question by ID.""" + for question in self.questions: + if question['id'] == question_id: + return question + return None + + def get_user_questions(self, user_id: int) -> List[Dict[str, Any]]: + """Get all questions asked by a specific user.""" + return [q for q in self.questions if q['user_id'] == user_id] + + def get_user_resolved_questions(self, user_id: int) -> List[Dict[str, Any]]: + """Get all questions resolved by a specific user.""" + return [q for q in self.questions if q['resolved_by'] == user_id] + + def set_pinned_message(self, peer_id: int, message_id: int) -> None: + """Set the pinned message ID for a chat.""" + self.pinned_messages[str(peer_id)] = message_id + self._save_pinned_messages() + + def get_pinned_message(self, peer_id: int) -> Optional[int]: + """Get the pinned message ID for a chat.""" + return self.pinned_messages.get(str(peer_id)) + + def clear_pinned_message(self, peer_id: int) -> None: + """Clear the pinned message ID for a chat.""" + if str(peer_id) in self.pinned_messages: + del self.pinned_messages[str(peer_id)] + self._save_pinned_messages() + + def generate_questions_desk_message(self, peer_id: int) -> str: + """Generate the questions desk message for pinning.""" + open_questions = self.get_open_questions(peer_id) + + if not open_questions: + return ( + "📋 Доска вопросов\n\n" + "Здесь пока нет вопросов.\n\n" + "Используйте 'ask [вопрос] [награда]' чтобы добавить вопрос." + ) + + message = "📋 Доска вопросов\n\n" + + for i, question in enumerate(open_questions[:10], 1): # Show top 10 + reward_text = f" 🏆{question['reward']}" if question['reward'] > 0 else "" + # Truncate long questions for the pinned message + question_text = question['question'] + if len(question_text) > 80: + question_text = question_text[:77] + "..." + + message += f"{i}. #{question['id']}: {question_text}{reward_text}\n" + + if len(open_questions) > 10: + message += f"\n... и еще {len(open_questions) - 10} вопросов" + + message += "\n\nИспользуйте 'resolve [ID]' чтобы решить вопрос." + message += "\nИспользуйте 'questions' чтобы увидеть полный список." + + return message \ No newline at end of file diff --git a/python/patterns.py b/python/patterns.py index 1834c72c..24c2e803 100644 --- a/python/patterns.py +++ b/python/patterns.py @@ -65,3 +65,13 @@ GITHUB_COPILOT = recompile( r'\A\s*(code|код)\s+(?P(' + COPILOT_LANGUAGES + r'))(?P[\S\s]+)\Z', IGNORECASE) + +# Questions desk patterns +ASK_QUESTION = recompile( + r'\A\s*(ask|спросить)\s+(?P[\S\s]+?)(\s+(?P\d+))?\s*\Z', IGNORECASE) + +RESOLVE_QUESTION = recompile( + r'\A\s*(resolve|решить)\s+(?P\d+)\s*\Z', IGNORECASE) + +QUESTIONS_DESK = recompile( + r'\A\s*(questions|вопросы|desk|доска)\s*\Z', IGNORECASE) diff --git a/python/tests.py b/python/tests.py index 4be4241e..0dc9560e 100644 --- a/python/tests.py +++ b/python/tests.py @@ -7,7 +7,7 @@ from modules import ( BetterBotBaseDataService, DataBuilder, - VkInstance, Commands + VkInstance, Commands, QuestionsService ) import patterns import config @@ -223,6 +223,178 @@ def test_apply_karma_change( self.commands.karma_message() +class Test3QuestionsService(TestCase): + """TestCase for questions service functionality""" + + def setUp(self): + self.questions_service = QuestionsService('test_questions.json', 'test_pinned.json') + # Clear any existing data + self.questions_service.questions = [] + self.questions_service.pinned_messages = {} + self.questions_service.next_id = 1 + + @ordered + def test_add_question(self): + """Test adding a question""" + question_id = self.questions_service.add_question( + question="How to use Python decorators?", + user_id=123, + user_name="TestUser", + peer_id=2000000001, + reward=5 + ) + + self.assertEqual(question_id, 1) + self.assertEqual(len(self.questions_service.questions), 1) + + question = self.questions_service.get_question_by_id(1) + self.assertIsNotNone(question) + self.assertEqual(question['question'], "How to use Python decorators?") + self.assertEqual(question['user_id'], 123) + self.assertEqual(question['reward'], 5) + self.assertEqual(question['status'], 'open') + + @ordered + def test_resolve_question(self): + """Test resolving a question""" + # Add a question first + question_id = self.questions_service.add_question( + question="Test question", + user_id=123, + user_name="TestUser", + peer_id=2000000001, + reward=10 + ) + + # Resolve it + resolved = self.questions_service.resolve_question( + question_id=question_id, + resolver_id=456, + resolver_name="Resolver" + ) + + self.assertIsNotNone(resolved) + self.assertEqual(resolved['status'], 'resolved') + self.assertEqual(resolved['resolved_by'], 456) + self.assertEqual(resolved['resolved_by_name'], "Resolver") + + @ordered + def test_get_open_questions(self): + """Test getting open questions sorted by reward""" + # Add multiple questions + self.questions_service.add_question("Question 1", 1, "User1", 2000000001, 5) + self.questions_service.add_question("Question 2", 2, "User2", 2000000001, 15) + self.questions_service.add_question("Question 3", 3, "User3", 2000000001, 10) + + open_questions = self.questions_service.get_open_questions(2000000001) + + # Should be sorted by reward descending + self.assertEqual(len(open_questions), 3) + self.assertEqual(open_questions[0]['reward'], 15) + self.assertEqual(open_questions[1]['reward'], 10) + self.assertEqual(open_questions[2]['reward'], 5) + + @ordered + def test_pinned_messages(self): + """Test pinned message management""" + peer_id = 2000000001 + message_id = 12345 + + # Set pinned message + self.questions_service.set_pinned_message(peer_id, message_id) + + # Get pinned message + pinned = self.questions_service.get_pinned_message(peer_id) + self.assertEqual(pinned, message_id) + + # Clear pinned message + self.questions_service.clear_pinned_message(peer_id) + pinned = self.questions_service.get_pinned_message(peer_id) + self.assertIsNone(pinned) + + @ordered + def test_generate_desk_message(self): + """Test generating questions desk message""" + peer_id = 2000000001 + + # Test empty desk + message = self.questions_service.generate_questions_desk_message(peer_id) + self.assertIn("пока нет вопросов", message) + + # Add questions + self.questions_service.add_question("Question 1", 1, "User1", peer_id, 5) + self.questions_service.add_question("Question 2", 2, "User2", peer_id, 0) + + message = self.questions_service.generate_questions_desk_message(peer_id) + self.assertIn("📋 Доска вопросов", message) + self.assertIn("Question 1", message) + self.assertIn("Question 2", message) + self.assertIn("🏆5", message) # Reward display + + +class Test4QuestionsCommands(TestCase): + """TestCase for questions commands functionality""" + + def setUp(self): + self.vk = VkInstance() + self.db = BetterBotBaseDataService('test_commands_db') + self.commands = Commands(self.vk, self.db) + self.commands.questions_service = QuestionsService('test_cmd_questions.json', 'test_cmd_pinned.json') + self.commands.questions_service.questions = [] + self.commands.questions_service.pinned_messages = {} + self.commands.questions_service.next_id = 1 + + # Setup test user + self.commands.current_user = self.db.get_or_create_user(123) + self.commands.current_user.karma = 50 + self.commands.peer_id = 2000000001 + self.commands.karma_enabled = True + + @ordered + def test_ask_question_command(self): + """Test ask question command""" + self.commands.msg = "ask How to learn Python? 10" + self.commands.match_command(patterns.ASK_QUESTION) + + initial_karma = self.commands.current_user.karma + self.commands.ask_question() + + # Check karma was deducted + self.assertEqual(self.commands.current_user.karma, initial_karma - 10) + + # Check question was added + questions = self.commands.questions_service.get_open_questions(self.commands.peer_id) + self.assertEqual(len(questions), 1) + self.assertEqual(questions[0]['question'], "How to learn Python?") + self.assertEqual(questions[0]['reward'], 10) + + @ordered + def test_resolve_question_command(self): + """Test resolve question command""" + # Add a question first + question_id = self.commands.questions_service.add_question( + question="Test question", + user_id=456, + user_name="Other User", + peer_id=self.commands.peer_id, + reward=15 + ) + + self.commands.msg = f"resolve {question_id}" + self.commands.match_command(patterns.RESOLVE_QUESTION) + + initial_karma = self.commands.current_user.karma + self.commands.resolve_question() + + # Check karma was awarded + self.assertEqual(self.commands.current_user.karma, initial_karma + 15) + + # Check question was resolved + question = self.commands.questions_service.get_question_by_id(question_id) + self.assertEqual(question['status'], 'resolved') + self.assertEqual(question['resolved_by'], self.commands.current_user.uid) + + if __name__ == '__main__': db = BetterBotBaseDataService("test_db") defaultTestLoader.sortTestMethodsUsing = compare From 31bc3087ae5ac9ae886b5c365c96d25ef880ac07 Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 13 Sep 2025 07:25:25 +0300 Subject: [PATCH 3/3] Remove CLAUDE.md - Claude command completed --- CLAUDE.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 5772bd7c..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/linksplatform/Bot/issues/106 -Your prepared branch: issue-106-4cca6719 -Your prepared working directory: /tmp/gh-issue-solver-1757736930200 - -Proceed. \ No newline at end of file