add comments, create post template
This commit is contained in:
parent
26e803b051
commit
29c829509b
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
21
scripts/init
21
scripts/init
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
|
|
Loading…
Reference in New Issue