summaryrefslogtreecommitdiff
path: root/haunt/jakob/utils/webmention.scm
blob: f30bb1258af92882cda7c4f4c7debf74ba16e25f (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
111
112
113
114
115
116
117
118
;;; Copyright © 2019 - 2022 Jakob L. Kreuze <zerodaysfordays@sdf.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
;;; <http://www.gnu.org/licenses/>.

(define-module (jakob utils webmention)
  #:use-module (ice-9 receive)
  #:use-module (ice-9 iconv)
  #:use-module (ice-9 match)
  #:use-module (srfi srfi-19)
  #:use-module (srfi srfi-43)
  #:use-module (json)
  #:use-module (web client)
  #:use-module (web response)
  #:use-module (oop goops)
  #:export (render-comment-view
            fetch-webmentions))

(define (format-comment webmention)
  "Format `webmention', an alist, as SXML for a comment-type interaction"
  (define (strip uri)
    "Attempt to remove any sort of protocol specification from `uri'"
    (let* ((needle "://")
           (index (string-contains uri needle)))
      (if index
          (strip (substring uri (+ index (string-length needle))))
          uri)))
  (let* ((author (assoc-ref webmention "author"))
         (author-name (assoc-ref author "name"))
         (author-photo (assoc-ref author "photo"))
         (author-url (assoc-ref author "url"))
         (content (assoc-ref webmention "content"))
         (content-text (assoc-ref content "text"))
         (published-time (assoc-ref webmention "published"))
         (received-time (assoc-ref webmention "wm-received"))
         (url (assoc-ref webmention "url"))
         (time (if (eqv? 'null published-time) received-time published-time)))
    `(li (@ (class "p-comment h-cite comment comment-source-webmention"))
         (img (@ (class "comment-source-identifier")
                 (alt "Webmention logo")
                 (src "/static/image/webmention-logo.png")))
         (div (@ (class "p-author h-card author"))
              (img (@ (class "u-photo")
                      (src ,(if (string-prefix? author-url "https://lobste.rs/")
                                "/static/image/lobsters.png"
                                (or author-photo "/static/image/default-icon.png")))))
              (a (@ (class "p-name u-url")
                    (href ,author-url))
                 ,author-name)
              (a (@ (class "author-url")
                    (href ,author-url))
                 ,(strip author-url)))
         (div (@ (class "e-content p-name comment-content"))
              ,content-text)
         (div (@ (class "metaline"))
              (a (@ (class "u-url")
                    (href ,url))
                 (time (@ (class "dt-published")
                          (datetime ,time))
                       ,(date->string
                         (string->date time "~Y~m~d~H~M~S")
                         "~B ~e, ~Y at ~H:~M")))))))

(define (format-interaction webmention)
  "Format `webmention', an alist, as SXML for a rich interaction without content"
  (let* ((author (assoc-ref webmention "author"))
         (author-name (assoc-ref author "name"))
         (author-photo (assoc-ref author "photo"))
         (author-url (assoc-ref author "url")))
    `(li (@ (class "p-comment h-cite interaction comment-source-webmention"))
         (a (@ (href ,author-url))
            (img (@ (class "u-photo")
                    (src ,(if (string-prefix? author-url "https://lobste.rs/")
                              "/static/image/lobsters.png"
                              (or author-photo "/static/image/default-icon.png"))))))
         (div (@ (class "e-content p-name comment-content"))
              (em
               ,(match (assoc-ref webmention "wm-property")
                  ("repost-of" "Reposted this!")
                  ("like-of" "Favorited this!")
                  (_ "[No Text Provided]"))))
         (img (@ (class "comment-source-identifier")
                 (alt "Webmention logo")
                 (src "/static/image/webmention-logo.png"))))))

(define (render-comment-view response)
  "Render `response', the output of `fetch-webmentions', as SXML"
  (vector->list
   (vector-map (lambda (_ x)
                 (if (and (assoc-ref x "wm-property")
                          (member (assoc-ref x "wm-property") '("in-reply-to" "mention-of")))
                     (format-comment x)
                     (format-interaction x)))
               (assoc-ref response "children"))))

(define (fetch-webmentions slug)
  "Blocking call to webmention.io to retrieve a vector of all Webmentions for `slug'"
  (define prefixes '("http://jakob.space/" "https://jakob.space/"
                     "http://jakob.space/blog/" "https://jakob.space/blog/"))
  (let* ((target-queries (map (lambda (pre)
                             (format #f "target[]=~a~a.html" pre slug))
                           prefixes))
         (url (format #f "https://webmention.io/api/mentions.jf2?per-page=200&page=0&~a"
                     (string-join targets-queries "&"))))
    (receive (response-status response-body)
        (http-request url)
      (call-with-input-string (bytevector->string response-body "UTF-8") json->scm))))