diff options
-rw-r--r-- | lisp/mastodon-notifications.el | 133 | ||||
-rw-r--r-- | lisp/mastodon-tl.el | 11 | ||||
-rw-r--r-- | lisp/mastodon.el | 1 | ||||
-rw-r--r-- | test/ert-helper.el | 2 | ||||
-rw-r--r-- | test/mastodon-notifications-test.el | 213 |
5 files changed, 355 insertions, 5 deletions
diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el new file mode 100644 index 0000000..ddaaaf4 --- /dev/null +++ b/lisp/mastodon-notifications.el @@ -0,0 +1,133 @@ +;;; mastodon-notifications.el --- Notification functions for mastodon.el -*- lexical-binding: t -*- + +;; Copyright (C) 2017 Johnson Denen +;; Author: Johnson Denen <johnson.denen@gmail.com> +;; Version: 0.7.2 +;; Homepage: https://github.com/jdenen/mastodon.el +;; Package-Requires: ((emacs "24.4")) + +;; This file is not part of GNU Emacs. + +;; This file is part of mastodon.el. + +;; mastodon.el 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. + +;; mastodon.el 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 mastodon.el. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; mastodon-notification.el provides notification functions for Mastodon. + +;;; Code: + +(defvar mastodon-notifications--types-alist + '(("mention" . mastodon-notifications--mention) + ("follow" . mastodon-notifications--follow) + ("favourite" . mastodon-notifications--favourite) + ("reblog" . mastodon-notifications--reblog)) + "Alist of notification types and their corresponding function.") + +(defvar mastodon-notifications--response-alist + '(("Mentioned" . "you") + ("Followed" . "you") + ("Favourited" . "your status") + ("Boosted" . "your status")) + "Alist of subjects for notification types.") + +(defun mastodon-notifications--byline-concat (message) + "Add byline for TOOT with MESSAGE." + (concat + " " + (propertize message 'face 'highlight) + " " + (cdr (assoc message mastodon-notifications--response-alist)))) + +(defun mastodon-notifications--mention (note) + "Format for a `mention' NOTE." + (let ((status (mastodon-tl--field 'status note))) + (mastodon-tl--insert-status + note + (mastodon-tl--clean-tabs-and-nl + (if (mastodon-tl--has-spoiler status) + (mastodon-tl--spoiler status) + (mastodon-tl--content status))) + 'mastodon-tl--byline-author + (lambda (_status) + (mastodon-notifications--byline-concat + "Mentioned"))))) + +(defun mastodon-notifications--follow (note) + "Format for a `follow' NOTE." + (mastodon-tl--insert-status + note + (propertize "Congratulations, you have a new follower!" + 'face 'default) + 'mastodon-tl--byline-author + (lambda (_status) + (mastodon-notifications--byline-concat + "Followed")))) + +(defun mastodon-notifications--favourite (note) + "Format for a `favourite' NOTE." + (let ((status (mastodon-tl--field 'status note))) + (mastodon-tl--insert-status + note + (mastodon-tl--clean-tabs-and-nl + (if (mastodon-tl--has-spoiler status) + (mastodon-tl--spoiler status) + (mastodon-tl--content status))) + (lambda (_status) + (mastodon-tl--byline-author + note)) + (lambda (_status) + (mastodon-notifications--byline-concat + "Favourited"))))) + +(defun mastodon-notifications--reblog (note) + "Format for a `boost' NOTE." + (let ((status (mastodon-tl--field 'status note))) + (mastodon-tl--insert-status + note + (mastodon-tl--clean-tabs-and-nl + (if (mastodon-tl--has-spoiler status) + (mastodon-tl--spoiler status) + (mastodon-tl--content status))) + (lambda (_status) + (mastodon-tl--byline-author + note)) + (lambda (_status) + (mastodon-notifications--byline-concat + "Boosted"))))) + +(defun mastodon-notifications--by-type (note) + "Filters NOTE for those listed in `mastodon-notifications--types-alist'." + (let* ((type (mastodon-tl--field 'type note)) + (fun (cdr (assoc type mastodon-notifications--types-alist)))) + (when fun (funcall fun note)))) + +(defun mastodon-notifications--timeline (json) + "Format JSON in Emacs buffer." + (mapc #'mastodon-notifications--by-type json) + (goto-char (point-min)) + (when mastodon-tl--display-media-p + (mastodon-media--inline-images))) + +(defun mastodon-notifications--get () + "Display NOTIFICATIONS in buffer." + (interactive) + (mastodon-tl--init + "*mastodon-notifications*" + "notifications" + 'mastodon-notifications--timeline)) + +(provide 'mastodon-notifications) +;;; mastodon-notifications.el ends here diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index de65344..b873991 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -507,6 +507,10 @@ LINK-TYPE is the type of link to produce." (let ((spoiler (mastodon-tl--field 'spoiler_text toot))) (and spoiler (> (length spoiler) 0)))) +(defun mastodon-tl--clean-tabs-and-nl (string) + (replace-regexp-in-string + "[\t\n ]*\\'" "" string)) + (defun mastodon-tl--spoiler (toot) "Render TOOT with spoiler message. @@ -517,8 +521,8 @@ message is a link which unhides/hides the main body." (let* ((spoiler (mastodon-tl--field 'spoiler_text toot)) (string (mastodon-tl--set-face ;; remove trailing whitespace - (replace-regexp-in-string "[\t\n ]*\\'" "" - (mastodon-tl--render-text spoiler toot)) + (mastodon-tl--clean-tabs-and-nl + (mastodon-tl--render-text spoiler toot)) 'default)) (message (concat "\n" " ---------------\n" @@ -580,8 +584,7 @@ it is `mastodon-tl--byline-boosted'" "Formats TOOT and insertes it into the buffer." (mastodon-tl--insert-status toot - (replace-regexp-in-string - "[\t\n ]*\\'" "" + (mastodon-tl--clean-tabs-and-nl (if (mastodon-tl--has-spoiler toot) (mastodon-tl--spoiler toot) (mastodon-tl--content toot))) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index c362513..16bb43f 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -140,6 +140,7 @@ If REPLY-TO-ID is non-nil, attach new toot to a conversation." (define-key map [backtab] #'mastodon-tl--previous-tab-item) (define-key map [?\S-\t] #'mastodon-tl--previous-tab-item) (define-key map [?\M-\t] #'mastodon-tl--previous-tab-item) + (define-key map (kbd "N") #'mastodon-notifications--get) )) (with-eval-after-load 'mastodon diff --git a/test/ert-helper.el b/test/ert-helper.el index 2df46d3..6979837 100644 --- a/test/ert-helper.el +++ b/test/ert-helper.el @@ -4,5 +4,5 @@ (load-file "lisp/mastodon-toot.el") (load-file "lisp/mastodon-media.el") (load-file "lisp/mastodon-tl.el") +(load-file "lisp/mastodon-notifications.el") (load-file "lisp/mastodon.el") - diff --git a/test/mastodon-notifications-test.el b/test/mastodon-notifications-test.el new file mode 100644 index 0000000..9758123 --- /dev/null +++ b/test/mastodon-notifications-test.el @@ -0,0 +1,213 @@ +(require 'cl-lib) +(require 'cl-macs) +(require 'el-mock) + +(defconst mastodon-notifications-test-base-mentioned + '((id . "1234") + (type . "mention") + (created_at . "2018-03-06T04:27:21.288Z" ) + (account (id . 42) + (username . "acct42") + (acct . "acct42@example.space") + (display_name . "Account 42") + (locked . :json-false) + (created_at . "2017-04-01T00:00:00.000Z") + (followers_count . 99) + (following_count . 13) + (statuses_count . 101) + (note . "E")) + (status (id . 61208) + (created_at . "2017-04-24T19:01:02.000Z") + (in_reply_to_id) + (in_reply_to_account_id) + (sensitive . :json-false) + (spoiler_text . "") + (visibility . "public") + (account (id . 42) + (username . "acct42") + (acct . "acct42@example.space") + (display_name . "Account 42") + (locked . :json-false) + (created_at . "2017-04-01T00:00:00.000Z") + (followers_count . 99) + (following_count . 13) + (statuses_count . 101) + (note . "E")) + (media_attachments . []) + (mentions . []) + (tags . []) + (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") + (url . "https://example.space/users/acct42/updates/123456789") + (content . "<p>Just some text</p>") + (reblogs_count . 0) + (favourites_count . 0) + (reblog)))) + +(defconst mastodon-notifications-test-base-favourite + '((id . "1234") + (type . "favourite") + (created_at . "2018-03-06T04:27:21.288Z" ) + (account (id . 42) + (username . "acct42") + (acct . "acct42@example.space") + (display_name . "Account 42") + (locked . :json-false) + (created_at . "2017-04-01T00:00:00.000Z") + (followers_count . 99) + (following_count . 13) + (statuses_count . 101) + (note . "E")) + (status (id . 61208) + (created_at . "2017-04-24T19:01:02.000Z") + (in_reply_to_id) + (in_reply_to_account_id) + (sensitive . :json-false) + (spoiler_text . "") + (visibility . "public") + (account (id . 42) + (username . "acct42") + (acct . "acct42@example.space") + (display_name . "Account 42") + (locked . :json-false) + (created_at . "2017-04-01T00:00:00.000Z") + (followers_count . 99) + (following_count . 13) + (statuses_count . 101) + (note . "E")) + (media_attachments . []) + (mentions . []) + (tags . []) + (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") + (url . "https://example.space/users/acct42/updates/123456789") + (content . "<p>Just some text</p>") + (reblogs_count . 0) + (favourites_count . 0) + (reblog)))) + +(defconst mastodon-notifications-test-base-boosted + '((id . "1234") + (type . "reblog") + (created_at . "2018-03-06T04:27:21.288Z" ) + (account (id . 42) + (username . "acct42") + (acct . "acct42@example.space") + (display_name . "Account 42") + (locked . :json-false) + (created_at . "2017-04-01T00:00:00.000Z") + (followers_count . 99) + (following_count . 13) + (statuses_count . 101) + (note . "E")) + (status (id . 61208) + (created_at . "2017-04-24T19:01:02.000Z") + (in_reply_to_id) + (in_reply_to_account_id) + (sensitive . :json-false) + (spoiler_text . "") + (visibility . "public") + (account (id . 42) + (username . "acct42") + (acct . "acct42@example.space") + (display_name . "Account 42") + (locked . :json-false) + (created_at . "2017-04-01T00:00:00.000Z") + (followers_count . 99) + (following_count . 13) + (statuses_count . 101) + (note . "E")) + (media_attachments . []) + (mentions . []) + (tags . []) + (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") + (url . "https://example.space/users/acct42/updates/123456789") + (content . "<p>Just some text</p>") + (reblogs_count . 0) + (favourites_count . 0) + (reblog)))) + +(defconst mastodon-notifications-test-base-followed + '((id . "1234") + (type . "follow") + (created_at . "2018-03-06T04:27:21.288Z" ) + (account (id . 42) + (username . "acct42") + (acct . "acct42@example.space") + (display_name . "Account 42") + (locked . :json-false) + (created_at . "2017-04-01T00:00:00.000Z") + (followers_count . 99) + (following_count . 13) + (statuses_count . 101) + (note . "E")) + (status (id . 61208) + (created_at . "2017-04-24T19:01:02.000Z") + (in_reply_to_id) + (in_reply_to_account_id) + (sensitive . :json-false) + (spoiler_text . "") + (visibility . "public") + (account (id . 42) + (username . "acct42") + (acct . "acct42@example.space") + (display_name . "Account 42") + (locked . :json-false) + (created_at . "2017-04-01T00:00:00.000Z") + (followers_count . 99) + (following_count . 13) + (statuses_count . 101) + (note . "E")) + (media_attachments . []) + (mentions . []) + (tags . []) + (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") + (url . "https://example.space/users/acct42/updates/123456789") + (content . "<p>Just some text</p>") + (reblogs_count . 0) + (favourites_count . 0) + (reblog)))) + +(defconst mastodon-notifications-test-base-favourite + '((id . "1234") + (type . "mention") + (created_at . "2018-03-06T04:27:21.288Z" ) + (account (id . 42) + (username . "acct42") + (acct . "acct42@example.space") + (display_name . "Account 42") + (locked . :json-false) + (created_at . "2017-04-01T00:00:00.000Z") + (followers_count . 99) + (following_count . 13) + (statuses_count . 101) + (note . "E")))) + +(ert-deftest notification-get () + "Ensure get request format for notifictions is accurate." + (let ((mastodon-instance-url "https://instance.url")) + (with-mock + (mock (mastodon-http--get-json "https://instance.url/api/v1/notifications")) + (mastodon-notifications--get)))) + +(defun mastodon-notifications--test-type (fun sample) + "Test notification draw functions. + +FUN is the notificiation function to be called and SAMPLE is the +notification to be tested." + (let ((mastodon-tl--show-avatars-p nil) + (timestamp (cdr (assoc 'created_at sample)))) + (with-temp-buffer (funcall fun sample) + (buffer-substring-no-properties (point-min) (point-max))))) + +(ert-deftest mastodon-notifications--test-byline-concat () + "Ensure proper suffix is appended to action." + (should (and + (string= " Mentioned you" + (mastodon-notifications--byline-concat "Mentioned")) + (string= " Followed you" + (mastodon-notifications--byline-concat "Followed")) + (string= " Favourited your status" + (mastodon-notifications--byline-concat "Favourited")) + (string= " Boosted your status" + (mastodon-notifications--byline-concat "Boosted"))))) + + |