Publ: Development Blog


Posted (a month ago)

v0.3.11 is now released, with the following changes:

  • A more complete fix for how to handle image sets and inline images with respect to paragraphs
  • Better cleanup for spurious empty paragraphs
  • Improved internal entry link handling

Detailed descriptions of the changes are below.

Improved entry link handling

Entry links used to just be pretty simplistic; for example,

previously an entry link like


would just generate

<a href="123">foo</a>

which would require at least a redirect to the entry from the path resolver, and also required external feed readers to be savvy enough to rewrite URLs (which is technically a violation of the Atom spec although most feed readers do the rewriting even though they’re not supposed to). Now it will generate a link like:

<a href="/example/123-some-foo">foo</a>

or, in an absolute context (e.g. a feed),

<a href="">foo</a>

But the primary improvement here is that it will also resolve links to entries by filename; for example, all of the below should work:

[some other entry](
[in a parent directory](../
[relative to content root](/blog/

You can see some tests of this. This link was, of course, generated with [some tests of this](/tests/relative entry (but using the entry ID should still work as well).

This of course means that any Publ site will automatically get much better links for existing entries too, with no work needed on the publisher’s end.

Thoughs about future functionality

One of the things I’ve been wanting to add since the very beginning is private content; I’ve rambled quite a lot about how I might support that in Atom over on my personal blog. But I haven’t really talked about how this will go into Publ itself.

The changes to URL resolution got me thinking a lot about the whole “public links to private entries” issue and thinking about how I want to deal with data hiding/sanitization in Publ itself, and I came to realize that a lot of the groundwork for the fiddly bits is already there in Publ. For example, the changes to caching already make it so that I don’t have to worry about serving up private content due to a spurious cache hit (or serving up a public view to an authenticated viewer, for that matter), as the authenticated user will be part of the cache memoization already.

And I think that the data privacy model can be that the Entry object itself knows about auth – for example, it will know who the logged-in user is and whether they have access to the entry – and will only provide the data that should be visible. Which means that out of the box, private entries will at worst show up as placeholders with no data (or displaying shim content, anyway), and even things like link generation will be subject to these rules; the link resolver will be able to just see whether the viewer is authorized to see the title, and if not, it will just produce an old-style /id link, so no information about it leaks through that either.

There will of course be a couple of APIs to add in order to improve the view for unauthorized content, though; I’ll probably add a property to Entry to indicate whether the entry is unauthorized (so the template can show a “please log in” thing or whatever), and then view.entries,, and entry.previous will gain an unauthorized parameter to decide whether unauthorized content should be shown in the first place. So in fact the placeholder entries wouldn’t even appear by default. Also it should get some way of determining if any auth is needed at all, so that e.g. Disqus threads can be configured appropriately (like having two separate communities, one for public posts that allows discovery and one for private posts which doesn’t).

View will also probably get a needs_auth property, which will return True if the user isn’t identified and there’s private content that would appear in the view. That way, if someone isn’t identified, a category template can show whatever is appropriate to request auth from the client (e.g. an HTML fragment directing the viewer to the login page, or an Atom fragment with <link rel="auth"> or whatever).

Authentication itself, by the way, will absolutely be handled via IndieAuth and AutoAuth.

From a publisher’s perspective I see it working like this:

First, there will be a metadata file in some as-yet-undetermined format (probably YAML or JSON) that has mappings like e.g.: # that's me!
    private # Larry from high school
    enemies # Alistair
    enemies  # I'm not talking to them right now...

Next, private entries will get a header that indicates which identities or groups have (or don’t have) access; for an over-complicated example:

Private: private !enemies !

which means that people in the “private” group can see it, unless they’re in the “enemies” group, and also let Fred (who isn’t in a group) to this entry, but don’t allow Nancy to see it even though she’s in the private group. (I would also probably have a special token * which matches anyone who has a known identity, whether they’re in a group or not, mostly for the purpose of showing a login/logout widget on the sidebar or whatever.)

Finally, if someone accesses the site and authenticates, this information will in some way be floated to the publisher, so they know whether to add the person to the friends list or whatever. (Perhaps there can be a daily digest of newly-visible folks, as well as a panel that is restricted to specific identities (like in the special _admin group) that shows all of the information about recent access. Most likely the user table will simply have a last_seen column.)

Open questions:

  • Would it be useful to assign access groups on a per-category basis, or does that just needlessly overcomplicate things?
  • What about access at the category level itself? (also probably overcomplicated)
  • Are there any IndieAuth endpoints out there which let people log in directly with particular OAuth identities?

    Like, it’s really annoying to require people to authenticate with a profile page that has a bidirectional rel="me" relationship to one of the common OAuth providers (GitHub, Twitter, etc.), but none of the endpoints I’ve seen let you just provide that provider as your profile link in the first place. And this presents a big barrier to entry, IMO.

    It’d also be great if these endpoints were to widen their net; so far I only see support for GitHub and Twitter, but there’s a ton of folks using Mastodon now, for example.

  • How the heck am I going to test IndieAuth login while I’m working on it? I guess I could spin up another Publ instance on my server, ugh…

Anyway, I am pretty excited about how having proper private blogging feels like it’s actually within my grasp!