summaryrefslogtreecommitdiff
path: root/haunt/jakob/dynamic/capabilities/gallery.scm
diff options
context:
space:
mode:
Diffstat (limited to 'haunt/jakob/dynamic/capabilities/gallery.scm')
-rw-r--r--haunt/jakob/dynamic/capabilities/gallery.scm111
1 files changed, 111 insertions, 0 deletions
diff --git a/haunt/jakob/dynamic/capabilities/gallery.scm b/haunt/jakob/dynamic/capabilities/gallery.scm
new file mode 100644
index 0000000..b8b46c9
--- /dev/null
+++ b/haunt/jakob/dynamic/capabilities/gallery.scm
@@ -0,0 +1,111 @@
+;;; 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 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 "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"))))
+ (if (valid-gallery-code code)
+ (values '((content-type . (application/json)))
+ (scm->json-string `((info . ,(get-gallery-info code))
+ (images . ,(get-gallery-images code)))))
+ (values (build-response #:code 400)
+ (scm->json-string
+ `((success . #f)
+ (error . "Invalid gallery 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"))))
+ (if (image-exists? file-name)
+ (read-image file-name)
+ (values (build-response #:code 400)
+ (scm->json-string
+ `((success . #f)
+ (error . "Invalid filename")))))))