;;; pivot.el --- Elisp library for the Pivotal Tracker API -*- lexical-binding: t; -*- ;; Copyright (C) 2014 Tom Willemse ;; Author: Tom Willemse ;; Keywords: comm, hypermedia ;; 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 . ;;; Commentary: ;; ;;; Code: (require 'json) (require 'url) (defgroup pivotel nil "Communicate with Pivotal Tracker." :group 'external) (defcustom pivotel-api-token nil "API token from Pivotal Tracker. From Pivotal Tracker: Your token enables access to your project and story data via the API, and needs to be kept private." :group 'pivotel) (defvar pivotel-api-url "https://www.pivotaltracker.com/services/v5" "Base URL of the Pivotal Tracker API. Does not need a final `/'.") (defvar pivotel-user-id nil "The user id of the current user.") (defvar pivotel-projects nil "The projects from the current user.") (defmacro with-pivotel-headers (headers &rest body) "Add `X-TrackerTocken' to HEADERS and bind them around BODY." (declare (indent 1)) `(let ((url-request-extra-headers (append (list (cons "X-TrackerToken" pivotel-api-token)) ,headers))) ,@body)) (defun pivotel--retrieve-from (url) "Retrieve data from URL." (with-current-buffer (url-retrieve-synchronously (concat pivotel-api-url url)) (goto-char (point-min)) (search-forward "\n\n") (let ((results (json-read))) (kill-buffer) results))) (defun pivotel-get-story (project story) "Get data from PROJECT for STORY." (with-pivotel-headers nil (pivotel--retrieve-from (format "/projects/%d/stories/%d" project story)))) (defun pivotel-get-projects () "Get a list of all projects." (or pivotel-projects (setq pivotel-projects (with-pivotel-headers nil (pivotel--retrieve-from "/projects"))))) (defun pivotel-get-stories (project) "Get a list of all stories in PROJECT." (with-pivotel-headers nil (pivotel--retrieve-from (format "/projects/%d/stories" project)))) (defun pivotel-get-me () "Get information about currently logged-in user." (with-pivotel-headers nil (pivotel--retrieve-from "/me"))) (defun pivotel-get-me-id () "Get and cache the current user's id." (or pivotel-user-id (setq pivotel-user-id (cdr (assoc 'id (pivotel-get-me)))))) (defun pivotel-get-all-stories () "Get all stories for the current user." (let ((project-ids (mapcar (lambda (itm) (cdr (assoc 'id itm))) (pivotel-get-projects)))) (apply #'append (append (mapcar #'pivotel-get-stories project-ids) '(nil))))) (defun pivotel--my-story-p (story) "Check whether or not STORY belongs to the current user." (memql (pivotel-get-me-id) (append (cdr (assoc 'owner_ids story)) '(nil)))) (defun pivotel-get-my-owned-stories () "Get the stories for which the user is an owner." (let ((stories (pivotel-get-all-stories))) (delq nil (mapcar (lambda (itm) (when (pivotel--my-story-p itm) itm)) stories)))) (provide 'pivot) ;;; pivot.el ends here