aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--slack/config.py25
-rw-r--r--slack/slack_api.py9
-rw-r--r--slack/slack_conversation.py20
-rw-r--r--slack/slack_message.py29
-rw-r--r--slack/slack_workspace.py15
-rw-r--r--typings/slack_api/slack_users_prefs.pyi16
-rw-r--r--typings/slack_rtm/slack_rtm_message.pyi7
7 files changed, 115 insertions, 6 deletions
diff --git a/slack/config.py b/slack/config.py
index 36e5726..10cc0a6 100644
--- a/slack/config.py
+++ b/slack/config.py
@@ -6,7 +6,7 @@ import weechat
from slack.log import print_error
from slack.shared import shared
-from slack.slack_conversation import invalidate_nicklists
+from slack.slack_conversation import invalidate_nicklists, update_buffer_props
from slack.slack_workspace import SlackWorkspace
from slack.util import get_callback_name
from slack.weechat_config import (
@@ -25,6 +25,14 @@ class SlackConfigSectionColor:
def __init__(self, weechat_config: WeeChatConfig):
self._section = WeeChatSection(weechat_config, "color")
+ self.buflist_muted_conversation = WeeChatOption(
+ self._section,
+ "buflist_muted_conversation",
+ "text color for muted conversations in the buflist",
+ WeeChatColor("darkgray"),
+ callback_change=self.config_change_buflist_muted_conversation_cb,
+ )
+
self.channel_mention = WeeChatOption(
self._section,
"channel_mention",
@@ -111,6 +119,11 @@ class SlackConfigSectionColor:
WeeChatColor("blue"),
)
+ def config_change_buflist_muted_conversation_cb(
+ self, option: WeeChatOption[WeeChatOptionType], parent_changed: bool
+ ):
+ update_buffer_props()
+
class SlackConfigSectionLook:
def __init__(self, weechat_config: WeeChatConfig):
@@ -177,6 +190,16 @@ class SlackConfigSectionLook:
"*",
)
+ self.muted_conversations_notify: WeeChatOption[
+ Literal["none", "personal_highlights", "all_highlights", "all"]
+ ] = WeeChatOption(
+ self._section,
+ "muted_conversations_notify",
+ "notify level to set for messages in muted conversations; none: don't notify for any messages; personal_highlights: only notify for personal highlights, i.e. not @channel and @here; all_highlights: notify for all highlights, but not other messages; all: notify for all messages, like other channels; note that this doesn't affect messages in threads you are subscribed to or in open thread buffers, those will always notify",
+ "personal_highlights",
+ string_values=["none", "personal_highlights", "all_highlights", "all"],
+ )
+
self.render_emoji_as: WeeChatOption[
Literal["emoji", "name", "both"]
] = WeeChatOption(
diff --git a/slack/slack_api.py b/slack/slack_api.py
index 9f57fdd..be74c2c 100644
--- a/slack/slack_api.py
+++ b/slack/slack_api.py
@@ -23,6 +23,7 @@ if TYPE_CHECKING:
from slack_api.slack_usergroups_info import SlackUsergroupsInfoResponse
from slack_api.slack_users_conversations import SlackUsersConversationsResponse
from slack_api.slack_users_info import SlackUserInfoResponse, SlackUsersInfoResponse
+ from slack_api.slack_users_prefs import SlackUsersPrefsGetResponse
from slack_edgeapi.slack_usergroups_info import SlackEdgeUsergroupsInfoResponse
from slack_edgeapi.slack_users_search import SlackUsersSearchResponse
@@ -134,6 +135,14 @@ class SlackApi(SlackApiCommon):
raise SlackApiError(self.workspace, method, response)
return response
+ async def fetch_users_get_prefs(self, prefs: Optional[str] = None):
+ method = "users.prefs.get"
+ params: Params = {"prefs": prefs} if prefs else {}
+ response: SlackUsersPrefsGetResponse = await self._fetch(method, params)
+ if response["ok"] is False:
+ raise SlackApiError(self.workspace, method, response)
+ return response
+
async def fetch_conversations_history(self, conversation: SlackConversation):
method = "conversations.history"
params: Params = {"channel": conversation.id}
diff --git a/slack/slack_conversation.py b/slack/slack_conversation.py
index ba76803..abfafa5 100644
--- a/slack/slack_conversation.py
+++ b/slack/slack_conversation.py
@@ -14,6 +14,7 @@ from slack.slack_message import MessagePriority, SlackMessage, SlackTs
from slack.slack_thread import SlackThread
from slack.slack_user import SlackBot, SlackUser, nick_color
from slack.task import gather, run_async
+from slack.util import with_color
if TYPE_CHECKING:
from slack_api.slack_conversations_info import SlackConversationsInfo
@@ -30,6 +31,12 @@ if TYPE_CHECKING:
from slack.slack_workspace import SlackWorkspace
+def update_buffer_props():
+ for workspace in shared.workspaces.values():
+ for conversation in workspace.open_conversations.values():
+ run_async(conversation.update_buffer_props())
+
+
def invalidate_nicklists():
for workspace in shared.workspaces.values():
for conversation in workspace.open_conversations.values():
@@ -164,6 +171,10 @@ class SlackConversation(SlackBuffer):
self._info["last_read"] = value
self.set_unread_and_hotlist()
+ @property
+ def muted(self) -> bool:
+ return self.id in self.workspace.muted_channels
+
async def sort_key(self) -> str:
type_sort_key = {
"channel": 0,
@@ -228,6 +239,10 @@ class SlackConversation(SlackBuffer):
name_without_prefix = await self.name()
name = f"{self.name_prefix('full_name')}{name_without_prefix}"
short_name = self.name_prefix("short_name") + name_without_prefix
+ if self.muted:
+ short_name = with_color(
+ shared.config.color.buflist_muted_conversation.value, short_name
+ )
return name, {
"short_name": short_name,
@@ -324,10 +339,15 @@ class SlackConversation(SlackBuffer):
self.hotlist_tss.add(message.ts)
if (
self.display_thread_replies()
+ and (
+ not self.muted
+ or shared.config.look.muted_conversations_notify.value == "all"
+ )
and message.latest_reply
and message.latest_reply > self.last_read
and message.latest_reply not in self.hotlist_tss
):
+ # TODO: Load subscribed threads, so they are added to hotlist for muted channels if they have highlights
priority = (
MessagePriority.PRIVATE
if self.buffer_type == "private"
diff --git a/slack/slack_message.py b/slack/slack_message.py
index c1953d3..c51c8b4 100644
--- a/slack/slack_message.py
+++ b/slack/slack_message.py
@@ -111,6 +111,7 @@ def convert_int_to_roman(num: int) -> str:
class MessagePriority(Enum):
+ NONE = "none"
LOW = weechat.WEECHAT_HOTLIST_LOW
MESSAGE = weechat.WEECHAT_HOTLIST_MESSAGE
PRIVATE = weechat.WEECHAT_HOTLIST_PRIVATE
@@ -221,7 +222,7 @@ class PendingMessageItem:
else:
assert_never(self.item_type)
- def should_highlight(self) -> bool:
+ def should_highlight(self, only_personal: bool) -> bool:
if self.item_type == "conversation":
return False
elif self.item_type == "user":
@@ -231,7 +232,7 @@ class PendingMessageItem:
return False
elif self.item_type == "broadcast":
# TODO: figure out how to handle here broadcast
- return True
+ return not only_personal
elif self.item_type == "message_nick":
return False
else:
@@ -342,8 +343,22 @@ class SlackMessage:
@property
def priority(self) -> MessagePriority:
- if self.should_highlight():
+ if (
+ self.conversation.muted
+ and shared.config.look.muted_conversations_notify.value == "none"
+ ):
+ return MessagePriority.NONE
+ elif self.should_highlight(
+ self.conversation.muted
+ and shared.config.look.muted_conversations_notify.value
+ == "personal_highlights"
+ ):
return MessagePriority.HIGHLIGHT
+ elif (
+ self.conversation.muted
+ and shared.config.look.muted_conversations_notify.value != "all"
+ ):
+ return MessagePriority.NONE
elif self.subtype in [
"channel_join",
"group_join",
@@ -367,6 +382,8 @@ class SlackMessage:
return "notify_message"
elif priority == MessagePriority.LOW:
return None
+ elif priority == MessagePriority.NONE:
+ return "notify_none"
else:
assert_never(priority)
@@ -427,12 +444,14 @@ class SlackMessage:
reaction["count"] -= 1
self._rendered_message = None
- def should_highlight(self) -> bool:
+ def should_highlight(self, only_personal: bool) -> bool:
# TODO: Highlight words from user preferences
parsed_message = self._parse_message_text()
for item in parsed_message:
- if isinstance(item, PendingMessageItem) and item.should_highlight():
+ if isinstance(item, PendingMessageItem) and item.should_highlight(
+ only_personal
+ ):
return True
return False
diff --git a/slack/slack_workspace.py b/slack/slack_workspace.py
index 76c8350..286f5c7 100644
--- a/slack/slack_workspace.py
+++ b/slack/slack_workspace.py
@@ -12,6 +12,7 @@ from typing import (
Iterable,
List,
Optional,
+ Set,
Tuple,
Type,
TypeVar,
@@ -193,6 +194,7 @@ class SlackWorkspace:
self.users = SlackUsers(self)
self.bots = SlackBots(self)
self.usergroups = SlackUsergroups(self)
+ self.muted_channels: Set[str] = set()
def __repr__(self):
return f"{self.__class__.__name__}({self.name})"
@@ -241,6 +243,9 @@ class SlackWorkspace:
await self._connect_ws(rtm_connect["url"])
+ prefs = await self.api.fetch_users_get_prefs("muted_channels")
+ self.muted_channels = set(prefs["prefs"]["muted_channels"].split(","))
+
if not self.api.edgeapi.is_available:
usergroups = await self.api.fetch_usergroups_list()
for usergroup in usergroups["usergroups"]:
@@ -332,6 +337,16 @@ class SlackWorkspace:
try:
if data["type"] == "hello":
return
+ elif data["type"] == "pref_change":
+ if data["name"] == "muted_channels":
+ new_muted_channels = set(data["value"].split(","))
+ changed_channels = self.muted_channels ^ new_muted_channels
+ self.muted_channels = new_muted_channels
+ for channel_id in changed_channels:
+ channel = self.open_conversations.get(channel_id)
+ if channel:
+ await channel.update_buffer_props()
+ return
elif data["type"] == "reaction_added" or data["type"] == "reaction_removed":
channel_id = data["item"]["channel"]
elif (
diff --git a/typings/slack_api/slack_users_prefs.pyi b/typings/slack_api/slack_users_prefs.pyi
new file mode 100644
index 0000000..13cc804
--- /dev/null
+++ b/typings/slack_api/slack_users_prefs.pyi
@@ -0,0 +1,16 @@
+from __future__ import annotations
+
+from slack_api.slack_common import SlackErrorResponse
+from typing_extensions import Literal, TypedDict, final
+
+@final
+class SlackUsersPrefs(TypedDict):
+ muted_channels: str
+ # Incomplete
+
+@final
+class SlackUsersPrefsGetSuccessResponse(TypedDict):
+ ok: Literal[True]
+ prefs: SlackUsersPrefs
+
+SlackUsersPrefsGetResponse = SlackUsersPrefsGetSuccessResponse | SlackErrorResponse
diff --git a/typings/slack_rtm/slack_rtm_message.pyi b/typings/slack_rtm/slack_rtm_message.pyi
index 7f566e2..709f4a5 100644
--- a/typings/slack_rtm/slack_rtm_message.pyi
+++ b/typings/slack_rtm/slack_rtm_message.pyi
@@ -239,6 +239,12 @@ class SlackUserTyping(TypedDict):
id: int
user: str
+@final
+class SlackPrefChange(TypedDict):
+ type: Literal["pref_change"]
+ name: str
+ value: str
+
SlackMessageRtm = (
SlackMessageStandardRtm
| SlackMessageMeRtm
@@ -273,4 +279,5 @@ SlackRtmMessage = (
| SlackShRoomJoin
| SlackShRoomUpdate
| SlackUserTyping
+ | SlackPrefChange
)