aboutsummaryrefslogtreecommitdiffstats
path: root/tekuti.el
blob: 9545fcc20fc1a95a399ba991a77c9a0d7dbfa631 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
;;; tekuti.el --- Tekuti interaction library         -*- lexical-binding: t; -*-

;; Copyright (C) 2021  Tom Willemse

;; Author: Tom Willemse <chelys@data>
;; Keywords: comm
;; Package-Requires: (org)

;; 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 <https://www.gnu.org/licenses/>.

;;; Commentary:

;; A simple module to help post things to your tekuti blog. You’ll want to
;; customize the ‘tekuti-host’ variable to point to your own blog. You should be
;; asked for your credentials, which should then be stored in ~/.authinfo.gpg.

;; Currently you should add these headers to your org document that you want to
;; send up:

;; #+TITLE: SOME TITLE
;; #+DATE: <2021-06-03 Thu 22:45>
;; #+TAGS: comma,separated
;; #+COMMENTS: open
;; #+COMMENTS_DATE:
;; #+STATUS: publish

;; The main entry point is ‘tekuti-send’. Call this from an org-mode buffer to
;; export the buffer to HTML and send it up to your blog.

;;; Code:

(require 'org)

(defvar tekuti-host "http://127.0.0.1:8080")

(defun tekuti--format-date (&optional date)
  "Format DATE into a date that tekuti understands."
  (format-time-string "%a, %d %b %Y %H:%M:%S %Z"
                      (unless (null date)
                        (org-timestamp-to-time
                         (org-timestamp-from-string date)))
                      t))

(defun tekuti-build-data-from-org ()
  "Parse the current org buffer to collect the necessary metadata."
  (let ((defaults `(("TITLE")
                    ("DATE" ,(tekuti--format-date))
                    ("TAGS")
                    ("STATUS")
                    ("COMMENTS")
                    ("COMMENTS-CLOSED-DATE")
                    ("BODY")))
        (data (append
               (mapcar
                (lambda (pair)
                  (pcase pair
                    (`("DATE" ,date)
                     (list "DATE" (tekuti--format-date date)))
                    (`("COMMENTS_DATE" ,date)
                     (list "COMMENTS-CLOSED-DATE"
                           (and (not (string-empty-p date))
                                (tekuti--format-date date))))
                    (_ pair)))
                (org-collect-keywords '("TITLE" "TAGS" "STATUS" "COMMENTS" "DATE" "COMMENTS_DATE")))
               (list
                (list "BODY"
                      (with-current-buffer (org-html-export-as-html nil nil nil t)
                        (buffer-substring-no-properties (point-min) (point-max))))))))
    (mapcar (lambda (item)
              (let ((key (car item)))
                `(,key ,@(or (alist-get key data nil nil #'string=)
                             (cdr item)))))
            defaults)))

(defun tekuti-form-encode-pair (key value)
  (concat (url-hexify-string key) "=" (url-hexify-string value)))

(defun tekuti-form-encode-data (data)
  (mapconcat
   (lambda (pair)
     (tekuti-form-encode-pair (downcase (car pair)) (cadr pair)))
   data
   "&"))

(defun tekuti--send-finished (status &rest _)
  (message "Finished: %s" status))

;;;###autoload
(defun tekuti-send ()
  (interactive)
  (let* ((data (tekuti-build-data-from-org))
         (url-request-method "POST")
         (url-request-extra-headers
          `(("Content-Type" . "application/x-www-form-urlencoded")))
         (url-request-data (tekuti-form-encode-data data)))
    (url-retrieve (format "%s/admin/new-post" tekuti-host) #'tekuti--send-finished)))

(provide 'tekuti)
;;; tekuti.el ends here