|
2 | 2 | UI to render a Zulip message for display, and respond contextually to actions
|
3 | 3 | """
|
4 | 4 |
|
| 5 | +import json |
5 | 6 | import typing
|
6 | 7 | from collections import defaultdict
|
7 | 8 | from datetime import date, datetime
|
@@ -729,6 +730,36 @@ def main_view(self) -> List[Any]:
|
729 | 730 | "/me", f"<strong>{self.message['sender_full_name']}</strong>", 1
|
730 | 731 | )
|
731 | 732 |
|
| 733 | + # If message contains submessages (like polls, todo), process them |
| 734 | + # and update the message content. |
| 735 | + if self.message["submessages"]: |
| 736 | + try: |
| 737 | + first_submessage_content = json.loads( |
| 738 | + self.message["submessages"][0]["content"] |
| 739 | + ) |
| 740 | + except (json.JSONDecodeError, TypeError): |
| 741 | + first_submessage_content = {} |
| 742 | + |
| 743 | + if ( |
| 744 | + "widget_type" in first_submessage_content |
| 745 | + and first_submessage_content["widget_type"] == "poll" |
| 746 | + ): |
| 747 | + question, votes_for_option = self.process_poll_data( |
| 748 | + self.message["submessages"] |
| 749 | + ) |
| 750 | + |
| 751 | + if question: |
| 752 | + self.message[ |
| 753 | + "content" |
| 754 | + ] = f"<strong>Poll Question: {question}</strong>\n" |
| 755 | + else: |
| 756 | + self.message["content"] = "<strong>Add Poll Question</strong>\n" |
| 757 | + for option, voters in votes_for_option.items(): |
| 758 | + voter_count = len(voters) |
| 759 | + count_text = f"<strong>[{voter_count:^3}]</strong>" |
| 760 | + option_text = f"{option}" |
| 761 | + self.message["content"] += f"{count_text} {option_text}\n" |
| 762 | + |
732 | 763 | # Transform raw message content into markup (As needed by urwid.Text)
|
733 | 764 | content, self.message_links, self.time_mentions = self.transform_content(
|
734 | 765 | self.message["content"], self.model.server_url
|
@@ -812,6 +843,43 @@ def update_message_author_status(self) -> bool:
|
812 | 843 |
|
813 | 844 | return author_is_present
|
814 | 845 |
|
| 846 | + @classmethod |
| 847 | + def process_poll_data(cls, poll_data: Any) -> Tuple[str, Dict[str, List[int]]]: |
| 848 | + question = "" |
| 849 | + votes_for_option = {} |
| 850 | + |
| 851 | + for submessage in poll_data: |
| 852 | + content = submessage.get("content", {}) |
| 853 | + if isinstance(content, str): |
| 854 | + try: |
| 855 | + content = json.loads(content) |
| 856 | + except json.JSONDecodeError: |
| 857 | + continue |
| 858 | + |
| 859 | + if "widget_type" in content and content["widget_type"] == "poll": |
| 860 | + question = content["extra_data"]["question"] |
| 861 | + votes_for_option = { |
| 862 | + option: [] for option in content["extra_data"]["options"] |
| 863 | + } |
| 864 | + |
| 865 | + elif "type" in content and content["type"] == "vote": |
| 866 | + key = content["key"] |
| 867 | + if key.startswith("canned,"): |
| 868 | + index_str = key.split(",")[1] |
| 869 | + if index_str.isdigit(): |
| 870 | + index = int(index_str) |
| 871 | + if index < len(votes_for_option): |
| 872 | + option = list(votes_for_option.keys())[index] |
| 873 | + voter_id = submessage["sender_id"] |
| 874 | + if content["vote"] == -1: |
| 875 | + if voter_id in votes_for_option[option]: |
| 876 | + votes_for_option[option].remove(voter_id) |
| 877 | + else: |
| 878 | + if voter_id not in votes_for_option[option]: |
| 879 | + votes_for_option[option].append(voter_id) |
| 880 | + |
| 881 | + return question, votes_for_option |
| 882 | + |
815 | 883 | @classmethod
|
816 | 884 | def transform_content(
|
817 | 885 | cls, content: Any, server_url: str
|
|
0 commit comments