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
37 changes: 37 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
| ⭐ | += [ССЫЛКА] | Добавить ссылку на профиль github в свой профиль. |
| ⭐ | -= [ССЫЛКА] | Убрать ссылку на профиль github из своего профиля. |
| ⭐ | what is [] | Искать в википедии |
| ✔️ | ask [ВОПРОС] [НАГРАДА] | Добавить вопрос на доску с наградой в карме. |
| ✔️ | resolve [ID] | Решить вопрос и получить награду. |
| ✔️ | questions | Показать доску вопросов. |

Так же возможно использование альтернативных названий команд.

Expand All @@ -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)

Expand Down Expand Up @@ -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)
Expand Down
54 changes: 53 additions & 1 deletion python/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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,
Expand Down
171 changes: 171 additions & 0 deletions python/modules/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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')

Expand Down Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion python/modules/commands_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand Down
Loading
Loading