3
3
import concurrent .futures
4
4
import functools
5
5
import json
6
+ import re
6
7
import os
7
8
import requests
8
9
import sys
10
+ import platform
9
11
import time
10
12
import traceback
11
13
import tempfile
12
14
import urwid
13
15
from datetime import datetime
16
+
14
17
from sclack .components import Attachment , Channel , ChannelHeader , ChatBox , Dm
15
18
from sclack .components import Indicators , MarkdownText , Message , MessageBox
16
19
from sclack .components import NewMessagesDivider , Profile , ProfileSideBar
@@ -84,6 +87,48 @@ def __init__(self, config):
84
87
)
85
88
self .configure_screen (self .urwid_loop .screen )
86
89
self .last_keypress = (0 , None )
90
+ self .mentioned_patterns = None
91
+
92
+ def get_mentioned_patterns (self ):
93
+ slack_mentions = [
94
+ '<!everyone>' ,
95
+ '<!here>' ,
96
+ '<!channel>' ,
97
+ '<@{}>' .format (self .store .state .auth ['user_id' ]),
98
+ ]
99
+
100
+ patterns = []
101
+
102
+ for mention in slack_mentions :
103
+ patterns .append ('^{}[ ]+' .format (mention ))
104
+ patterns .append ('^{}$' .format (mention ))
105
+ patterns .append ('[ ]+{}' .format (mention ))
106
+
107
+ return re .compile ('|' .join (patterns ))
108
+
109
+ def should_notify_me (self , message_obj ):
110
+ """
111
+ Checking whether notify to user
112
+ :param message_obj:
113
+ :return:
114
+ """
115
+ # You send message, don't need notification
116
+ if self .config ['features' ]['notification' ] in ['' , 'none' ] or message_obj ['user' ] == self .store .state .auth ['user_id' ]:
117
+ return False
118
+
119
+ if self .config ['features' ]['notification' ] == 'all' :
120
+ return True
121
+
122
+ # Private message
123
+ if message_obj .get ('channel' ) is not None and message_obj .get ('channel' )[0 ] == 'D' :
124
+ return True
125
+
126
+ regex = self .mentioned_patterns
127
+ if regex is None :
128
+ regex = self .get_mentioned_patterns ()
129
+ self .mentioned_patterns = regex
130
+
131
+ return len (re .findall (regex , message_obj ['text' ])) > 0
87
132
88
133
def start (self ):
89
134
self ._loading = True
@@ -140,6 +185,8 @@ def mount_sidebar(self, executor):
140
185
loop .run_in_executor (executor , self .store .load_users ),
141
186
loop .run_in_executor (executor , self .store .load_user_dnd ),
142
187
)
188
+ self .mentioned_patterns = self .get_mentioned_patterns ()
189
+
143
190
profile = Profile (name = self .store .state .auth ['user' ], is_snoozed = self .store .state .is_snoozed )
144
191
channels = [
145
192
Channel (
@@ -158,7 +205,7 @@ def mount_sidebar(self, executor):
158
205
if user :
159
206
dms .append (Dm (
160
207
dm ['id' ],
161
- name = user . get ( 'display_name' ) or user . get ( 'real_name' ) or user [ 'name' ] ,
208
+ name = self . store . get_user_display_name ( user ) ,
162
209
user = dm ['user' ],
163
210
you = user ['id' ] == self .store .state .auth ['user_id' ]
164
211
))
@@ -286,7 +333,7 @@ def go_to_profile(self, user_id):
286
333
return
287
334
self .store .state .profile_user_id = user_id
288
335
profile = ProfileSideBar (
289
- user . get ( 'display_name' ) or user . get ( 'real_name' ) or user [ 'name' ] ,
336
+ self . store . get_user_display_name ( user ) ,
290
337
user ['profile' ].get ('status_text' , None ),
291
338
user ['profile' ].get ('tz_label' , None ),
292
339
user ['profile' ].get ('phone' , None ),
@@ -302,7 +349,7 @@ def render_chatbox_header(self):
302
349
if self .store .state .channel ['id' ][0 ] == 'D' :
303
350
user = self .store .find_user_by_id (self .store .state .channel ['user' ])
304
351
header = ChannelHeader (
305
- name = user . get ( 'display_name' ) or user . get ( 'real_name' ) or user [ 'name' ] ,
352
+ name = self . store . get_user_display_name ( user ) ,
306
353
topic = user ['profile' ]['status_text' ],
307
354
is_starred = self .store .state .channel .get ('is_starred' , False ),
308
355
is_dm_workaround_please_remove_me = True
@@ -324,6 +371,16 @@ def on_change_topic(self, text):
324
371
self .store .set_topic (self .store .state .channel ['id' ], text )
325
372
self .go_to_sidebar ()
326
373
374
+ def notification_messages (self , messages ):
375
+ """
376
+ Check and send notifications
377
+ :param messages:
378
+ :return:
379
+ """
380
+ for message in messages :
381
+ if self .should_notify_me (message ):
382
+ self .send_notification (message , MarkdownText (message ['text' ]))
383
+
327
384
def render_message (self , message , channel_id = None ):
328
385
is_app = False
329
386
subtype = message .get ('subtype' )
@@ -375,6 +432,7 @@ def render_message(self, message, channel_id=None):
375
432
return None
376
433
377
434
user_id = user ['id' ]
435
+ # TODO
378
436
user_name = user ['profile' ]['display_name' ] or user .get ('name' )
379
437
color = user .get ('color' )
380
438
if message .get ('file' ):
@@ -387,6 +445,7 @@ def render_message(self, message, channel_id=None):
387
445
return None
388
446
389
447
user_id = user ['id' ]
448
+ # TODO
390
449
user_name = user ['profile' ]['display_name' ] or user .get ('name' )
391
450
color = user .get ('color' )
392
451
@@ -399,6 +458,7 @@ def render_message(self, message, channel_id=None):
399
458
]
400
459
401
460
attachments = []
461
+
402
462
for attachment in message .get ('attachments' , []):
403
463
attachment_widget = Attachment (
404
464
service_name = attachment .get ('service_name' ),
@@ -475,8 +535,9 @@ def render_messages(self, messages, channel_id=None):
475
535
previous_date = self .store .state .last_date
476
536
last_read_datetime = datetime .fromtimestamp (float (self .store .state .channel .get ('last_read' , '0' )))
477
537
today = datetime .today ().date ()
478
- for message in messages :
479
- message_datetime = datetime .fromtimestamp (float (message ['ts' ]))
538
+
539
+ for raw_message in messages :
540
+ message_datetime = datetime .fromtimestamp (float (raw_message ['ts' ]))
480
541
message_date = message_datetime .date ()
481
542
date_text = None
482
543
unread_text = None
@@ -505,6 +566,42 @@ def render_messages(self, messages, channel_id=None):
505
566
506
567
return _messages
507
568
569
+ def send_notification (self , raw_message , markdown_text ):
570
+ """
571
+ Only MacOS
572
+ @TODO Linux libnotify and Windows
573
+ :param raw_message:
574
+ :param markdown_text:
575
+ :return:
576
+ """
577
+ user = self .store .find_user_by_id (raw_message .get ('user' ))
578
+ sender_name = self .store .get_user_display_name (user )
579
+
580
+ # TODO Checking bot
581
+ if raw_message .get ('channel' )[0 ] == 'D' :
582
+ notification_title = 'New message in {}' .format (
583
+ self .store .state .auth ['team' ]
584
+ )
585
+ else :
586
+ notification_title = 'New message in {} #{}' .format (
587
+ self .store .state .auth ['team' ],
588
+ self .store .get_channel_name (raw_message .get ('channel' )),
589
+ )
590
+
591
+ sub_title = sender_name
592
+
593
+ if platform .system () == 'Darwin' :
594
+ # Macos
595
+ import pync
596
+ pync .notify (
597
+ markdown_text .render_text (),
598
+ title = notification_title ,
599
+ subtitle = sub_title ,
600
+ appIcon = './resources/slack_icon.png'
601
+ )
602
+ else :
603
+ pass
604
+
508
605
def handle_mark_read (self , data ):
509
606
"""
510
607
Mark as read to bottom
@@ -633,6 +730,7 @@ def stop_typing(*args):
633
730
self .chatbox .message_box .typing = None
634
731
635
732
alarm = None
733
+
636
734
while self .store .slack .server .connected is True :
637
735
events = self .store .slack .rtm_read ()
638
736
for event in events :
@@ -664,10 +762,15 @@ def stop_typing(*args):
664
762
self .chatbox .body .scroll_to_bottom ()
665
763
else :
666
764
pass
765
+
766
+ if event .get ('subtype' ) != 'message_deleted' and event .get ('subtype' ) != 'message_changed' :
767
+ # Notification
768
+ self .notification_messages ([event ])
667
769
elif event ['type' ] == 'user_typing' :
668
770
if event .get ('channel' ) == self .store .state .channel ['id' ]:
669
771
user = self .store .find_user_by_id (event ['user' ])
670
- name = user .get ('display_name' ) or user .get ('real_name' ) or user ['name' ]
772
+ name = self .store .get_user_display_name (user )
773
+
671
774
if alarm is not None :
672
775
self .urwid_loop .remove_alarm (alarm )
673
776
self .chatbox .message_box .typing = name
@@ -799,6 +902,7 @@ def ask_for_token(json_config):
799
902
config_file .write (json .dumps (token_config , indent = False ))
800
903
json_config .update (token_config )
801
904
905
+
802
906
if __name__ == '__main__' :
803
907
json_config = {}
804
908
with open ('./config.json' , 'r' ) as config_file :
0 commit comments