diff --git a/experiments/test_logic.py b/experiments/test_logic.py new file mode 100644 index 00000000..72daa247 --- /dev/null +++ b/experiments/test_logic.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +""" +Simple test to verify the logic of top position calculation. +This test mimics the logic without importing the actual modules. +""" + +def calculate_real_karma(user, POSITIVE_VOTES_PER_KARMA=3, NEGATIVE_VOTES_PER_KARMA=2): + """Mock implementation of calculate_real_karma""" + base_karma = user["karma"] + up_votes = len(user["supporters"]) / POSITIVE_VOTES_PER_KARMA + down_votes = len(user["opponents"]) / NEGATIVE_VOTES_PER_KARMA + return base_karma + up_votes - down_votes + +def get_users_sorted_by_karma(mock_users): + """Mock implementation of get_users_sorted_by_karma""" + # Filter to only chat members (all in our mock) + users = mock_users.copy() + + # Sort by real karma + users.sort(key=lambda u: calculate_real_karma(u), reverse=True) + return users + +def get_user_top_position(user, mock_users): + """Mock implementation of get_user_top_position""" + users = get_users_sorted_by_karma(mock_users) + users = [u for u in users if + (u["karma"] != 0) or + ("programming_languages" in u and len(u["programming_languages"]) > 0)] + + user_uid = user["uid"] + for index, ranked_user in enumerate(users): + if ranked_user["uid"] == user_uid: + return index + 1 # 1-based position + return 0 # User not found in ranking + +def test_top_position(): + """Test the top position logic""" + # Mock users with different karma values + mock_users = [ + {"uid": 1, "karma": 100, "supporters": [], "opponents": [], "name": "User1", "programming_languages": ["Python"]}, + {"uid": 2, "karma": 80, "supporters": [101, 102], "opponents": [], "name": "User2", "programming_languages": ["JavaScript"]}, + {"uid": 3, "karma": 60, "supporters": [], "opponents": [201], "name": "User3", "programming_languages": ["Java"]}, + {"uid": 4, "karma": 40, "supporters": [301], "opponents": [401, 402, 403], "name": "User4", "programming_languages": ["C++"]}, + {"uid": 5, "karma": 20, "supporters": [], "opponents": [], "name": "User5", "programming_languages": ["Go"]}, + {"uid": 6, "karma": 0, "supporters": [], "opponents": [], "name": "User6", "programming_languages": []}, # Should be excluded + ] + + print("Mock users with calculated real karma:") + sorted_users = get_users_sorted_by_karma(mock_users) + for i, user in enumerate(sorted_users): + real_karma = calculate_real_karma(user) + print(f" {i+1}. {user['name']} (uid: {user['uid']}) - karma: {user['karma']}, real karma: {real_karma:.1f}") + + print("\nFiltered users for ranking (excluding users with 0 karma and no languages):") + filtered_users = [u for u in sorted_users if + (u["karma"] != 0) or + ("programming_languages" in u and len(u["programming_languages"]) > 0)] + for i, user in enumerate(filtered_users): + print(f" {i+1}. {user['name']} (uid: {user['uid']})") + + print("\nTesting position calculation:") + for user in mock_users: + position = get_user_top_position(user, mock_users) + print(f" {user['name']} (uid: {user['uid']}) -> position: {position}") + +if __name__ == "__main__": + test_top_position() \ No newline at end of file diff --git a/experiments/test_top_position.py b/experiments/test_top_position.py new file mode 100644 index 00000000..aa37c5db --- /dev/null +++ b/experiments/test_top_position.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +""" +Test script to verify the top position functionality works correctly. +""" +import sys +import os +sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python')) + +# Mock the necessary dependencies for testing +class MockBetterUser(dict): + pass + +class MockVk: + def get_members_ids(self, peer_id): + return [1, 2, 3, 4, 5] # Mock member IDs + +class MockDataService: + def get_user_property(self, user, prop): + return user[prop] + + def get_user_sorted_programming_languages(self, user): + return user.get("programming_languages", []) + + def get_users(self, other_keys=None, sort_key=None, reverse_sort=True): + # Mock users data with different karma values + mock_users = [ + {"uid": 1, "karma": 100, "supporters": [], "opponents": [], "name": "User1", "programming_languages": ["Python"], "github_profile": "user1"}, + {"uid": 2, "karma": 80, "supporters": [], "opponents": [], "name": "User2", "programming_languages": ["JavaScript"], "github_profile": "user2"}, + {"uid": 3, "karma": 60, "supporters": [], "opponents": [], "name": "User3", "programming_languages": ["Java"], "github_profile": "user3"}, + {"uid": 4, "karma": 40, "supporters": [], "opponents": [], "name": "User4", "programming_languages": ["C++"], "github_profile": "user4"}, + {"uid": 5, "karma": 20, "supporters": [], "opponents": [], "name": "User5", "programming_languages": ["Go"], "github_profile": "user5"}, + ] + + if sort_key: + mock_users.sort(key=sort_key, reverse=reverse_sort) + + return mock_users + +# Import the modules after setting up mocks +from modules.data_builder import DataBuilder +from modules.commands_builder import CommandsBuilder + +def test_get_user_top_position(): + """Test that the get_user_top_position function works correctly""" + vk_instance = MockVk() + data_service = MockDataService() + + # Test user with highest karma (should be position 1) + user1 = MockBetterUser({"uid": 1, "karma": 100, "supporters": [], "opponents": [], "name": "User1", "programming_languages": ["Python"], "github_profile": "user1"}) + position1 = DataBuilder.get_user_top_position(user1, vk_instance, data_service, 2000000001) + print(f"User1 (karma 100) position: {position1}") + + # Test user with middle karma (should be position 3) + user3 = MockBetterUser({"uid": 3, "karma": 60, "supporters": [], "opponents": [], "name": "User3", "programming_languages": ["Java"], "github_profile": "user3"}) + position3 = DataBuilder.get_user_top_position(user3, vk_instance, data_service, 2000000001) + print(f"User3 (karma 60) position: {position3}") + + # Test user with lowest karma (should be position 5) + user5 = MockBetterUser({"uid": 5, "karma": 20, "supporters": [], "opponents": [], "name": "User5", "programming_languages": ["Go"], "github_profile": "user5"}) + position5 = DataBuilder.get_user_top_position(user5, vk_instance, data_service, 2000000001) + print(f"User5 (karma 20) position: {position5}") + + # Test non-existent user (should be position 0) + user_fake = MockBetterUser({"uid": 999, "karma": 50, "supporters": [], "opponents": [], "name": "FakeUser", "programming_languages": ["Python"], "github_profile": "fake"}) + position_fake = DataBuilder.get_user_top_position(user_fake, vk_instance, data_service, 2000000001) + print(f"Fake user position: {position_fake}") + +def test_build_info_message(): + """Test that the build_info_message includes top position""" + vk_instance = MockVk() + data_service = MockDataService() + + user2 = MockBetterUser({"uid": 2, "karma": 80, "supporters": [], "opponents": [], "name": "User2", "programming_languages": ["JavaScript"], "github_profile": "user2"}) + + # Test with karma enabled and group chat + message = CommandsBuilder.build_info_message( + user2, data_service, 2, True, vk_instance, 2000000001 + ) + print("Info message with top position:") + print(message) + print() + + # Test without karma + message_no_karma = CommandsBuilder.build_info_message( + user2, data_service, 2, False, vk_instance, 2000000001 + ) + print("Info message without karma:") + print(message_no_karma) + +if __name__ == "__main__": + print("Testing top position functionality...") + test_get_user_top_position() + print() + test_build_info_message() + print("All tests completed!") \ No newline at end of file diff --git a/python/modules/commands.py b/python/modules/commands.py index 93d99817..9fef6eff 100644 --- a/python/modules/commands.py +++ b/python/modules/commands.py @@ -56,7 +56,8 @@ def info_message(self) -> NoReturn: """Sends user info""" self.vk_instance.send_msg( CommandsBuilder.build_info_message( - self.user, self.data_service, self.from_id, self.karma_enabled), + self.user, self.data_service, self.from_id, self.karma_enabled, + self.vk_instance, self.peer_id), self.peer_id) def update_command(self) -> NoReturn: diff --git a/python/modules/commands_builder.py b/python/modules/commands_builder.py index 29dc739f..b2f345b1 100644 --- a/python/modules/commands_builder.py +++ b/python/modules/commands_builder.py @@ -36,26 +36,38 @@ def build_info_message( user: BetterUser, data: BetterBotBaseDataService, from_id: int, - karma: bool + karma: bool, + vk_instance=None, + peer_id: int = 0 ) -> str: """Builds info message. Arguments: - {user} - selected user; - {data} - data service; - - {peer_id} - chat ID; - - {karma} - is karma enabled in chat. + - {from_id} - user ID requesting info; + - {karma} - is karma enabled in chat; + - {vk_instance} - VK instance for getting top position; + - {peer_id} - chat ID for getting top position. """ programming_languages_string = DataBuilder.build_programming_languages(user, data) profile = DataBuilder.build_github_profile(user, data, default="отсутствует") mention = f"[id{data.get_user_property(user, 'uid')}|{data.get_user_property(user, 'name')}]" is_self = data.get_user_property(user, 'uid') == from_id karma_str: str = "" + + # Get top position if in group chat and karma enabled + top_position_str = "" + if karma and peer_id > 2e9 and vk_instance: + position = DataBuilder.get_user_top_position(user, vk_instance, data, peer_id) + if position > 0: + top_position_str = f" (место в топе: {position})" + if karma: if is_self: - karma_str = f"{mention}, Ваша карма - {DataBuilder.build_karma(user, data)}.\n" + karma_str = f"{mention}, Ваша карма - {DataBuilder.build_karma(user, data)}{top_position_str}.\n" else: - karma_str = f"Карма {mention} - {DataBuilder.build_karma(user, data)}.\n" + karma_str = f"Карма {mention} - {DataBuilder.build_karma(user, data)}{top_position_str}.\n" else: karma_str = f"{mention}.\n" return (f"{karma_str}" diff --git a/python/modules/data_builder.py b/python/modules/data_builder.py index c594f7e1..db87e46c 100644 --- a/python/modules/data_builder.py +++ b/python/modules/data_builder.py @@ -88,6 +88,31 @@ def get_users_sorted_by_name( users.reverse() return users + @staticmethod + def get_user_top_position( + user: BetterUser, + vk_instance: Vk, + data: BetterBotBaseDataService, + peer_id: int + ) -> int: + """Gets user's position in the top ranking (1-based index). + + Returns: + - Position number (1 for first place, 2 for second, etc.) + - 0 if user is not found in ranking + """ + users = DataBuilder.get_users_sorted_by_karma(vk_instance, data, peer_id) + users = [u for u in users if + (u["karma"] != 0) or + ("programming_languages" in u and len(u["programming_languages"]) > 0) + ] + + user_uid = user["uid"] + for index, ranked_user in enumerate(users): + if ranked_user["uid"] == user_uid: + return index + 1 # 1-based position + return 0 # User not found in ranking + @staticmethod def calculate_real_karma( user: BetterUser,