diff options
Diffstat (limited to 'slack')
-rw-r--r-- | slack/commands.py | 24 | ||||
-rw-r--r-- | slack/register.py | 13 | ||||
-rw-r--r-- | slack/shared.py | 1 | ||||
-rw-r--r-- | slack/slack_api.py | 26 | ||||
-rw-r--r-- | slack/slack_buffer.py | 23 | ||||
-rw-r--r-- | slack/slack_conversation.py | 5 | ||||
-rw-r--r-- | slack/slack_thread.py | 15 | ||||
-rw-r--r-- | slack/slack_workspace.py | 10 |
8 files changed, 112 insertions, 5 deletions
diff --git a/slack/commands.py b/slack/commands.py index 7315359..476c4ba 100644 --- a/slack/commands.py +++ b/slack/commands.py @@ -18,7 +18,7 @@ from slack.slack_conversation import SlackConversation from slack.slack_thread import SlackThread from slack.slack_user import name_from_user_info_without_spaces from slack.slack_workspace import SlackWorkspace -from slack.task import run_async +from slack.task import run_async, sleep from slack.util import get_callback_name, with_color from slack.weechat_config import WeeChatOption, WeeChatOptionTypes @@ -532,6 +532,19 @@ def complete_previous(slack_buffer: SlackBuffer, query: str) -> int: return weechat.WEECHAT_RC_OK +async def mark_read(slack_buffer: SlackBuffer): + # Sleep so the read marker is updated before we run slack_buffer.mark_read + await sleep(1) + await slack_buffer.mark_read() + + +def buffer_set_unread_cb(data: str, buffer: str, command: str) -> int: + slack_buffer = shared.buffers.get(buffer) + if slack_buffer: + run_async(mark_read(slack_buffer)) + return weechat.WEECHAT_RC_OK + + def input_complete_cb(data: str, buffer: str, command: str) -> int: slack_buffer = shared.buffers.get(buffer) if slack_buffer: @@ -558,6 +571,15 @@ def input_complete_cb(data: str, buffer: str, command: str) -> int: def register_commands(): weechat.hook_command_run( + "/buffer set unread", get_callback_name(buffer_set_unread_cb), "" + ) + weechat.hook_command_run( + "/buffer set unread *", get_callback_name(buffer_set_unread_cb), "" + ) + weechat.hook_command_run( + "/input set_unread_current_buffer", get_callback_name(buffer_set_unread_cb), "" + ) + weechat.hook_command_run( "/input complete_*", get_callback_name(input_complete_cb), "" ) weechat.hook_completion( diff --git a/slack/register.py b/slack/register.py index 5e81792..2e85fcc 100644 --- a/slack/register.py +++ b/slack/register.py @@ -20,9 +20,18 @@ def shutdown_cb(): def signal_buffer_switch_cb(data: str, signal: str, buffer_pointer: str) -> int: + prev_buffer_pointer = shared.current_buffer_pointer + shared.current_buffer_pointer = buffer_pointer + + if prev_buffer_pointer != buffer_pointer: + prev_slack_buffer = shared.buffers.get(prev_buffer_pointer) + if prev_slack_buffer: + run_async(prev_slack_buffer.mark_read()) + slack_buffer = shared.buffers.get(buffer_pointer) if slack_buffer: run_async(slack_buffer.buffer_switched_to()) + return weechat.WEECHAT_RC_OK @@ -105,6 +114,7 @@ def register(): "", ): shared.weechat_version = int(weechat.info_get("version_number", "") or 0) + shared.current_buffer_pointer = weechat.current_buffer() shared.standard_emojis = load_standard_emojis() shared.workspaces = {} shared.config = SlackConfig() @@ -115,9 +125,6 @@ def register(): "buffer_switch", get_callback_name(signal_buffer_switch_cb), "" ) weechat.hook_signal( - "window_switch", get_callback_name(signal_buffer_switch_cb), "" - ) - weechat.hook_signal( "input_text_changed", get_callback_name(input_text_changed_cb), "" ) weechat.hook_signal( diff --git a/slack/shared.py b/slack/shared.py index 0cf25f4..1661a04 100644 --- a/slack/shared.py +++ b/slack/shared.py @@ -25,6 +25,7 @@ class Shared: self.active_futures: Dict[str, Future[object]] = {} self.buffers: Dict[str, SlackBuffer] = {} self.workspaces: Dict[str, SlackWorkspace] = {} + self.current_buffer_pointer: str self.config: SlackConfig self.uncaught_errors: List[UncaughtError] = [] self.standard_emojis: Dict[str, Emoji] diff --git a/slack/slack_api.py b/slack/slack_api.py index 3aa1d57..8e0b28a 100644 --- a/slack/slack_api.py +++ b/slack/slack_api.py @@ -14,6 +14,7 @@ from slack.util import chunked if TYPE_CHECKING: from slack_api.slack_bots_info import SlackBotInfoResponse, SlackBotsInfoResponse + from slack_api.slack_common import SlackGenericResponse from slack_api.slack_conversations_history import SlackConversationsHistoryResponse from slack_api.slack_conversations_info import SlackConversationsInfoResponse from slack_api.slack_conversations_members import SlackConversationsMembersResponse @@ -49,7 +50,7 @@ class SlackApiCommon: class SlackEdgeApi(SlackApiCommon): @property def is_available(self) -> bool: - return self.workspace.config.api_token.value.startswith("xoxc-") + return self.workspace.token_type == "session" async def _fetch_edgeapi(self, method: str, params: EdgeParams = {}): enterprise_id_part = ( @@ -248,3 +249,26 @@ class SlackApi(SlackApiCommon): if response["ok"] is False: raise SlackApiError(self.workspace, method, response) return response + + async def conversations_mark(self, conversation: SlackConversation, ts: SlackTs): + method = "conversations.mark" + params: Params = {"channel": conversation.id, "ts": ts} + response: SlackGenericResponse = await self._fetch(method, params) + if response["ok"] is False: + raise SlackApiError(self.workspace, method, response, params) + return response + + async def subscriptions_thread_mark( + self, conversation: SlackConversation, thread_ts: SlackTs, ts: SlackTs + ): + method = "subscriptions.thread.mark" + params: Params = { + "channel": conversation.id, + "thread_ts": thread_ts, + "ts": ts, + "read": 1, + } + response: SlackGenericResponse = await self._fetch(method, params) + if response["ok"] is False: + raise SlackApiError(self.workspace, method, response, params) + return response diff --git a/slack/slack_buffer.py b/slack/slack_buffer.py index e2cdeac..3da8aad 100644 --- a/slack/slack_buffer.py +++ b/slack/slack_buffer.py @@ -259,6 +259,29 @@ class SlackBuffer(ABC): if backlog: weechat.buffer_set(self.buffer_pointer, "unread", "") + def last_read_line_ts(self) -> Optional[SlackTs]: + if self.buffer_pointer: + own_lines = weechat.hdata_pointer( + weechat.hdata_get("buffer"), self.buffer_pointer, "own_lines" + ) + first_line_not_read = weechat.hdata_integer( + weechat.hdata_get("lines"), own_lines, "first_line_not_read" + ) + if first_line_not_read: + return + line = weechat.hdata_pointer( + weechat.hdata_get("lines"), own_lines, "last_read_line" + ) + while line: + ts = hdata_line_ts(line) + if ts: + return ts + line = weechat.hdata_move(weechat.hdata_get("line"), line, -1) + + @abstractmethod + async def mark_read(self) -> None: + raise NotImplementedError() + def set_unread_and_hotlist(self): if self.buffer_pointer: # TODO: Move unread marker to correct position according to last_read for WeeChat >= 4.0.0 diff --git a/slack/slack_conversation.py b/slack/slack_conversation.py index e290933..aa8c66e 100644 --- a/slack/slack_conversation.py +++ b/slack/slack_conversation.py @@ -529,3 +529,8 @@ class SlackConversation(SlackBuffer): else: nick = await message.nick(colorize=False, only_nick=True) self.nicklist_add_user(sender, nick) + + async def mark_read(self): + last_read_line_ts = self.last_read_line_ts() + if last_read_line_ts and last_read_line_ts != self.last_read: + await self._api.conversations_mark(self, last_read_line_ts) diff --git a/slack/slack_thread.py b/slack/slack_thread.py index 44a6751..24bdc66 100644 --- a/slack/slack_thread.py +++ b/slack/slack_thread.py @@ -91,3 +91,18 @@ class SlackThread(SlackBuffer): await self.print_history() self.history_pending = False + + async def mark_read(self): + # subscriptions.thread.mark is only available for session tokens + if self.workspace.token_type != "session": + return + + # last_read can only be set if it exists (which is on threads you're subscribed to) + if self.last_read == SlackTs("0.0"): + return + + last_read_line_ts = self.last_read_line_ts() + if last_read_line_ts and last_read_line_ts != self.last_read: + await self._api.subscriptions_thread_mark( + self.parent.conversation, self.parent.ts, last_read_line_ts + ) diff --git a/slack/slack_workspace.py b/slack/slack_workspace.py index 59ac415..f202a86 100644 --- a/slack/slack_workspace.py +++ b/slack/slack_workspace.py @@ -50,6 +50,7 @@ if TYPE_CHECKING: from slack_api.slack_users_conversations import SlackUsersConversations from slack_api.slack_users_info import SlackUserInfo from slack_rtm.slack_rtm_message import SlackRtmMessage + from typing_extensions import Literal else: SlackBotInfo = object SlackConversationsInfo = object @@ -197,6 +198,15 @@ class SlackWorkspace: return f"{self.__class__.__name__}('{self.name}')" @property + def token_type(self) -> Literal["oauth", "session", "unknown"]: + if self.config.api_token.value.startswith("xoxp-"): + return "oauth" + elif self.config.api_token.value.startswith("xoxc-"): + return "session" + else: + return "unknown" + + @property def is_connected(self): return self._is_connected |