my-emacs-d/elpa/slack-20160928.2036/slack-file.el

245 lines
9.8 KiB
EmacsLisp

;;; slack-file.el --- handle files -*- lexical-binding: t; -*-
;; Copyright (C) 2016 南優也
;; Author: 南優也 <yuyaminami@minamiyuunari-no-MacBook-Pro.local>
;; 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 <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
(require 'eieio)
(require 'slack-room)
(defconst slack-file-list-url "https://slack.com/api/files.list")
(defconst slack-file-upload-url "https://slack.com/api/files.upload")
(defconst slack-file-delete-url "https://slack.com/api/files.delete")
(defclass slack-file (slack-message)
((id :initarg :id)
(created :initarg :created)
(name :initarg :name)
(size :initarg :size)
(public :initarg :public)
(filetype :initarg :filetype)
(user :initarg :user)
(preview :initarg :preview)
(initial-comment :initarg :initial_comment :initform nil)
(permalink :initarg :permalink)
(channels :initarg :channels :type list)
(groups :initarg :groups :type list)
(ims :initarg :ims :type list)
(username :initarg :username)))
(defclass slack-file-room (slack-room) ())
(defun slack-file-room-obj (team)
(with-slots (file-room) team
(if file-room
file-room
(setq file-room (slack-file-room "file-room"
:name "Files"
:id "F"
:team-id (oref team id)
:created (format-time-string "%s")
:last_read "0"
:latest nil
:unread_count 0
:unread_count_display 0
:messages '())))))
(defun slack-file-create (payload)
(plist-put payload :channels (append (plist-get payload :channels) nil))
(plist-put payload :groups (append (plist-get payload :groups) nil))
(plist-put payload :ims (append (plist-get payload :ims) nil))
(plist-put payload :reactions (append (plist-get payload :reactions) nil))
(plist-put payload :pinned_to (append (plist-get payload :pinned_to) nil))
(plist-put payload :ts (number-to-string (plist-get payload :timestamp)))
(let ((file (apply #'slack-file "file"
(slack-collect-slots 'slack-file payload))))
(oset file reactions
(mapcar #'slack-reaction-create (plist-get payload :reactions)))
file))
(defmethod slack-message-equal ((f slack-file) other)
(string= (oref f id) (oref other id)))
(defmethod slack-file-pushnew ((f slack-file) team)
(let ((room (slack-file-room-obj team)))
(with-slots (messages) room
(cl-pushnew f messages
:test #'slack-message-equal))))
(defmethod slack-message-body ((file slack-file) team)
(with-slots (initial-comment) file
(let ((body (plist-get initial-comment :comment)))
(slack-message-unescape-string body team))))
(defmethod slack-message-to-string ((file slack-file) team)
(with-slots (ts name size filetype permalink user initial-comment reactions)
file
(let* ((header (slack-user-name user team))
(body (format "name: %s\nsize: %s\ntype: %s\n%s\n"
name size filetype permalink))
(reactions-str (slack-message-reactions-to-string
reactions)))
(slack-message-put-header-property header)
(slack-message-put-text-property body)
(slack-message-put-reactions-property reactions-str)
(let ((message
(concat header "\n" body
(if initial-comment
(format "comment: %s\n%s\n"
(slack-user-name
(plist-get initial-comment :user)
team)
(slack-message-body file team)))
(if reactions-str
(concat "\n" reactions-str "\n")))))
(put-text-property 0 (length message) 'ts ts message)
message))))
(defmethod slack-room-update-mark ((_room slack-file-room) _team _msg))
(defun slack-file-create-buffer (team)
(funcall slack-buffer-function
(slack-buffer-create (slack-file-room-obj team)
team
:type 'info)))
(defun slack-file-list ()
(interactive)
(let* ((team (slack-team-select))
(room (slack-file-room-obj team)))
(with-slots (messages) room
(if messages
(slack-file-create-buffer team)
(slack-room-history room team nil
#'(lambda ()
(slack-file-create-buffer team)))))))
(defmethod slack-room-history ((room slack-file-room) team
&optional
oldest
after-success
async)
(cl-labels
((on-file-list
(&key data &allow-other-keys)
(slack-request-handle-error
(data "slack-file-list")
(let ((files (cl-loop for e across (plist-get data :files)
collect (slack-file-create e))))
(if oldest
(slack-room-set-prev-messages room files)
(slack-room-update-last-read room
(make-instance 'slack-message
:ts "0"))
(slack-room-set-messages room files)))
(if after-success
(funcall after-success)))))
(slack-request
slack-file-list-url
team
:params (list (if oldest
(cons "ts_to" oldest)))
:success #'on-file-list
:sync (if async nil t))))
(defun slack-file-upload ()
(interactive)
(cl-labels
((on-file-upload (&key data &allow-other-keys)
(slack-request-handle-error
(data "slack-file-upload")))
(select-channels (channels acc)
(let ((selected (completing-read "Select Channel: "
channels nil t)))
(if (< 0 (length selected))
(select-channels channels (push selected acc))
acc)))
(channel-id (selected channels)
(oref (cdr (cl-assoc selected channels :test #'string=))
id)))
(let* ((team (slack-team-select))
(channels (slack-room-names
(append (oref team ims)
(oref team channels)
(oref team groups))))
(target-channels (select-channels channels '()))
(channel-ids (mapconcat #'(lambda (selected)
(channel-id selected channels))
(cl-delete-if #'null target-channels)
","))
(buf (find-file-noselect
(car (find-file-read-args
"Select File: "
(confirm-nonexistent-file-or-buffer)))))
(filename (read-from-minibuffer "Filename: "
(file-name-nondirectory
(buffer-file-name buf))))
(filetype (read-from-minibuffer "Filetype: "
(file-name-extension
(buffer-file-name buf))))
(initial-comment (read-from-minibuffer "Message: ")))
(slack-request
slack-file-upload-url
team
:type "POST"
:params (list (cons "filename" filename)
(cons "channels" channel-ids)
(cons "filetype" filetype)
(if initial-comment
(cons "initial_comment" initial-comment)))
:files (list (cons "file" buf))
:headers (list (cons "Content-Type" "multipart/form-data"))
:success #'on-file-upload
:sync nil))))
(defun slack-file-delete ()
(interactive)
(cl-labels
((on-file-delete (&key data &allow-other-keys)
(slack-request-handle-error
(data "slack-file-delete"))))
(let* ((team (slack-team-select))
(files (oref (slack-file-room-obj team) messages))
(your-files (cl-remove-if #'(lambda (f)
(not (string= (oref f user)
(oref team self-id))))
files))
(candidates (mapcar #'(lambda (f)
(cons (concat
(slack-message-time-to-string (oref f ts))
" "
(oref f name))
f))
your-files))
(selected (completing-read "Select File: " candidates))
(deleting-file (cdr (cl-assoc selected candidates :test #'string=))))
(slack-request
slack-file-delete-url
team
:params (list (cons "file" (oref deleting-file id)))
:sync nil
:success #'on-file-delete))))
(provide 'slack-file)
;;; slack-file.el ends here