;;; Copyright © 2019 - 2023 Jakob L. Kreuze ;;; ;;; 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 ;;; . (define-module (jakob dynamic capabilities comment-form) #:use-module (gcrypt base64) #:use-module (haunt html) #:use-module (ice-9 match) #:use-module (jakob builder blog) #:use-module (jakob dynamic captcha) #:use-module (jakob dynamic util) #:use-module (jakob theme) #:use-module (jakob utils sxml) #:use-module (json) #:use-module (srfi srfi-1) #:use-module (srfi srfi-11) #:use-module (web request) #:use-module (web response) #:use-module (web uri) #:export (render-static-comment-form render-dynamic-comment-form get-comment-form)) (define (render-comment-field) `((div (@ (class "form-row")) (input (@ (type "text") (id "name") (name "name") (required #t) (aria-label "Name") (placeholder "Name"))) (input (@ (type "text") (id "subject") (name "subject") (aria-label "Subject") (placeholder "Subject (Optional)")))) (div (@ (class "form-row")) (input (@ (type "text") (id "url") (name "url") (aria-label "Website URL") (placeholder "Website (https://...)")))) (textarea (@ (id "coment") (name "comment") (placeholder "Write your comment here...") (rows "4") (required "") (aria-label "Comment body"))))) (define* (render-comment-captcha-field #:optional (captcha-id "") captcha-image #:key hidden) `((div (@ (id "captcha-container")) (div (@ (id "captcha-image-wrapper"))) (div (@ (id "captcha-input-wrapper")) (input (@ (type "text") (id "captcha-solution") (name "captcha") (required "true"))) (button (@ (id "captcha-challenge-trigger") (type "button")) "Fetch Captcha")) (input (@ (autocomplete "off") (type "text") (hidden #t) (id "captcha-id") (name "captcha-id") (value ,captcha-id))) (input (@ (autocomplete "off") (type "text") (hidden #t) (id "captcha-alt") (name "captcha-alt"))) (input (@ (autocomplete "off") (type "text") (hidden #t) (id "captcha-alt-id") (name "captcha-alt-id"))) (div (@ (id "captcha-alternative-wrapper") (hidden "true")) (p "If you can't solve this integral, click this button to run an alternative proof-of-work captcha.") (button (@ (type "button") (id "proof-of-work-trigger") (aria-label "Automatic Captcha Button")) "Calculate Proof-of-Work For Me"))))) (define (render-static-comment-form slug captcha-id captcha-image) `(div (@ (id "comment-form")) (h1 "Comment form") (form (@ (id "comment-input") (action "/api/comment") (method "post")) (input (@ (type "text") (name "slug") (hidden #t) (value ,slug))) ,(render-comment-field) ,(render-comment-captcha-field captcha-id captcha-image)) ,(script "proof-of-work.js"))) (define (render-dynamic-comment-form slug) `(form (@ (id "comment-form") (action "/api/comment") (method "post") (hidden "true")) ;; Hidden fields. (input (@ (autocomplete "off") (type "text") (hidden #t) (name "slug") (value ,slug))) (input (@ (autocomplete "off") (type "text") (hidden #t) (name "reply-to") (id "reply-to") (value ""))) ,@(render-comment-field) ,@(render-comment-captcha-field) (button (@ (type "submit") (style "margin-top: 10px;")) "Submit Comment") ,(script "dynamic-comment-form.js") ,(script "proof-of-work.js"))) (define (get-comment-form request body) (let-values (((captcha-id captcha-image) (new-captcha!))) (let* ((path-encoded (uri-path (request-uri request))) (path (split-and-decode-uri-path path-encoded)) (slug (last path)) (form (render-static-comment-form slug captcha-id captcha-image))) (values '((content-type . (text/html))) (sxml->html-string (theme #:content form #:title "Comment prompt"))))))