From e9dd14192f0e9f1e2367b378b937c2b2f042ffa1 Mon Sep 17 00:00:00 2001 From: Johnson Denen Date: Fri, 21 Apr 2017 22:55:34 -0400 Subject: Add mastodon-client feature --- lisp/mastodon-client.el | 95 +++++++++++++++++++++++++++++++++++++++++++ test/mastodon-client-tests.el | 76 ++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 lisp/mastodon-client.el create mode 100644 test/mastodon-client-tests.el diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el new file mode 100644 index 0000000..25f303f --- /dev/null +++ b/lisp/mastodon-client.el @@ -0,0 +1,95 @@ +;;; mastodon-client.el --- Client functions for mastodon.el + +;; Copyright (C) 2017 Johnson Denen +;; Author: Johnson Denen +;; Homepage: https://github.com/jdenen/mastodon.el + +;; 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 . + +;;; Commentary: + +;; mastodon-client.el supports registering the Emacs client with your Mastodon instance. + +;;; Code: + +(require 'plstore) +(require 'mastodon-http) + +(defgroup mastodon-client nil + "Register your client with Mastodon." + :prefix "mastodon-client-" + :group 'mastodon) + +(defvar mastodon-client nil + "Client id and secret.") + +(defun mastodon-client--register () + "POST client to Mastodon." + (mastodon-http--post + (mastodon--api-for "apps") + '(("client_name" . "mastodon.el") + ("redirect_uris" . "urn:ietf:wg:oauth:2.0:oob") + ("scopes" . "read write follow") + ("website" . "https://github.com/jdenen/mastodon.el")) + nil)) + +(defun mastodon-client--fetch () + "Return JSON from `mastodon-client--register' call." + (with-current-buffer (mastodon-client--register) + (goto-char (point-min)) + (re-search-forward "^$" nil 'move) + (let ((json-object-type 'plist) + (json-key-type 'keyword) + (json-array-type 'vector) + (json-string (buffer-substring-no-properties (point) (point-max)))) + (json-read-from-string json-string)))) + +(defun mastodon-client--token-file () + "Return `mastodon-token-file'." + mastodon-token-file) + +(defun mastodon-client--store () + "Store client_id and client_secret in `mastodon-token-file'. + +Make `mastodon-client--fetch' call to determine client values." + (let ((plstore (plstore-open (mastodon-client--token-file))) + (client (mastodon-client--fetch))) + (plstore-put plstore "mastodon" client nil) + (plstore-save plstore) + (plstore-close plstore) + client)) + +(defun mastodon-client--read () + "Retrieve client_id and client_secret from `mastodon-token-file'." + (let* ((plstore (plstore-open (mastodon-client--token-file))) + (mastodon (plstore-get plstore "mastodon"))) + (when mastodon + (delete "mastodon" mastodon)))) + +(defun mastodon-client () + "Return `mastodon-client' plist. + +Read plist from `mastodon-token-file' if `mastodon-client' is nil. +Fetch and store plist if `mastodon-client--read' returns nil." + (or mastodon-client + (setq mastodon-client + (or (mastodon-client--read) + (mastodon-client--store))))) + +(provide 'mastodon-client) +;;; mastodon-client.el ends here diff --git a/test/mastodon-client-tests.el b/test/mastodon-client-tests.el new file mode 100644 index 0000000..2a58b84 --- /dev/null +++ b/test/mastodon-client-tests.el @@ -0,0 +1,76 @@ +(require 'el-mock) +(load-file "../lisp/mastodon-client.el") + +(ert-deftest register () + "Should POST to /apps." + (with-mock + (mock (mastodon--api-for "apps") => "https://instance.url/api/v1/apps") + (mock (mastodon-http--post "https://instance.url/api/v1/apps" + '(("client_name" . "mastodon.el") + ("redirect_uris" . "urn:ietf:wg:oauth:2.0:oob") + ("scopes" . "read write follow") + ("website" . "https://github.com/jdenen/mastodon.el")) + nil)) + (mastodon-client--register))) + +(ert-deftest fetch () + "Should return client registration JSON." + (with-temp-buffer + (with-mock + (mock (mastodon-client--register) => (progn + (insert "\n\n{\"foo\":\"bar\"}") + (current-buffer))) + (should (equal (mastodon-client--fetch) '(:foo "bar")))))) + +(ert-deftest store-1 () + "Should return the client plist." + (let ((plist '(:client_id "id" :client_secret "secret"))) + (with-mock + (mock (mastodon-client--token-file) => "stubfile.plstore") + (mock (mastodon-client--fetch) => '(:client_id "id" :client_secret "secret")) + (let* ((plstore (plstore-open "stubfile.plstore")) + (client (delete "mastodon" (plstore-get plstore "mastodon")))) + (should (equal (mastodon-client--store) plist)) + )))) + +(ert-deftest store-2 () + "Should store client in `mastodon-client--token-file'." + (let* ((plstore (plstore-open "stubfile.plstore")) + (client (delete "mastodon" (plstore-get plstore "mastodon")))) + (plstore-close plstore) + (should (string= (plist-get client :client_id) "id")) + (should (string= (plist-get client :client_secret) "secret")))) + +(ert-deftest read-1 () + "Should return mastodon client from `mastodon-token-file' if it exists." + (with-mock + (mock (mastodon-client--token-file) => "fixture/client.plstore") + (should (equal (mastodon-client--read) '(:client_id "id" :client_secret "secret"))))) + +(ert-deftest read-2 () + "Should return nil if mastodon client is not present in the plstore." + (with-mock + (mock (mastodon-client--token-file) => "fixture/empty.plstore") + (should (equal (mastodon-client--read) nil)))) + +(ert-deftest client-1 () + "Should return `mastondon-client' if non-nil." + (let ((mastodon-client t)) + (should (eq (mastodon-client) t)))) + +(ert-deftest client-2 () + "Should read from `mastodon-token-file' if available." + (let ((mastodon-client nil)) + (with-mock + (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) + (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) + (should (equal mastodon-client '(:client_id "foo" :client_secret "bar")))))) + +(ert-deftest client-3 () + "Should store client data in plstore if it can't be read." + (let ((mastodon-client nil)) + (with-mock + (mock (mastodon-client--read)) + (mock (mastodon-client--store) => '(:client_id "foo" :client_secret "baz")) + (should (equal (mastodon-client) '(:client_id "foo" :client_secret "baz"))) + (should (equal mastodon-client '(:client_id "foo" :client_secret "baz")))))) -- cgit v1.2.3