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
54 changes: 54 additions & 0 deletions examples/test_daily_outreach.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Test script for daily outreach functionality."""
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'python'))

from modules.daily_outreach import DailyOutreach
from modules.data_service import BetterBotBaseDataService
from modules.vk_instance import VkInstance

def test_daily_outreach():
"""Test the daily outreach functionality."""
print("Testing DailyOutreach functionality...")

# Create mock VK instance and data service
vk_instance = VkInstance()
data_service = BetterBotBaseDataService("test_users")

# Create daily outreach instance
daily_outreach = DailyOutreach(vk_instance, data_service)

print("✓ DailyOutreach instance created successfully")

# Test question selection
candidates = [12345, 67890]
selection = daily_outreach.select_random_user_and_question(candidates)
if selection:
user_id, question = selection
print(f"✓ Random selection works: User {user_id}, Question: '{question}'")
else:
print("✗ Random selection failed")

# Test response processing
test_responses = [
("My GitHub is github.com/testuser", 12345),
("I know Python and JavaScript", 67890),
("Regular message", 11111)
]

for msg, from_id in test_responses:
processed = daily_outreach.process_potential_response(msg, from_id)
print(f"✓ Message '{msg}' processed: {processed}")

# Test should_run_daily_outreach
should_run_first = daily_outreach.should_run_daily_outreach()
should_run_second = daily_outreach.should_run_daily_outreach()

print(f"✓ Daily check - First run: {should_run_first}, Second run: {should_run_second}")

print("✓ All tests completed successfully!")

if __name__ == "__main__":
test_daily_outreach()
16 changes: 16 additions & 0 deletions python/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from modules import (
BetterBotBaseDataService, Commands
)
from modules.daily_outreach import DailyOutreach
from tokens import BOT_TOKEN
from userbot import UserBot
import patterns
Expand Down Expand Up @@ -38,6 +39,7 @@ def __init__(
self.messages_to_delete = {}
self.userbot = UserBot()
self.data = BetterBotBaseDataService()
self.daily_outreach = DailyOutreach(self, self.data)
self.commands = Commands(self, self.data)
self.commands.register_cmds(
(patterns.HELP, self.commands.help_message),
Expand Down Expand Up @@ -99,6 +101,20 @@ def message_new(

user = self.data.get_user(from_id, self) if from_id > 0 else None

# Daily outreach: ask random user about programming languages or GitHub
if peer_id >= 2e9 and self.daily_outreach.should_run_daily_outreach(): # Only in group chats
try:
self.daily_outreach.send_daily_question(peer_id)
except Exception as e:
print(f"Daily outreach error: {e}")

# Process potential responses to daily questions
if from_id > 0 and user:
try:
self.daily_outreach.process_potential_response(msg, from_id)
except Exception as e:
print(f"Response processing error: {e}")

messages = self.get_messages(event)
selected_message = messages[0] if len(messages) == 1 else None
selected_user = (
Expand Down
1 change: 1 addition & 0 deletions python/modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .data_service import BetterBotBaseDataService
from .data_builder import DataBuilder
from .vk_instance import VkInstance
from .daily_outreach import DailyOutreach
from .utils import (
get_default_programming_language,
contains_string,
Expand Down
120 changes: 120 additions & 0 deletions python/modules/daily_outreach.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
"""Daily outreach module for asking users about programming languages and GitHub profiles."""
import random
from datetime import datetime, timedelta
from typing import List, NoReturn, Optional
from regex import search, IGNORECASE

from .data_service import BetterBotBaseDataService
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
import config


class DailyOutreach:
"""Handles daily outreach to users without programming languages or GitHub profiles."""

QUESTIONS = [
"У вас есть страничка на GitHub?",
"Какие языки программирования вы знаете?"
]

def __init__(self, vk_instance, data_service: BetterBotBaseDataService):
self.vk_instance = vk_instance
self.data_service = data_service
self.last_outreach_date = None

def should_run_daily_outreach(self) -> bool:
"""Check if daily outreach should run (once per day)."""
today = datetime.now().date()
if self.last_outreach_date != today:
self.last_outreach_date = today
return True
return False

def find_users_without_profile_info(self, peer_id: int) -> List[int]:
"""Find users without programming languages or GitHub profiles."""
try:
member_ids = self.vk_instance.get_members_ids(peer_id)
if not member_ids:
return []

candidates = []
for uid in member_ids:
user = self.data_service.get_user(uid, self.vk_instance)

# Check if user has no programming languages and no GitHub profile
has_languages = (hasattr(user, 'programming_languages') and
user.programming_languages and
len(user.programming_languages) > 0)
has_github = (hasattr(user, 'github_profile') and
user.github_profile and
user.github_profile.strip() != "")

if not has_languages and not has_github:
candidates.append(uid)

return candidates
except Exception as e:
print(f"Error finding users: {e}")
return []

def select_random_user_and_question(self, candidates: List[int]) -> Optional[tuple]:
"""Select a random user and question."""
if not candidates:
return None

user_id = random.choice(candidates)
question = random.choice(self.QUESTIONS)
return user_id, question

def send_daily_question(self, peer_id: int) -> NoReturn:
"""Send daily question to a random user."""
candidates = self.find_users_without_profile_info(peer_id)

if not candidates:
return

selection = self.select_random_user_and_question(candidates)
if not selection:
return

user_id, question = selection
try:
user_name = self.vk_instance.get_user_name(user_id, "nom")
message = f"[id{user_id}|{user_name}], {question}"
self.vk_instance.send_msg(message, peer_id)
except Exception as e:
print(f"Error sending daily question: {e}")

def process_potential_response(self, msg: str, from_id: int) -> bool:
"""
Process a message that might be a response to our daily questions.
Returns True if response was processed, False otherwise.
"""
msg_lower = msg.lower()

# Check for GitHub profile response
github_match = search(r'github\.com/([a-zA-Z0-9-_]+)', msg, IGNORECASE)
if github_match:
username = github_match.group(1)
user = self.data_service.get_user(from_id, self.vk_instance)
user.github_profile = username
self.data_service.save_user(user)
return True

# Check for programming language response
for lang in config.DEFAULT_PROGRAMMING_LANGUAGES:
# Remove regex escaping for matching
lang_clean = lang.replace(r'\+', '+').replace(r'\-', '-').replace(r'\\', '')
if search(lang_clean, msg, IGNORECASE):
user = self.data_service.get_user(from_id, self.vk_instance)
if not hasattr(user, 'programming_languages'):
user.programming_languages = []
if lang_clean not in user.programming_languages:
user.programming_languages.append(lang_clean)
self.data_service.save_user(user)
return True

return False
Loading