-
Notifications
You must be signed in to change notification settings - Fork 117
/
slack-all-threads-buffer.el
312 lines (273 loc) · 13.9 KB
/
slack-all-threads-buffer.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
;;; slack-all-threads-buffer.el --- -*- lexical-binding: t; -*-
;; Copyright (C) 2018
;; Author: <yuya373@archlinux>
;; Keywords:
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
(require 'eieio)
(require 'slack-util)
(require 'slack-buffer)
(require 'slack-create-message)
(require 'slack-message-buffer)
(defconst slack-subscriptions-thread-get-view-url "https://slack.com/api/subscriptions.thread.getView")
(defconst slack-subscriptions-thread-clear-all-url "https://slack.com/api/subscriptions.thread.clearAll")
(define-derived-mode slack-all-threads-buffer-mode
slack-buffer-mode
"Slack All Treads")
(defface slack-all-thread-buffer-thread-header-face
'((t (:weight bold :height 1.2)))
"Face used to All Threads buffer's each threads header."
:group 'slack)
(defclass slack-all-threads-buffer (slack-buffer)
((current-ts :initarg :current-ts :type string)
(has-more :initarg :has-more :type boolean)
(total-unread-replies :initarg :total-unread-replies :type integer)
(new-threads-count :initarg :new-threads-count :type integer)
(threads :initarg :threads :type list '())))
(cl-defmethod slack-buffer-name ((this slack-all-threads-buffer))
(format "*Slack - %s : All Threads"
(slack-team-name (slack-buffer-team this))))
(cl-defmethod slack-buffer-key ((_class (subclass slack-all-threads-buffer)))
'slack-all-threads-buffer)
(cl-defmethod slack-buffer-key ((_this slack-all-threads-buffer))
(slack-buffer-key 'slack-all-threads-buffer))
(cl-defmethod slack-team-buffer-key ((_class (subclass slack-all-threads-buffer)))
'slack-all-threads-buffer)
(defclass slack-thread-view ()
((root-msg :initarg :root_msg :type slack-message)
(latest-replies :initarg :latest_replies :type list :initform '())
(unread-replies :initarg :unread_replies :type list :initform '())))
(cl-defmethod slack-message-user-ids ((this slack-thread-view))
(let ((ret (slack-message-user-ids (oref this root-msg))))
(cl-loop for m in (oref this latest-replies)
do (cl-loop for id in (slack-message-user-ids m)
do (cl-pushnew id ret :test #'string=)))
(cl-loop for m in (oref this unread-replies)
do (cl-loop for id in (slack-message-user-ids m)
do (cl-pushnew id ret :test #'string=)))
ret))
(cl-defmethod slack-buffer-find-message ((this slack-all-threads-buffer) ts)
(cl-block outer
(cl-loop for thread in (reverse (oref this threads))
do (cl-loop for message in (append (list (oref thread root-msg))
(oref thread latest-replies)
(oref thread unread-replies))
when (string= ts (slack-ts message))
do (cl-return-from outer message)))))
(cl-defmethod slack-buffer--replace ((this slack-all-threads-buffer) ts)
(let ((message (slack-buffer-find-message this ts)))
(when message
(slack-buffer-replace this message))))
(defun slack-create-thread-view (payload team)
(let ((room (slack-room-find (plist-get (plist-get payload :root_msg)
:channel)
team)))
(make-instance 'slack-thread-view
:root_msg (slack-message-create (plist-get payload :root_msg) team room)
:latest_replies (mapcar #'(lambda (e) (slack-message-create e team room))
(plist-get payload :latest_replies))
:unread_replies (mapcar #'(lambda (e) (slack-message-create e team room))
(plist-get payload :unread_replies)))))
(defun slack-create-all-threads-buffer (team total-unread-replies new-threads-count threads has-more)
(slack-if-let* ((buf (slack-buffer-find 'slack-all-threads-buffer team)))
buf
(slack-all-threads-buffer :team-id (oref team id)
:total-unread-replies total-unread-replies
:new-threads-count new-threads-count
:threads threads
:has-more has-more)))
(cl-defmethod slack-buffer-init-buffer ((this slack-all-threads-buffer))
(let* ((buf (cl-call-next-method)))
(with-current-buffer buf
(let ((inhibit-read-only t))
(delete-region (point-min) (point-max)))
(slack-all-threads-buffer-mode)
(slack-buffer-set-current-buffer this)
(goto-char lui-input-marker)
(let ((lui-time-stamp-position nil))
(lui-insert (propertize "All Threads\n"
'face '(:weight bold))
t))
(with-slots (threads current-ts) this
(cl-loop for thread in threads
do (slack-buffer-insert-thread this thread)))
(when (slack-buffer-has-next-page-p this)
(slack-buffer-insert-load-more this))
(goto-char (point-min)))
(slack-subscriptions-thread-clear-all (slack-buffer-team this))
buf))
(cl-defmethod slack-buffer-insert-thread ((this slack-all-threads-buffer) thread)
(with-slots (root-msg latest-replies unread-replies) thread
(oset this current-ts (oref root-msg last-read))
(let* ((lui-time-stamp-position nil)
(team (slack-buffer-team this))
(channel (oref root-msg channel))
(room (slack-room-find channel team))
(prefix (or (and (slack-im-p room) "@") "#")))
(lui-insert (format "%s\n"
(make-string lui-fill-column ?=))
t)
(lui-insert (propertize (format "%s%s"
prefix
(slack-room-name room team))
'face
'slack-all-thread-buffer-thread-header-face)
t))
(slack-buffer-insert this root-msg t)
(cl-loop for reply in latest-replies
do (slack-buffer-insert this reply t))
(cl-loop for reply in unread-replies
do (slack-buffer-insert this reply t))))
(cl-defmethod slack-buffer-has-next-page-p ((this slack-all-threads-buffer))
(oref this has-more))
(cl-defmethod slack-buffer-delete-load-more-string ((_this slack-all-threads-buffer))
(slack-if-let*
((beg (next-single-property-change (point-min)
'loading-message))
(end (next-single-property-change beg
'loading-message)))
(delete-region beg end)))
(cl-defmethod slack-buffer-prepare-marker-for-history ((_this slack-all-threads-buffer)))
(cl-defmethod slack-buffer-insert-history ((this slack-all-threads-buffer))
(with-slots (threads current-ts) this
(cl-loop for thread in (cl-remove-if #'(lambda (e)
(not (string< (oref (oref e root-msg)
last-read)
current-ts)))
threads)
do (slack-buffer-insert-thread this thread))))
(cl-defmethod slack-buffer-insert--history ((this slack-all-threads-buffer))
(slack-buffer-insert-history this)
(when (slack-buffer-has-next-page-p this)
(slack-buffer-insert-load-more this)))
(cl-defmethod slack-buffer-request-history ((this slack-all-threads-buffer) after-success)
(let ((cur-point (point)))
(with-slots (current-ts) this
(cl-labels
((success (total-unread-replies new-threads-count threads has-more)
(oset this total-unread-replies total-unread-replies)
(oset this new-threads-count new-threads-count)
(oset this threads (append (oref this threads) threads))
(oset this has-more has-more)
(funcall after-success)
(when (and (< (point-min) cur-point)
(< cur-point (point-max)))
(goto-char cur-point))))
(slack-subscriptions-thread-get-view (slack-buffer-team this) current-ts #'success)))))
(cl-defmethod slack-buffer-display-thread ((this slack-all-threads-buffer) ts)
(with-slots (threads) this
(slack-if-let* ((thread (cl-find-if #'(lambda (e) (string= ts (slack-ts (oref e root-msg))))
threads))
(root (oref thread root-msg))
(room-id (oref root channel))
(team (slack-buffer-team this))
(room (slack-room-find room-id team)))
(cl-labels
((display-thread (message)
(slack-thread-show-messages message
room
team)))
(slack-if-let* ((ts (slack-ts root))
(message (slack-room-find-message room ts)))
(display-thread message)
(cl-labels
((success (messages _next-cursor)
(slack-room-set-messages room messages team)
(let ((message (slack-room-find-message room (slack-ts root))))
(display-thread message))))
(slack-conversations-history room team
:oldest (slack-ts root)
:inclusive "true"
:limit "1"
:after-success #'success)))))))
(defun slack-all-threads ()
(interactive)
(let ((team (slack-team-select)))
(cl-labels
((open-buffer (total-unread-replies new-threads-count threads has-more)
(slack-buffer-display
(slack-create-all-threads-buffer team
total-unread-replies
new-threads-count
threads
has-more)))
(success (&rest args)
(slack-if-let* ((buf (slack-buffer-find 'slack-all-threads-buffer team)))
(progn
(kill-buffer (slack-buffer-buffer buf))
(apply #'open-buffer args))
(apply #'open-buffer args))))
(slack-subscriptions-thread-get-view team nil #'success))))
(defun slack-subscriptions-thread-clear-all (team)
(let ((current-ts (substring
(number-to-string (time-to-seconds (current-time)))
0 15)))
(cl-labels
((success (&key data &allow-other-keys)
(slack-request-handle-error
(data "slack-subscriptions-thread-clear-all"))))
(slack-request
(slack-request-create
slack-subscriptions-thread-clear-all-url
team
:type "POST"
:params (list (cons "current_ts" current-ts))
:success #'success)))))
(defun slack-subscriptions-thread-get-view (team &optional current-ts after-success)
(let ((current-ts (or current-ts
(substring
(number-to-string (time-to-seconds (current-time)))
0 15))))
(cl-labels
((callback (total-unread-replies
new-threads-count
threads
has-more)
(when (functionp after-success)
(funcall after-success
total-unread-replies
new-threads-count
threads
has-more)))
(success (&key data &allow-other-keys)
(slack-request-handle-error
(data "slack-subscriptions-thread-get-view")
(let* ((total-unread-replies (plist-get data :total_unread_replies))
(new-threads-count (plist-get data :new_threads_count))
(threads (mapcar #'(lambda (e) (slack-create-thread-view e team))
(plist-get data :threads)))
(has-more (eq (plist-get data :has_more) t))
(user-ids (slack-team-missing-user-ids
team (cl-loop for thread in threads
nconc (slack-message-user-ids thread)))))
(if (< 0 (length user-ids))
(slack-users-info-request
user-ids team :after-success
#'(lambda () (callback total-unread-replies
new-threads-count
threads
has-more)))
(callback total-unread-replies
new-threads-count
threads
has-more))))))
(slack-request
(slack-request-create
slack-subscriptions-thread-get-view-url
team
:type "POST"
:params (list (cons "current_ts" current-ts))
:success #'success)))))
(provide 'slack-all-threads-buffer)
;;; slack-all-threads-buffer.el ends here