add comments, create post template

This commit is contained in:
xenia 2020-07-23 01:02:00 -04:00
parent 26e803b051
commit 29c829509b
6 changed files with 65 additions and 6 deletions

View File

@ -1,6 +1,8 @@
#lang racket #lang racket
;; compiler ;; compiler:
;; infrastructure for incrementally compiling blog contents from source to html/json/etc
;; lots of graphs (it's all graphs)
(provide (struct-out rule) (provide (struct-out rule)
generate-operations generate-operations

View File

@ -1,5 +1,8 @@
#lang racket #lang racket
;; prefs:
;; utilities for reading and writing preferences
(require net/url-string) (require net/url-string)
(provide prefs-save prefs-load prefs-get prefs-update DEFAULT-PREFS) (provide prefs-save prefs-load prefs-get prefs-update DEFAULT-PREFS)
@ -17,31 +20,39 @@
(define (pronoun-list? x) (define (pronoun-list? x)
(and (list? x) (= 5 (length x)))) (and (list? x) (= 5 (length x))))
;; a preferences schema with validation functions
(define SCHEMA (define SCHEMA
(hash 'instance-url instance-url? (hash 'instance-url instance-url?
'display-name string? 'display-name string?
'name id-string? 'name id-string?
'title string?
'make-discoverable boolean? 'make-discoverable boolean?
'is-cat boolean? 'is-cat boolean?
'lang string?
'pronouns pronoun-list?)) 'pronouns pronoun-list?))
(define DEFAULT-PREFS (define DEFAULT-PREFS
'((instance-url "https://myinstance.tld/") '((instance-url "https://myinstance.tld/")
(display-name "Display Name(tm)") (display-name "Display Name(tm)")
(name "username") (name "username")
(title "My Shiny New Blog")
(lang "en")
(make-discoverable #t) (make-discoverable #t)
(is-cat #t) (is-cat #t)
(pronouns ("they" "them" "their" "theirs" "themselves")))) (pronouns ("they" "them" "their" "theirs" "themselves"))))
;; saves preferences to the given port (or current out)
(define (prefs-save prefs [port (current-output-port)]) (define (prefs-save prefs [port (current-output-port)])
(pretty-write prefs port)) (pretty-write prefs port))
;; validates a preference entry against the schema
(define (validate-one k v) (define (validate-one k v)
(unless (hash-has-key? SCHEMA k) (unless (hash-has-key? SCHEMA k)
(error "unknown preference name" k)) (error "unknown preference name" k))
(unless (apply (hash-ref SCHEMA k) (list v)) (unless (apply (hash-ref SCHEMA k) (list v))
(error "invalid preference value" v (hash-ref SCHEMA k)))) (error "invalid preference value" v (hash-ref SCHEMA k))))
;; validates a whole prefs object
(define (validate x) (define (validate x)
(unless (list? x) (unless (list? x)
(error "preferences must be list")) (error "preferences must be list"))
@ -50,16 +61,20 @@
[(list k v) (validate-one k v)] [(list k v) (validate-one k v)]
[_ (error "invalid preference")])) [_ (error "invalid preference")]))
x) x)
;; check the defaults
(void (validate DEFAULT-PREFS)) (void (validate DEFAULT-PREFS))
;; reads and validates preferences from the given port (or current in)
(define (prefs-load [port (current-input-port)]) (define (prefs-load [port (current-input-port)])
(validate (read port))) (validate (read port)))
;; finds a preference by name
(define (prefs-get prefs what) (define (prefs-get prefs what)
(match prefs (match prefs
[(list _ ... (list (? (curry symbol=? what)) value) _ ...) value] [(list _ ... (list (? (curry symbol=? what)) value) _ ...) value]
[_ (error "no such pref" prefs what)])) [_ (error "no such pref" prefs what)]))
;; updates one key/value pair in the preferences list
(define (prefs-update prefs key value) (define (prefs-update prefs key value)
(validate-one key value) (validate-one key value)
(define (upd p) (define (upd p)

View File

@ -1,6 +1,7 @@
#lang racket #lang racket
;; static generation rules ;; rules:
;; the actual rules that generate the blog contents
(require json (require json
net/url-string net/url-string
@ -11,6 +12,7 @@
"compile.rkt" "compile.rkt"
"prefs.rkt") "prefs.rkt")
;; actor context object
(define ACTOR-CONTEXT (define ACTOR-CONTEXT
(list "https://www.w3.org/ns/activitystreams" (list "https://www.w3.org/ns/activitystreams"
"https://w3id.org/security/v1" "https://w3id.org/security/v1"
@ -64,6 +66,7 @@
(reverse (cons (substring str last-pos) items))])) (reverse (cons (substring str last-pos) items))]))
(first (process+ xexpr))) (first (process+ xexpr)))
;; creates the index.json file (an actor object for this blog)
(define compile-index-json (define compile-index-json
(rule '("db/actorkey.pub" "src/instance.rktd" "src/bio.md") "public/index.json" (rule '("db/actorkey.pub" "src/instance.rktd" "src/bio.md") "public/index.json"
(lambda (in out) (lambda (in out)
@ -82,6 +85,7 @@
(match p (match p
[(list a b _ ...) (format "~a/~a" a b)] [(list a b _ ...) (format "~a/~a" a b)]
[_ "any"])) [_ "any"]))
(define actor (hash (define actor (hash
'@context ACTOR-CONTEXT '@context ACTOR-CONTEXT
'Type "Person" 'Type "Person"
@ -92,35 +96,40 @@
'isCat (prefs-get prefs 'is-cat) 'isCat (prefs-get prefs 'is-cat)
'pronouns (hash 'en (prefs-get prefs 'pronouns)) 'pronouns (hash 'en (prefs-get prefs 'pronouns))
'icon (hash 'type "Image" 'icon (hash 'type "Image"
'url "something" 'url "something" ;; TODO
'sensitive #f) 'sensitive #f)
'image (hash 'type "Image" 'image (hash 'type "Image"
'url "something" 'url "something" ;; TODO
'sensitive #f) 'sensitive #f)
'tag (for/list ([hashtag (in-set bio-hashtags)]) 'tag (for/list ([hashtag (in-set bio-hashtags)])
(hash 'type "Hashtag" (hash 'type "Hashtag"
'href (string-append instance-url "tags/" 'href (string-append instance-url "tags/"
(substring hashtag 1)) (substring hashtag 1))
'name hashtag)) 'name hashtag))
'manuallyApprovesFollowers #f 'manuallyApprovesFollowers #f ;; TODO
'summary bio 'summary bio
'attachment (list (hash 'type "PropertyValue" 'attachment (list (hash 'type "PropertyValue" ;; TODO
'name "pronouns" 'name "pronouns"
'value (render-pronouns))) 'value (render-pronouns)))
'url instance-url 'url instance-url
'inbox (string-append instance-url "inbox") 'inbox (string-append instance-url "inbox")
'sharedInbox (string-append instance-url "inbox") 'sharedInbox (string-append instance-url "inbox")
;; there's only one inbox
'endpoints (hash 'sharedInbox (string-append instance-url "inbox")) 'endpoints (hash 'sharedInbox (string-append instance-url "inbox"))
'outbox (string-append instance-url "outbox") 'outbox (string-append instance-url "outbox")
;; currently we don't support actually following anyone
'following 'null 'following 'null
'followers (string-append instance-url "followers") 'followers (string-append instance-url "followers")
;; liking posts is similarly not supported
'liked 'null 'liked 'null
;; TODO key rotation or something idk
'publicKey (hash 'id (string-append instance-url "#main-key") 'publicKey (hash 'id (string-append instance-url "#main-key")
'type "Key" 'type "Key"
'owner instance-url 'owner instance-url
'publicKeyPem key))) 'publicKeyPem key)))
(write-json actor out)))) (write-json actor out))))
;; builds the webfinger endpoint for the instance actor
(define compile-webfinger (define compile-webfinger
(rule '("src/instance.rktd") "public/webfinger.json" (rule '("src/instance.rktd") "public/webfinger.json"
(lambda (in out) (lambda (in out)
@ -137,7 +146,9 @@
'href instance-url)))) 'href instance-url))))
(write-json webfinger out)))) (write-json webfinger out))))
;; generates render rules for each post that is present
(define (generate-post-render-rules) (define (generate-post-render-rules)
;; creates a rule that builds common post info into cache
(define (make-post-cache-rule post-src post-dst) (define (make-post-cache-rule post-src post-dst)
(rule `("src/instance.rktd" ,post-src) post-dst (rule `("src/instance.rktd" ,post-src) post-dst
(lambda (in out) (lambda (in out)
@ -156,12 +167,14 @@
(s-exp->fasl (s-exp->fasl
(hash 'is-meow (hash-ref src-meta 'is-meow #t) (hash 'is-meow (hash-ref src-meta 'is-meow #t)
'title (hash-ref src-meta 'title "unknown") 'title (hash-ref src-meta 'title "unknown")
'summary (hash-ref src-meta 'summary "unknown")
'date (hash-ref src-meta 'date '(0 0 0)) 'date (hash-ref src-meta 'date '(0 0 0))
'hashtags (set->list hashtags) 'hashtags (set->list hashtags)
'toc (toc post-htmls) 'toc (toc post-htmls)
'content post-htmls)) 'content post-htmls))
out)))) out))))
;; add all cache rules
(define-values [posts-set cache-set] (define-values [posts-set cache-set]
(for/fold ([posts (set)] [caches (set)]) ([post-name (in-list (directory-list "src/posts"))] (for/fold ([posts (set)] [caches (set)]) ([post-name (in-list (directory-list "src/posts"))]
#:when (regexp-match? #px"\\.md$" post-name)) #:when (regexp-match? #px"\\.md$" post-name))
@ -185,12 +198,14 @@
(write-bytes (s-exp->fasl (for/hash ([(k v) (in-hash index)]) (write-bytes (s-exp->fasl (for/hash ([(k v) (in-hash index)])
(values k (set->list v)))) out))))) (values k (set->list v)))) out)))))
;; build the main blog css
(define compile-css (define compile-css
(rule '("src/style.sass") "public/style.css" (rule '("src/style.sass") "public/style.css"
(lambda (in out) (lambda (in out)
(define str (port->string (hash-ref in "src/style.sass"))) (define str (port->string (hash-ref in "src/style.sass")))
(write-string (sass-compile/string str #t) out)))) (write-string (sass-compile/string str #t) out))))
;; collect all compiler rules
(define compiler-rules (define compiler-rules
(set-union (set-union
(generate-post-render-rules) (generate-post-render-rules)

View File

@ -1,5 +1,10 @@
#lang racket #lang racket
;; taskq:
;; infrastructure for a persistent task queue that guarantees each entry will execute to completion
;; at least once. entries are responsible for implementing idempotency in the case of interrupted
;; operations (due to a crash, for example)
(require db crypto racket/fasl) (require db crypto racket/fasl)
(provide make-taskq taskq-shutdown taskq-enqueue taskq-dequeue taskq-complete taskq-resched) (provide make-taskq taskq-shutdown taskq-enqueue taskq-dequeue taskq-complete taskq-resched)

View File

@ -55,6 +55,27 @@
(void))) (void)))
(with-output-to-file "src/style.sass" (with-output-to-file "src/style.sass"
(lambda () (write-string "// styles go here :P\n") (void))) (lambda () (write-string "// styles go here :P\n") (void)))
;; TODO index template
(with-output-to-file "src/template-post.html"
(lambda ()
(write-string ;; TODO add more meta elements / semantic web type stuff
;; add an embedded json-LD object maybe
"<!DOCTYPE html>
<html lang='{{prefs.lang}}'>
<head>
<meta charset='UTF-8' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
<meta name='description' content='{{post.summary}}'>
<title>{{post.title}} &em; {{prefs.title}}</title>
</head>
<body>
<article>
{{post.content}}
</article>
</body>
</html>"
) (void)))
(make-directory "src/posts") (make-directory "src/posts")
(make-directory "src/drafts") (make-directory "src/drafts")

View File

@ -24,6 +24,7 @@
(lambda () (lambda ()
(pretty-write `((date (,(date-year now) ,(date-month now) ,(date-day now))) (pretty-write `((date (,(date-year now) ,(date-month now) ,(date-day now)))
(title ,name) (title ,name)
(summary "a new post on this blog")
(is-meow #t))) (is-meow #t)))
(printf "\n# ~a\n\nHello world\n" name)))) (printf "\n# ~a\n\nHello world\n" name))))
(void)) (void))