summaryrefslogtreecommitdiff
path: root/src/weepinbell/webserver/retriever.clj
blob: 986db8ea7dc61646eb48852232813cd54160f4ec (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
(ns weepinbell.webserver.retriever
  "Service getting webmention form storage and wrapping it in a response."
  (:require [weepinbell.utils.url :refer [get-domain get-path]]
            [ring.util.http-response :refer [bad-request not-found ok]]))

(def default-page-size 12)

;; response utilities 

(defn- respond-webmention-json [data]
  (if (and data (some? (:webmention data)))
    (ok data)
    (not-found {:message "The requested webmention does not exist."})))

(defn- respond-webmention-list-json [data]
  (cond
    (= data :OOB) (bad-request {:message "Page number is too large."})
    (empty? data) (not-found {:message "The requested webmention list does not exist."})
    :else         (ok data)))

;; query list of webmentions

(defn- filter-by-jf2type
  [jf2type data]
  (if (nil? jf2type) data
      (filter #(= jf2type (get-in % [:jf2 :wm-property])) data)))

(defn- paging
  "Paging utility, given a full set of data, partition it and return
   the requested frame.
   Returns the last frame if page number is not a number, as a fallback.
   Returns :OOB (Out Of Bounds) if page number is too large."
  [^Long page ^Long page-size data]
  (if (nil? page)
    ;; if no page number, return the whole query-list
    data
    ;; otherwise, partition all and return the requested frame
    (let [pages (->> data (partition-all page-size) vec)
          npages (count pages)
          page-number (if (number? page) page
                          (- (count pages) 1))]
      (if (>= page-number npages)
        :OOB ; Out Of Bounds
        (get pages page-number)))))

(defn query-list
  "Get a list of webmentions by certain filters."
  [{:keys [^String domain, ^String path, ^Long page, ^Long page-size
           storage mftype]}]
  {:pre [(contains? storage :get-by-domain)]}
  (let [;; parse to number if possible, use original if not
        page (try (Long/parseLong page) (catch Exception _ page))
        ;; data trasformations
        data ((:get-by-domain storage path) domain)
        data (filter-by-jf2type mftype data)
        data (paging page page-size data)]
    (respond-webmention-list-json data)))

(defn by-domain
  "Get webmentions sent to a particular domain."
  [domain page storage opts]
  (query-list {:domain domain
               :path nil
               :page page
               :page-size default-page-size
               :storage storage
               :mftype (:type opts)}))

(defn by-url
  "Get webmention sent to a particular URL."
  [url page storage opts]
  (if url
    (query-list {:domain (get-domain url)
                 :path (get-path url)
                 :page page
                 :page-size default-page-size
                 :storage storage
                 :mftype (:type opts)})
    {:status 400
     :body {:message "Missing URL. Specify target URL whose webmentions you are querying."}}))

;; query one webmention

(defn query-one
  "Get one specific webmention by id or by its source and target."
  [opts]
  {:post [(vector? (:identifiers opts))
          (contains? (:storage opts) :get)]}
  (let [{:keys [identifiers storage]} opts
        data (apply (:get storage) identifiers)]
    (respond-webmention-json data)))

(defn by-id
  "Get one specific webmention by ID."
  [id storage]
  (query-one {:identifiers [id]
              :storage storage}))

(defn by-st-pair
  "Get one specific webmention by source and target."
  [source target storage]
  (query-one {:identifiers [source target]
              :storage storage}))