summaryrefslogtreecommitdiff
path: root/haunt/jakob/dynamic/capabilities/gallery.scm
blob: 8f29c85448af3cf3a06361e24dac85e100b719db (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
;;; 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 dynamic capabilities gallery)
  #:use-module (ice-9 binary-ports)
  #:use-module (ice-9 ftw)
  #:use-module (ice-9 match)
  #:use-module (jakob dynamic errors)
  #:use-module (jakob dynamic util)
  #:use-module (json)
  #:use-module (squee)
  #:use-module (srfi srfi-1)
  #:use-module (web request)
  #:use-module (web response)
  #:use-module (web uri)
  #:export (get-gallery get-image))

(define conn (connect-to-postgres-paramstring "user=jakob_dynamic dbname=jakob_gallery"))

;; How many bytes of entropy to use when generating vanity ID's.
(define %vanity-length (make-parameter 9))

;; Path where gallery images are stored.
(define %gallery-image-directory (make-parameter "/home/jakob/gallery-images/"))

(define (valid-gallery-code code)
  "Check database to see if `code' names a nonempty gallery."
  (and (= (string-length code) (base64-length (%vanity-length)))
       (positive?
        (length
         (exec-query conn "SELECT * FROM images WHERE vanity = $1"
                     (list code))))))

(define (get-gallery-images code)
  "Handler for enumerating the image in a gallery."
  (define (format-image image)
    (match image
      ((title filename thumbnail datetime)
       `((title . ,title)
         (filename . ,filename)
         (thumbnail . ,thumbnail)
         (datetime . ,datetime)))))
  (let* ((images (exec-query conn "SELECT title, filename, thumb_filename, datetime FROM images WHERE vanity = $1" (list code))))
    (list->vector (map format-image images))))

(define (get-gallery-info code)
  "Handler for enumerating the image in a gallery."
  (define (format-gallery info)
    (match info
      ((title description datetime)
       `((title . ,title)
         (description . ,description)
         (datetime . ,datetime)))))
  (let* ((info (exec-query conn "SELECT title, description, datetime FROM galleries WHERE vanity = $1" (list code))))
    (format-gallery (car info))))

(define (get-gallery request body)
  (let* ((query-string (uri-query (request-uri request)))
         (params (if query-string
                     (decode-form query-string)
                     '()))
         (code (car (assoc-ref params "g"))))
    (unless (valid-gallery-code code) (panic "invalid gallery code"))
    (values '((content-type . (application/json)))
            (scm->json-string `((info . ,(get-gallery-info code))
                                (images . ,(get-gallery-images code)))))))

(define (image-exists? file-name)
  (define (string/= a b) (not (string= a b)))
  (and (string/= file-name ".")
       (string/= file-name "..")
       (member file-name (scandir (%gallery-image-directory)))))

(define (read-image file-name)
  (let* ((ext (string-downcase (last (string-split file-name #\.))))
         (mime (cond ((string= ext "jpg") 'image/jpeg)
                     ((string= ext "png") 'image/png)
                     (else (error "Unknown MIME type.")))))
    (values `((content-type . (,mime)))
            (call-with-input-file (format #f "~a/~a" (%gallery-image-directory) file-name)
              (lambda (port)
                (get-bytevector-all port))))))

(define (get-image request body)
  (let* ((query-string (uri-query (request-uri request)))
         (params (if query-string
                     (decode-form query-string)
                     '()))
         (file-name (car (assoc-ref params "name"))))
    (unless (image-exists? file-name) (panic "invalid filename"))
    (read-image file-name)))