Browse Source

Rename libbasecampel to libbcel

That we way follow the branding guidelines:
https://github.com/basecamp/api/blob/master/sections/brand_guidelines.md.
tags/v0.3.0
Damien Cassou 6 months ago
parent
commit
75b53f4944
Signed by: DamienCassou <damien@cassou.me> GPG Key ID: B68746238E59B548
4 changed files with 159 additions and 159 deletions
  1. +10
    -10
      README.org
  2. +11
    -11
      libbcel-client.el
  3. +43
    -43
      libbcel-oauth.el
  4. +95
    -95
      libbcel.el

+ 10
- 10
README.org View File

@@ -1,17 +1,17 @@
* libbasecampel
* libbcel

#+BEGIN_HTML
<p>
<a href="https://stable.melpa.org/#/libbasecampel">
<img alt="MELPA Stable" src="https://stable.melpa.org/packages/libbasecampel-badge.svg"/>
<a href="https://stable.melpa.org/#/libbcel">
<img alt="MELPA Stable" src="https://stable.melpa.org/packages/libbcel-badge.svg"/>
</a>

<a href="https://melpa.org/#/libbasecampel">
<img alt="MELPA" src="https://melpa.org/packages/libbasecampel-badge.svg"/>
<a href="https://melpa.org/#/libbcel">
<img alt="MELPA" src="https://melpa.org/packages/libbcel-badge.svg"/>
</a>

<a href="https://gitlab.petton.fr/basecampel/libbasecampel/commits/master">
<img alt="pipeline status" src="https://gitlab.petton.fr/basecampel/libbasecampel/badges/master/pipeline.svg" />
<a href="https://gitlab.petton.fr/bcel/libbcel/commits/master">
<img alt="pipeline status" src="https://gitlab.petton.fr/bcel/libbcel/badges/master/pipeline.svg" />
</a>
</p>
#+END_HTML
@@ -19,12 +19,12 @@

** Summary

The package libbasecampel is an Emacs library to interact with
The package libbcel is an Emacs library to interact with
[[https://basecamp.com][Basecamp]], a project management web application.

** Authentication

To make libbasecampel work, you first have to give it access to your
To make libbcel work, you first have to give it access to your
Basecamp account. This is done through OAUTH2. If you already have a
client id and secret, skip the next section. Otherwise, keep reading.

@@ -57,4 +57,4 @@ See [[file:COPYING][COPYING]]. Copyright (c) 2019 Damien Cassou.
</a>
#+END_HTML

# LocalWords: Basecampel MPD minibuffer
# LocalWords: Bcel MPD minibuffer

libbasecampel-client.el → libbcel-client.el View File

@@ -1,9 +1,9 @@
;;; libbasecampel-client.el --- Handles connection to the Basecamp 3 API -*- lexical-binding: t; -*-
;;; libbcel-client.el --- Handles connection to the Basecamp 3 API -*- lexical-binding: t; -*-

;; Copyright (C) 2019 Damien Cassou

;; Author: Damien Cassou <damien@cassou.me>
;; Url: https://gitlab.petton.fr/basecampel/libbasecampel
;; Url: https://gitlab.petton.fr/bcel/libbcel
;; Package-requires: ((emacs "26.1"))
;; Version: 0.2.0

@@ -23,42 +23,42 @@
;;; Commentary:

;; This file takes care of communicating with Basecamp 3 API. The
;; authentication part is handled by `libbasecampel-oauth.el'.
;; authentication part is handled by `libbcel-oauth.el'.

;;; Code:

(require 'request)
(require 'json)

(defun libbasecampel-client-get-url (access-token url &optional callback)
(defun libbcel-client-get-url (access-token url &optional callback)
"Do a GET query to Basecamp 3 API at URL.

ACCESS-TOKEN is found in the result of the OAUTH2 authentication.
See `libbasecampel-oauth-get-access-token'.
See `libbcel-oauth-get-access-token'.

When CALLBACK is non-nil, evaluate it with the response."
(request
url
:type "GET"
:headers `(("User-Agent" . "basecampel (damien@cassou.me)")
:headers `(("User-Agent" . "bcel (damien@cassou.me)")
("Authorization" . ,(format "Bearer %s" access-token)))
:parser #'json-read
:success (cl-function (lambda (&key data &allow-other-keys)
(funcall callback data)))))

(defun libbasecampel-client-get-path (access-token account-id path &optional callback)
(defun libbcel-client-get-path (access-token account-id path &optional callback)
"Execute CALLBACK with the result of the GET call to PATH.

ACCESS-TOKEN can be retrieved with `libbasecampel-oauth-get-access-token'.
ACCESS-TOKEN can be retrieved with `libbcel-oauth-get-access-token'.

ACCOUNT-ID is the first number appearing after basecamp.com in
the URL when you are on the basecamp website."
(libbasecampel-client-get-url
(libbcel-client-get-url
access-token
(format "https://3.basecampapi.com/%s/%s"
account-id
path)
callback))

(provide 'libbasecampel-client)
;;; libbasecampel-client.el ends here
(provide 'libbcel-client)
;;; libbcel-client.el ends here

libbasecampel-oauth.el → libbcel-oauth.el View File

@@ -1,9 +1,9 @@
;;; libbasecampel-oauth.el --- Connects to basecamp API through oauth -*- lexical-binding: t; -*-
;;; libbcel-oauth.el --- Connects to basecamp API through oauth -*- lexical-binding: t; -*-

;; Copyright (C) 2019 Damien Cassou

;; Author: Damien Cassou <damien@cassou.me>
;; Url: https://gitlab.petton.fr/basecampel/libbasecampel
;; Url: https://gitlab.petton.fr/bcel/libbcel
;; Package-requires: ((emacs "26.1"))
;; Version: 0.2.0

@@ -33,15 +33,15 @@
;;; Configuration

(defgroup libbasecampel-oauth nil
(defgroup libbcel-oauth nil
"Group for OAuth authentication to Basecamp."
:group 'libbasecampel)
:group 'libbcel)

(defcustom libbasecampel-oauth-store-filename (concat user-emacs-directory "libbasecampel-oauth.store")
(defcustom libbcel-oauth-store-filename (concat user-emacs-directory "libbcel-oauth.store")
"Filename where Basecamp 3 OAuth tokens are stored."
:type 'file)

(defcustom libbasecampel-oauth-local-http-port 9321
(defcustom libbcel-oauth-local-http-port 9321
"The port number used for the redirect uri.

This number should be specified when defining the integration on
@@ -51,16 +51,16 @@ the basecamp website."
;;; OAuth2 client protocol

(defun libbasecampel-oauth--kill-process (process)
(defun libbcel-oauth--kill-process (process)
"Terminate the network PROCESS."
(stop-process process)
(delete-process process))

(defun libbasecampel-oauth--make-http-server (client-id client-secret callback)
(defun libbcel-oauth--make-http-server (client-id client-secret callback)
"Create a network process listening for HTTP connections.

The port the server listens to is
`libbasecampel-oauth-local-http-port'.
`libbcel-oauth-local-http-port'.

CLIENT-ID and CLIENT-SECRET are provided by basecamp for each
integration.
@@ -68,23 +68,23 @@ integration.
CALLBACK is executed with the authentication data if the OAUTH
authentication terminates successfully."
(let ((http-server-process))
(let ((kill-process-fn (lambda () (libbasecampel-oauth--kill-process http-server-process))))
(let ((kill-process-fn (lambda () (libbcel-oauth--kill-process http-server-process))))
(setq http-server-process
(make-network-process
:server t
:name "libbasecampel-oauth-http-server"
:service libbasecampel-oauth-local-http-port
:buffer (generate-new-buffer "*libbasecampel-oauth-http-server*")
:name "libbcel-oauth-http-server"
:service libbcel-oauth-local-http-port
:buffer (generate-new-buffer "*libbcel-oauth-http-server*")
:filter (apply-partially
#'libbasecampel-oauth--http-server-filter
#'libbcel-oauth--http-server-filter
client-id
client-secret
(libbasecampel-oauth--redirect-uri)
(libbcel-oauth--redirect-uri)
kill-process-fn
callback))))))

(defun libbasecampel-oauth--open-browser (client-id redirect-uri)
"Open the user's favorite web browser so s·he can authorize libbasecampel.
(defun libbcel-oauth--open-browser (client-id redirect-uri)
"Open the user's favorite web browser so s·he can authorize libbcel.

CLIENT-ID is provided by basecamp for each integration.

@@ -95,7 +95,7 @@ should be a string such as \"http://localhost:9321\"."
client-id
redirect-uri)))

(defun libbasecampel-oauth--http-server-filter (client-id client-secret redirect-uri kill-process-fn callback process data)
(defun libbcel-oauth--http-server-filter (client-id client-secret redirect-uri kill-process-fn callback process data)
"Analyze DATA and continue the OAUTH process if DATA has a code.

CLIENT-ID and CLIENT-SECRET are provided by basecamp for each
@@ -118,7 +118,7 @@ client which opened the connection."
(setf (point) (point-min))
(when (re-search-forward (rx bol "GET /?code=" (group-n 1 (+ (not (any " ")))) " ") nil t)
(let ((code (match-string 1)))
(libbasecampel-oauth--send-auth-request
(libbcel-oauth--send-auth-request
`((type . "web_server")
(client_id . ,client-id)
(redirect_uri . ,redirect-uri)
@@ -134,16 +134,16 @@ client which opened the connection."
(funcall kill-process-fn))
kill-process-fn))))))

(defun libbasecampel-oauth--refresh-access-token (store callback)
(defun libbcel-oauth--refresh-access-token (store callback)
"Execute CALLBACK with a refreshed access token from STORE."
(let* ((client-id (map-elt store :client-id))
(client-secret (map-elt store :client-secret))
(refresh-token (map-elt store :refresh-token)))
(libbasecampel-oauth--send-auth-request
(libbcel-oauth--send-auth-request
`((type . "refresh")
(refresh_token . ,refresh-token)
(client_id . ,client-id)
(redirect_uri . ,(libbasecampel-oauth--redirect-uri))
(redirect_uri . ,(libbcel-oauth--redirect-uri))
(client_secret . ,client-secret))
(lambda (data)
(funcall callback data))
@@ -151,7 +151,7 @@ client which opened the connection."
(user-error "Failed to refresh basecamp access token")
(funcall callback)))))

(defun libbasecampel-oauth--send-auth-request (params success failure)
(defun libbcel-oauth--send-auth-request (params success failure)
"Do a POST request with PARAMS on Basecamp auth URL.
Execute SUCCESS with data upon success, or FAILURE."
(request
@@ -165,28 +165,28 @@ Execute SUCCESS with data upon success, or FAILURE."
:error (cl-function (lambda (&rest _args)
(funcall failure)))))

(defun libbasecampel-oauth--redirect-uri ()
"Generate a local redirect-uri from `libbasecampel-oauth-local-http-port'.
(defun libbcel-oauth--redirect-uri ()
"Generate a local redirect-uri from `libbcel-oauth-local-http-port'.

REDIRECT-URI is specified when creating a new integration. It is
a string such as \"http://localhost:9321\"."
(concat "http://localhost:" (number-to-string libbasecampel-oauth-local-http-port)))
(concat "http://localhost:" (number-to-string libbcel-oauth-local-http-port)))

(defun libbasecampel-oauth--fetch (store callback)
(defun libbcel-oauth--fetch (store callback)
"Get new tokens using credentials in STORE and pass them to CALLBACK."
(let* ((client-id (map-elt store :client-id))
(client-secret (map-elt store :client-secret)))
(libbasecampel-oauth--make-http-server client-id client-secret callback)
(libbasecampel-oauth--open-browser client-id (libbasecampel-oauth--redirect-uri))))
(libbcel-oauth--make-http-server client-id client-secret callback)
(libbcel-oauth--open-browser client-id (libbcel-oauth--redirect-uri))))

;;; Token storage

(defun libbasecampel-oauth--store-has-access-token-p (store)
(defun libbcel-oauth--store-has-access-token-p (store)
"Return non-nil if STORE has an access token."
(map-contains-key store :access-token))

(cl-defun libbasecampel-oauth--store-save (store &key auth-token client-id client-secret)
(cl-defun libbcel-oauth--store-save (store &key auth-token client-id client-secret)
"Save AUTH-TOKEN within STORE."
(map-put store :expires-in (or (map-elt auth-token 'expires_in)
(map-elt store :expires-in)))
@@ -198,7 +198,7 @@ a string such as \"http://localhost:9321\"."
(map-elt store :client-id)))
(map-put store :client-secret (or client-secret
(map-elt store :client-secret)))
(with-current-buffer (find-file-noselect libbasecampel-oauth-store-filename)
(with-current-buffer (find-file-noselect libbcel-oauth-store-filename)
(erase-buffer)
(insert (format "%S" store))
(save-buffer)))
@@ -206,13 +206,13 @@ a string such as \"http://localhost:9321\"."
;;; Public function

(defun libbasecampel-oauth-get-store (client-id client-secret)
(defun libbcel-oauth-get-store (client-id client-secret)
"Return a `store' where Basecamp tokens should be saved.

CLIENT-ID and CLIENT-SECRET are provided by basecamp for each
integration."
(let ((store (if (file-readable-p libbasecampel-oauth-store-filename)
(with-current-buffer (find-file-noselect libbasecampel-oauth-store-filename)
(let ((store (if (file-readable-p libbcel-oauth-store-filename)
(with-current-buffer (find-file-noselect libbcel-oauth-store-filename)
(setf (point) (point-min))
(read (current-buffer)))
(make-hash-table :size 10))))
@@ -220,18 +220,18 @@ integration."
(map-put store :client-secret client-secret)
store))

(defun libbasecampel-oauth-get-access-token (store callback)
(defun libbcel-oauth-get-access-token (store callback)
"Execute CALLBACK with an access-token using the credentials saved in STORE.
To create STORE, call `libbasecampel-oauth-get-store'."
To create STORE, call `libbcel-oauth-get-store'."
(let ((auth-token-callback
(lambda (auth-token)
(message "auth-token: %s" auth-token)
(libbasecampel-oauth--store-save store :auth-token auth-token)
(libbcel-oauth--store-save store :auth-token auth-token)
(funcall callback (map-elt store :access-token)))))
(if (libbasecampel-oauth--store-has-access-token-p store)
(libbasecampel-oauth--refresh-access-token store auth-token-callback)
(libbasecampel-oauth--fetch store auth-token-callback)))
(if (libbcel-oauth--store-has-access-token-p store)
(libbcel-oauth--refresh-access-token store auth-token-callback)
(libbcel-oauth--fetch store auth-token-callback)))
t)

(provide 'libbasecampel-oauth)
;;; libbasecampel-oauth.el ends here
(provide 'libbcel-oauth)
;;; libbcel-oauth.el ends here

libbasecampel.el → libbcel.el View File

@@ -1,9 +1,9 @@
;;; libbasecampel.el --- Library to connect to basecamp 3 API -*- lexical-binding: t; -*-
;;; libbcel.el --- Library to connect to basecamp 3 API -*- lexical-binding: t; -*-

;; Copyright (C) 2019 Damien Cassou

;; Author: Damien Cassou <damien@cassou.me>
;; Url: https://gitlab.petton.fr/basecampel/libbasecampel
;; Url: https://gitlab.petton.fr/bcel/libbcel
;; Package-requires: ((emacs "26.1") (json-process-client "0.2.0"))
;; Version: 0.2.0

@@ -24,29 +24,29 @@

;; This library provides a bunch of functions and structures to
;; connect to Basecamp 3 API. The connection is handled by
;; libbasecampel-proxy.el and the JS files in the proxy/ directory.
;; libbcel-proxy.el and the JS files in the proxy/ directory.

;;; Code:

(require 'libbasecampel-oauth)
(require 'libbasecampel-client)
(require 'libbcel-oauth)
(require 'libbcel-client)

;; Configuration

(defgroup libbasecampel nil
"Configure libbasecampel to integrate Basecamp."
(defgroup libbcel nil
"Configure libbcel to integrate Basecamp."
:group 'external)

(defcustom libbasecampel-client-id nil
(defcustom libbcel-client-id nil
"Set your basecamp client id here."
:type 'string)

(defcustom libbasecampel-client-secret nil
(defcustom libbcel-client-secret nil
"Set your basecamp client secret here."
:type 'string)

(defcustom libbasecampel-account-id nil
(defcustom libbcel-account-id nil
"The account id to connect to.
This is the first number appearing after basecamp.com in the URL
when you are on the basecamp website."
@@ -55,77 +55,77 @@ when you are on the basecamp website."
;; Structures

(cl-defstruct (libbasecampel-entity
(:constructor libbasecampel--entity-create)
(:conc-name libbasecampel--entity-))
(cl-defstruct (libbcel-entity
(:constructor libbcel--entity-create)
(:conc-name libbcel--entity-))
(id nil :read-only t)
(name nil :read-only t)
(url nil :read-only t)
(type nil :read-only t)
(alist nil :read-only t))

(cl-defstruct (libbasecampel-project
(:include libbasecampel-entity)
(:constructor libbasecampel-project-create)
(:conc-name libbasecampel-project-))
(cl-defstruct (libbcel-project
(:include libbcel-entity)
(:constructor libbcel-project-create)
(:conc-name libbcel-project-))
(description nil :read-only t)
(tools nil
:read-only t
:alist-key-name dock
:alist-transformer (lambda (tools-data)
(libbasecampel--create-instances-from-data 'libbasecampel-tool tools-data))))
(libbcel--create-instances-from-data 'libbcel-tool tools-data))))

(cl-defstruct (libbasecampel-tool
(:include libbasecampel-entity)
(:constructor libbasecampel-tool-create)
(:conc-name libbasecampel-tool-))
(cl-defstruct (libbcel-tool
(:include libbcel-entity)
(:constructor libbcel-tool-create)
(:conc-name libbcel-tool-))
(enabled nil
:read-only t
:alist-transformer (lambda (data) (not (eq data :json-false)))))

(cl-defstruct (libbasecampel-message
(:include libbasecampel-entity
(cl-defstruct (libbcel-message
(:include libbcel-entity
(name nil :alist-key-name subject))
(:constructor libbasecampel-message-create)
(:conc-name libbasecampel-message-))
(:constructor libbcel-message-create)
(:conc-name libbcel-message-))
(content nil :read-only t))

(cl-defstruct (libbasecampel-todolist
(:include libbasecampel-entity)
(:constructor libbasecampel-todolist-create)
(:conc-name libbasecampel-todolist-))
(cl-defstruct (libbcel-todolist
(:include libbcel-entity)
(:constructor libbcel-todolist-create)
(:conc-name libbcel-todolist-))
(todos-url nil
:read-only t
:alist-key-name todos_url))

(cl-defstruct (libbasecampel-todo
(:include libbasecampel-entity
(cl-defstruct (libbcel-todo
(:include libbcel-entity
(name nil :alist-key-name title))
(:constructor libbasecampel-todo-create)
(:conc-name libbasecampel-todo-))
(:constructor libbcel-todo-create)
(:conc-name libbcel-todo-))
(description nil :read-only t))

(cl-defmethod libbasecampel-name ((entity libbasecampel-entity))
(libbasecampel--entity-name entity))
(cl-defmethod libbcel-name ((entity libbcel-entity))
(libbcel--entity-name entity))

(cl-defmethod libbasecampel-id ((entity libbasecampel-entity))
(libbasecampel--entity-id entity))
(cl-defmethod libbcel-id ((entity libbcel-entity))
(libbcel--entity-id entity))

;;; Private variables

(defvar libbasecampel--oauth-store nil
(defvar libbcel--oauth-store nil
"Remembers the OAuth authentication data.")

;;; Private functions

(defun libbasecampel--oauth-store ()
(defun libbcel--oauth-store ()
"Return the OAuth authentication data."
(or libbasecampel--oauth-store
(setq libbasecampel--oauth-store (libbasecampel-oauth-get-store libbasecampel-client-id libbasecampel-client-secret))))
(or libbcel--oauth-store
(setq libbcel--oauth-store (libbcel-oauth-get-store libbcel-client-id libbcel-client-secret))))

(defun libbasecampel--async-mapcar (mapfn list callback)
(defun libbcel--async-mapcar (mapfn list callback)
"Apply MAPFN to each element of LIST and pass result to CALLBACK.

MAPFN is a function taking 2 arguments: the element to map and a
@@ -152,7 +152,7 @@ callback to call when the mapping is done."
callback
(seq-concatenate 'list result))))))))))

(defun libbasecampel--async-mapc (mapfn list callback)
(defun libbcel--async-mapc (mapfn list callback)
"Same as `navigel-async-mapcar' but for side-effects only.

MAPFN is a function taking 2 arguments: an element of LIST and a
@@ -161,12 +161,12 @@ done computing.

CALLBACK is a function of no argument that is called when done
computing for the all elements of LIST."
(libbasecampel--async-mapcar
(libbcel--async-mapcar
(lambda (item callback) (funcall mapfn item (lambda () (funcall callback nil))))
list
(lambda (_result) (funcall callback))))

(defun libbasecampel--create-instance-from-data (struct-type entity-data)
(defun libbcel--create-instance-from-data (struct-type entity-data)
"Return an instance of a STRUCT-TYPE from ENTITY-DATA, an alist."
(apply
#'record
@@ -183,94 +183,94 @@ computing for the all elements of LIST."
(funcall transformer alist-value)))
(cdr (cl-struct-slot-info struct-type)))))

(defun libbasecampel--create-instances-from-data (struct-type entities-data)
(defun libbcel--create-instances-from-data (struct-type entities-data)
"Return a list of instances of a STRUCT-TYPE from ENTITIES-DATA, a list of alists."
(mapcar (lambda (entity-data) (libbasecampel--create-instance-from-data struct-type entity-data))
(mapcar (lambda (entity-data) (libbcel--create-instance-from-data struct-type entity-data))
entities-data))

(defun libbasecampel-get-path (path &optional callback)
(defun libbcel-get-path (path &optional callback)
"Execute CALLBACK with the result of a GET call to PATH."
(libbasecampel-oauth-get-access-token
(libbasecampel--oauth-store)
(libbcel-oauth-get-access-token
(libbcel--oauth-store)
(lambda (access-token)
(libbasecampel-client-get-path access-token libbasecampel-account-id path callback))))
(libbcel-client-get-path access-token libbcel-account-id path callback))))

(defun libbasecampel-get-url (url callback)
(defun libbcel-get-url (url callback)
"Do a GET request on URL and evaluate CALLBACK with the result."
(libbasecampel-oauth-get-access-token
(libbasecampel--oauth-store)
(libbcel-oauth-get-access-token
(libbcel--oauth-store)
(lambda (access-token)
(libbasecampel-client-get-url access-token url callback))))
(libbcel-client-get-url access-token url callback))))

;;; Public functions

(cl-defgeneric libbasecampel-children (entity callback)
(cl-defgeneric libbcel-children (entity callback)
"Execute CALLBACK with the children of ENTITY as parameter.")

(cl-defmethod libbasecampel-children ((_entity (eql projects)) callback)
(cl-defmethod libbcel-children ((_entity (eql projects)) callback)
"Execute CALLBACK with the list of all projects as parameter."
(libbasecampel-get-path
(libbcel-get-path
"/projects.json"
(lambda (projects-data)
(funcall callback
(libbasecampel--create-instances-from-data
'libbasecampel-project
(libbcel--create-instances-from-data
'libbcel-project
projects-data)))))

(cl-defmethod libbasecampel-children ((project libbasecampel-project) callback)
(cl-defmethod libbcel-children ((project libbcel-project) callback)
(funcall
callback
(seq-filter
#'libbasecampel-tool-enabled
(libbasecampel-project-tools project))))
#'libbcel-tool-enabled
(libbcel-project-tools project))))

(defun libbasecampel--tool-child-struct-type (tool)
(defun libbcel--tool-child-struct-type (tool)
"Return a struct-type to instanciate children of TOOL."
(let ((type (libbasecampel-name tool)))
(let ((type (libbcel-name tool)))
(cond
((string= type "message_board") 'libbasecampel-message)
((string= type "todoset") 'libbasecampel-todolist)
(t (user-error "Libbasecampel: unknown tool type `%s" type)))))
((string= type "message_board") 'libbcel-message)
((string= type "todoset") 'libbcel-todolist)
(t (user-error "Libbcel: unknown tool type `%s" type)))))

(defun libbasecampel--tool-child-url-key (tool)
(defun libbcel--tool-child-url-key (tool)
"Return the URL association key to fetch children of TOOL."
(let ((type (libbasecampel-name tool)))
(let ((type (libbcel-name tool)))
(cond
((string= type "message_board") 'messages_url)
((string= type "todoset") 'todolists_url)
(t (user-error "Libbasecampel: unknown tool type `%s" type)))))
(t (user-error "Libbcel: unknown tool type `%s" type)))))

(cl-defmethod libbasecampel-children ((tool libbasecampel-tool) callback)
(libbasecampel-get-url
(libbasecampel-tool-url tool)
(cl-defmethod libbcel-children ((tool libbcel-tool) callback)
(libbcel-get-url
(libbcel-tool-url tool)
(lambda (tool-data)
(libbasecampel-get-url
(map-elt tool-data (libbasecampel--tool-child-url-key tool))
(libbcel-get-url
(map-elt tool-data (libbcel--tool-child-url-key tool))
(lambda (children-data)
(funcall callback
(libbasecampel--create-instances-from-data
(libbasecampel--tool-child-struct-type tool)
(libbcel--create-instances-from-data
(libbcel--tool-child-struct-type tool)
children-data)))))))

(cl-defmethod libbasecampel-children ((todolist libbasecampel-todolist) callback)
(libbasecampel-get-url
(libbasecampel-todolist-todos-url todolist)
(cl-defmethod libbcel-children ((todolist libbcel-todolist) callback)
(libbcel-get-url
(libbcel-todolist-todos-url todolist)
(lambda (todos-data)
(funcall callback (libbasecampel--create-instances-from-data 'libbasecampel-todo todos-data)))))
(funcall callback (libbcel--create-instances-from-data 'libbcel-todo todos-data)))))

(cl-defmethod libbasecampel-children ((entities list) callback)
(libbasecampel--async-mapcar
#'libbasecampel-children
(cl-defmethod libbcel-children ((entities list) callback)
(libbcel--async-mapcar
#'libbcel-children
entities
callback))

(defun libbasecampel-completing-read (prompt entities &optional transformer)
(defun libbcel-completing-read (prompt entities &optional transformer)
"PROMPT user to select one entity among ENTITIES.

Transform each entity to a string with TRANSFORMER,
`libbasecampel-name' if nil."
(let* ((transformer (or transformer #'libbasecampel-name))
`libbcel-name' if nil."
(let* ((transformer (or transformer #'libbcel-name))
(map (make-hash-table :test 'equal :size (length entities)))
(entity-strings (mapcar (lambda (entity) (funcall transformer entity)) entities)))
(cl-mapcar (lambda (entity entity-string)
@@ -279,16 +279,16 @@ Transform each entity to a string with TRANSFORMER,
(let ((entity-string (completing-read prompt entity-strings nil t)))
(gethash entity-string map))))

(defun libbasecampel-completing-read-entity (function prompt entity &optional transformer)
(defun libbcel-completing-read-entity (function prompt entity &optional transformer)
"Call FUNCTION after prompting for a child of ENTITY.

Pass PROMPT, the elements of ENTITY and TRANSFORMER to
`libbasecampel-completing-read'."
(libbasecampel-children
`libbcel-completing-read'."
(libbcel-children
entity
(lambda (entities)
(funcall function
(libbasecampel-completing-read prompt entities transformer)))))
(libbcel-completing-read prompt entities transformer)))))

(provide 'libbasecampel)
;;; libbasecampel.el ends here
(provide 'libbcel)
;;; libbcel.el ends here

Loading…
Cancel
Save