| ID | a9c7b2c3-737c-4d6d-a131-24b3aaa81a5a |
|---|---|
| DeertopiaVisibility | public |
Publishing my Org-roam notes (archived)
This is old and bad. See the new file at Publishing my Org-roam notes.
Motivation and goals
unimplemented! (verse-block)
{:type "verse-block",
:affiliated {},
:contents-begin 343,
:contents-end 1028,
:position
{:start {:line 12, :column 1, :offset 329},
:end {:line 22, :column 1, :offset 1040}},
:children
([:b ("maddy")]
": a blog would be neat and would fulfill my desire to Post, but it's oddly too formal. i realise blogs are anything but formal, but i can't write anything non-private and article-shaped without getting really obsessed with the quality and leaving it unfinished. i liked your haskellboard post }:3.\n"
[:b ("maddy:")]
" i think publishing a subset of my personal notes is attractive to me for that reason. they're presented without an audience in mind }xP. you're eavesdropping on a conversation with myself. other readers aren't even acknowledged.\n\n(on diff feeds)\n\n"
[:b ("faye")]
": that would be fun!!!\n"
[:b ("faye")]
": maybe you could trigger it on inactivity\n"
[:b ("faye")]
": so you get a cohesive diff every time\n")}
Monitor an org directory. After N minutes of inactivity, snapshot the org files, and diff it with the previous snapshot.
Serve RSS: feeds of complete diffs, addition-only feeds.
Lazily export files to HTML. querying e.g. deertopia.net/notes/file for the first time will export file.org to HTML and cache it. Perhaps this should be a separate tool.
Per-node visibility set via Org's key/value properties.
This turns dailies into a Twitter/Bluesky substitute.
For other notes, it's an interesting way to see what I'm working on / thinking about.
Periodically, automatically export my Org notes to HTML
But only those marked as public! It looks like nodes' properties are stored in the Org-roam database, which should make this very easy.
Serve the notes on Deertopia's webpage
Human readable URLs via node title; perma-links via node ID
Provide an interactive graph view, Ã la org-roam-ui
IDEA Post dailies to Bluesky with a bot?
KILL Haskell implementation
I'm dropping the Haskell implementation and starting anew in Clojure, due to frustrations with the Haskell ecosystem (mostly the LDAP options).
Backend unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 2304,
:end 2309,
:value "[1/7]",
:post-blank 0,
:position
{:start {:line 47, :column 17, :offset 2304},
:end {:line 47, :column 22, :offset 2309}}}
unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 2304,
:end 2309,
:value "[1/7]",
:post-blank 0,
:position
{:start {:line 47, :column 17, :offset 2304},
:end {:line 47, :column 22, :offset 2309}}}
Choose implementation language
State "DONE" from "TODO"
I think we're going with Haskell! I've missed her. }:)unimplemented! (
{:type "line-break", :position {:start {:line 51, :column 63, :offset 2444}, :end {:line 51, :column 65, :offset 2446}}}line-break)
HTTP server
Using Servant.
When queried for a node,
/node/«name»
Get the node corresponding to «name».org.
/id/«id»
Get the node with ID «id».
Authentication unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 2938,
:end 2943,
:value "[3/5]",
:post-blank 0,
:position
{:start {:line 71, :column 25, :offset 2938},
:end {:line 71, :column 30, :offset 2943}}}
unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 2938,
:end 2943,
:value "[3/5]",
:post-blank 0,
:position
{:start {:line 71, :column 25, :offset 2938},
:end {:line 71, :column 30, :offset 2943}}}
What the hell am I doing?
I took some notes on LDAP, but I don't think direct interaction is the way. Perhaps we can integrate with Authelia?
While I'm familiar with the recipe to make Nginx request authentication before forwarding traffic to the internal service, I'm not so sure how one may properly integrate their application with an identity provider. By "integrate," I mean that my application isn't simply living behind a wall setup by Nginx. My app is exposed to the world, but aware of potential authentication. Consider a web app with 1. a display of the currently signed-in user's name, or "not signed in" if not; and 2. a link to a sign-in page.
Noting that Copyparty integrates with SSO providers (e.g. Authelia), I browsed their documentation and Deertopia's Copyparty configuration. A solution then crawled into view from the end of the tunnel, and it looks pretty simple! Copyparty's only required knowledge is the names of two HTTP headers in which the username and the user's groups are read from. See Deertopia's Copyparty config and Copyparty's documentation.
Oops, the preceding paragraph is wrong. Copyparty still must live behind a coproxy with authentication.
After authentication, Authelia will provide a cookiehttps://www.authelia.com/configuration/session/introduction/, authelia_session, which lingers around and is attached to all further requests to deertopia.net. If we can figure out how to validate this authelia_session cookie, we can safely make use of the remote-user and remote-groups headers.
It looks like Authelia is not meant to be used in this way after all. Direct LDAP access is probably the way. From here, I suppose we'll have to look into creating a login form. See servant-auth and clientsession.
Plan of action
Log-in form does
GET https://deertopia.net/api/login?username=«username»&password=«password»Haskell app validates w/ LLDAP.
On success, session cookies are provided.
Servant manages the rest; we are given
AuthResult User, whereUseris defined by us. Will have fields for username and LDAP groups.When rendering nodes, check visibility and act appropriately using the username and user groups, querying the LDAP server as necessary.
Login form
Get handlers authentication-aware
Filter nodes by visibility
Allow arbitrary LDAP filters per node?
Integrate with LDAP
HTML exporter unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 5930,
:end 5936,
:value "[2/14]",
:post-blank 0,
:position
{:start {:line 108, :column 24, :offset 5930},
:end {:line 108, :column 30, :offset 5936}}}
unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 5930,
:end 5936,
:value "[2/14]",
:post-blank 0,
:position
{:start {:line 108, :column 24, :offset 5930},
:end {:line 108, :column 30, :offset 5936}}}
Headlines unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 5958,
:end 5963,
:value "[3/6]",
:post-blank 0,
:position
{:start {:line 110, :column 21, :offset 5958},
:end {:line 110, :column 26, :offset 5963}}}
unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 5958,
:end 5963,
:value "[3/6]",
:post-blank 0,
:position
{:start {:line 110, :column 21, :offset 5958},
:end {:line 110, :column 26, :offset 5963}}}
Title
Number
Contents
Self-link
To-do keyword unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 6163,
:end 6168,
:value "[0/5]",
:post-blank 0,
:position
{:start {:line 123, :column 26, :offset 6163},
:end {:line 123, :column 31, :offset 6168}}}
unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 6163,
:end 6168,
:value "[0/5]",
:post-blank 0,
:position
{:start {:line 123, :column 26, :offset 6163},
:end {:line 123, :column 31, :offset 6168}}}
TODO
DONE
KILL
WAIT
HOLD
Tags
Document top-level
Export blocks
Markup unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 6390,
:end 6395,
:value "[0/8]",
:post-blank 0,
:position
{:start {:line 142, :column 18, :offset 6390},
:end {:line 142, :column 23, :offset 6395}}}
unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 6390,
:end 6395,
:value "[0/8]",
:post-blank 0,
:position
{:start {:line 142, :column 18, :offset 6390},
:end {:line 142, :column 23, :offset 6395}}}
Emphasis
Italics
Strike-through
Underline
Superscript
Subscript
Verbatim
Code
Source blocks
Quote blocks
Verse blocks
Example blocks
Links
id:
file:
img:
https
Math
TeX fragments
TeX environments
Paragraphs
Footnotes
Footnote references
Proper "back to content" links
important for accessibility
Footnote definitions
Tables
Lists
Checklists
Export directory
KILL NO Double-export
I currently believe the easiest way to do this is to export twice. Once for public files, with non-public headings filtered out. The second time will not be filtered, and will be served at a different URL with Deertopia authentication.
KILL NO Non-static site
Customise the HTML exporter to include visibility info in the exported document. Write a little proxy application to serve the exported HTML that will account for visibility.
This means the backend will have to parse, filter, and re-print HTML.
YES Export to JSON/EDN; CGI script manages visibility and HTML-rendering
This fork of ox-json works well.
Implement publish function for ox-json
Should be trivial.
Watch Org directory for inactivity
Generate graph data
Define output schema
JSON or EDN?
State "DONE" from "TODO"
Just use JSON }:P.unimplemented! (
{:type "line-break", :position {:start {:line 236, :column 63, :offset 8427}, :end {:line 236, :column 65, :offset 8429}}}line-break)Frontend will be written in ClojureScript, so EDN will be nice.
Aeson will make JSON easy.
What information do we need?
Obviously, vertices and edges.
Clustering? Colouring? Centrality? Weight?
Frontend unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 8685,
:end 8690,
:value "[0/1]",
:post-blank 0,
:position
{:start {:line 247, :column 18, :offset 8685},
:end {:line 247, :column 23, :offset 8690}}}
unimplemented! (statistics-cookie)
{:type "statistics-cookie",
:begin 8685,
:end 8690,
:value "[0/1]",
:post-blank 0,
:position
{:start {:line 247, :column 18, :offset 8685},
:end {:line 247, :column 23, :offset 8690}}}
Graph
ClojureScript + D3.js
Clojure implementation
Authentication
Login page
References
The single most important reference used was Hugo Cisnero's blog post, which essentially serves as an outline of what I want to implement here. Thanks! }:D