<?xml version="1.0" encoding="utf-8"?>



<feed xmlns="http://www.w3.org/2005/Atom"
    xmlns:fh="http://purl.org/syndication/history/1.0"
    xmlns:at="http://purl.org/atompub/tombstones/1.0">

    <title>Publ: Development Blog</title>
    <subtitle>A personal publishing system for the modern web</subtitle>
    <link href="http://publ.beesbuzz.biz/blog/feed?tag=design" rel="self" />
    <link href="http://publ.beesbuzz.biz/blog/feed" rel="current" />
    <link href="https://busybee.superfeedr.com" rel="hub" />
    
    <link href="http://publ.beesbuzz.biz/blog/feed?date=2018-09" rel="prev-archive" />
    
    
    <link href="http://publ.beesbuzz.biz/blog/" />
    <fh:archive />
    <id>tag:publ.beesbuzz.biz,2020-01-07:blog</id>
    <updated>2025-01-05T19:25:49-08:00</updated>

    
    <entry>
        <title>Publ + Pushl releases and a bunch of plans</title>
        <link href="http://publ.beesbuzz.biz/blog/930-Publ-Pushl-releases-and-a-bunch-of-plans" rel="alternate" type="text/html" />
        <published>2025-01-05T19:25:49-08:00</published>
        <updated>2025-01-05T19:25:49-08:00</updated>
        <id>urn:uuid:448a6793-87ae-5753-bf62-2ac50f10867e</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>There&rsquo;s been a few releases of both Publ (now on 0.7.35) and Pushl (now on 0.4.0). A pretty decent amount has changed!</p><p>Publ changes since 0.7.31:</p>
<ul>
<li>Fix some error handling issues causing an ISE</li>
<li>Add support for HTTP <code>Accept:</code>, properly allowing multiple templates with the same name and providing <a href="http://publ.beesbuzz.biz/manual/324-Templating-Guide#template-mapping">reasonable fallback behavior</a></li>
<li>Improve the <code>Content-Type</code> handling in general</li>
<li>Fix some markup-safe handling bugs</li>
</ul>
<p>Note that in order to upgrade to 0.7.35 you&rsquo;ll also need to restrict your Python environment to use a Python version &lt; 3.13; more on that in a bit.</p><p>Pushl changes since v0.3.5:</p>
<ul>
<li>Tidy up some code rot</li>
<li>Actually send an <code>Accept:</code> header</li>
<li>Removed lxml + Pingback support, which has never actually been useful</li>
</ul>
<p>So, let&rsquo;s talk about these projects and some other related stuff.</p>

<h3 id="930_h3_1_Tech-debt"><a href="http://publ.beesbuzz.biz/blog/930-Publ-Pushl-releases-and-a-bunch-of-plans#930_h3_1_Tech-debt"></a>Tech debt</h3><p>Publ has quite a lot of tech debt.</p><p>Most of the testing is done in an ad-hoc smoke-testing manner, and this has sometimes made it difficult for me to work on new features. (Of course I also am the only person working on these features, so I only prioritize things that I personally need.)</p><h4 id="930_h4_2_Pony"><a href="http://publ.beesbuzz.biz/blog/930-Publ-Pushl-releases-and-a-bunch-of-plans#930_h4_2_Pony"></a>Pony</h4><p>One particular issue is that it relies heavily on <a href="https://ponyorm.com">Pony</a>. Pony is a great ORM for doing quick application prototyping stuff, but unfortunately it&rsquo;s been a problem for quite some time:</p>
<ul>
<li>It makes proper unit testing significantly more difficult (it&rsquo;s actually the main reason the testing is in such a sorry state right now)</li>
<li>New Python versions usually end up breaking its clever code generator (which is why Publ 0.7.35 requires you to restrict your Python version)</li>
<li>It never gained support for schema migrations (which, thankfully, Publ was designed to not need to begin with, but this hampers some of my other plans)</li>
<li>General community support just never really materialized</li>
</ul>
<p>To address many of these problems, I&rsquo;ve been wanting to move to another database abstraction; I will most likely use <a href="https://www.sqlalchemy.org/">SQLAlchemy</a>. Whether I use its ORM or not is something I&rsquo;m still trying to decide.</p><h4 id="930_h4_3_Whoosh"><a href="http://publ.beesbuzz.biz/blog/930-Publ-Pushl-releases-and-a-bunch-of-plans#930_h4_3_Whoosh"></a>Whoosh</h4><p>Similarly, full-text search uses <a href="https://pypi.org/project/Whoosh/">whoosh</a>, which has been more or less abandoned. I have updated to use <a href="https://pypi.org/project/Whoosh-Reloaded/">whoosh-reloaded</a>, a community fork that has fixed most of the more egregious issues, but there are still a lot of issues with it:</p>
<ul>
<li>Its locking behavior is difficult to work with (and can cause a lot of operational difficulty)</li>
<li>Its ingest is slow and not easily threadable</li>
<li>Updating the index can be difficult and fragile</li>
<li>It stores the index on the local filesystem which can be a problem for many deployment scenarios</li>
<li>It puts <em>way</em> too much structured into its structured queries, and is overkill for the kinds of query representation Publ needs</li>
</ul>
<p>Unfortunately there aren&rsquo;t as many existing full-text search implementations for Python. My expectation for now is that I&rsquo;ll roll my own using the algorithms described in <a href="https://bart.degoe.de/building-a-full-text-search-engine-150-lines-of-code/">Bart de Goede&rsquo;s article</a>, although this doesn&rsquo;t feel like a great way to do things either.</p><h4 id="930_h4_4_Misaka"><a href="http://publ.beesbuzz.biz/blog/930-Publ-Pushl-releases-and-a-bunch-of-plans#930_h4_4_Misaka"></a>Misaka</h4><p>Finally, the Markdown engine currently used by Publ has been abandoned and is unlikely to continue to working in the long term. It&rsquo;s always been a bit of an operational problem, as well, because it relies on Hoedown (which has been abandoned for ages and never even got updated with HTML 5 support) and requires being able to either retrieve architecture-specific binaries or being able to build them yourself. The build process has been <em>mostly</em> easy for most users, but it&rsquo;s still not ideal.</p><p>Fortunately, I&rsquo;ve been playing with other Markdown implementations on other projects, and I&rsquo;m fairly certain that I&rsquo;ll be happy with <a href="https://github.com/lepture/mistune">Mistune</a> instead. Switching to that will require reimplementing a bunch of stuff in Publ, but it&rsquo;s all stuff I&rsquo;d been wanting to fix anyway.</p><p>In particular, I&rsquo;ve been wanting to figure out a way to templatize footnotes (for example, letting people make use of <a href="https://edwardtufte.github.io/tufte-css/">Tufte sidenotes</a> or putting a <code>&lt;details&gt;</code> reveal inline or after the current paragraph or the like), and there&rsquo;s a lot that could be better about how image sets are currently handled, and ideally I&rsquo;d be able to templatize those as well.</p><h3 id="930_h3_5_Comments"><a href="http://publ.beesbuzz.biz/blog/930-Publ-Pushl-releases-and-a-bunch-of-plans#930_h3_5_Comments"></a>Comments</h3><p>The main ways that I&rsquo;ve handled comments on Publ-based sites is either:</p>
<ul>
<li><a href="https://webmention.io/">webmention.io</a> + <a href="https://github.com/PlaidWeb/webmention.js">webmention.js</a></li>
<li><a href="https://isso-comments.de">isso</a></li>
</ul>
<p>Both of these are Fine™ for simple usage but they run into a bunch of issues on larger sites, and also the UX just isn&rsquo;t really where I&rsquo;d like it to be.</p><p>I wrote a <a href="https://beesbuzz.biz/blog/7457-Some-thoughts-on-comments">much more detailed blog post</a> on my main site, but the short version is that I&rsquo;d like to make a comment system that works more closely with Publ (or any other publishing framework) that stores things locally and supports both local posts <em>and</em> webmention (both sending and receiving), and which would also accept user data from the publishing stack.</p><p>I&rsquo;m thinking it would take the form of a Python library that you can embed into an app (with easy hooks for Flask), but would also offer its own Flask frontend for hosting it as an embeddable app instance that can be used from non-Python things.</p><h3 id="930_h3_6_ActivityPub"><a href="http://publ.beesbuzz.biz/blog/930-Publ-Pushl-releases-and-a-bunch-of-plans#930_h3_6_ActivityPub"></a>ActivityPub</h3><p>Native ActivityPub support has been at the back of my mind for a while. Having its own built-in webmention endpoint would also make for a nice spot to start adding in ActivityPub, since ActivityPub verbs aren&rsquo;t fundamentally different from Webmention verbs.</p><p>The main thing this would bring to the table is being able to set up various outboxes for different views (for example, <code>@blog@example.com</code> for just blog posts or <code>@all@example.com</code> for everything), and then also being able to make use of the user permissions to send private entries as DMs to the authorized subscribers, reducing the need for private entry stubs (which are bad UX all around and which I only adopted as a compromise because <a href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links">magic links have problems</a> and feed readers <em>still</em> don&rsquo;t support bearer tokens or <a href="https://indieweb.org/Ticketing_for_IndieAuth">Ticket Auth</a>).</p><h3 id="930_h3_7_Documentation"><a href="http://publ.beesbuzz.biz/blog/930-Publ-Pushl-releases-and-a-bunch-of-plans#930_h3_7_Documentation"></a>Documentation</h3><p>Also, having had to actually consult the docs while building a new Publ-based website, I&rsquo;ve come to realize just how bad a disaster the <a href="http://publ.beesbuzz.biz/manual/">manual</a> currently is. It could really do with some reorganization at the very least.</p><h3 id="930_h3_8_In-conclusion"><a href="http://publ.beesbuzz.biz/blog/930-Publ-Pushl-releases-and-a-bunch-of-plans#930_h3_8_In-conclusion"></a>In conclusion</h3><p>I have a lot of stuff I want to work on and hopefully I get somewhere with some of these things this year. If you&rsquo;d like to help out, you can make code contributions, or you can make financial contributions via <a href="https://ko-fi.com/fluffycritter">Ko-Fi</a>, <a href="https://patreon.com/fluffy">Patreon</a>, or <a href="https://github.com/sponsors/fluffy-critter">GitHub Sponsors</a>. But no pressure.</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>Why Publ won&#39;t support magic auth links</title>
        <link href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links" rel="alternate" type="text/html" />
        <published>2019-10-25T17:36:11-07:00</published>
        <updated>2019-10-25T17:36:11-07:00</updated>
        <id>urn:uuid:6695ff51-4390-5f69-affd-544a44f80f8a</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>Since adding user authentication to Publ, I&rsquo;ve been thinking of ways of allowing people to subscribe to sites from feed readers while getting their own native authorization, so that people can see entries directly in their readers rather than needing the clumsy mechanisms of unauthorized placeholder entries.</p><p>Out of the box, Publ authentication does support a shared cookie jar; if you can provide your cookies to your feed reader in some way, then things will Just Work. Unfortunately, I don&rsquo;t know of any feed readers that actually support this, at least not easily. (Back when most browsers had a feed reader built-in this was a lot simpler. But time marches on.)</p><p>The two mechanisms which seemed most promising are <a href="https://indieweb.org/AutoAuth">AutoAuth</a> and &ldquo;magic links,&rdquo; where users get signed URLs that come pre-authenticated and show the full authorized content for that user. AutoAuth is still in a draft phase that&rsquo;s stuck in a chicken-and-egg situation (and also requires a lot of buy-in to IndieWeb protocols, which is still a pill too large to swallow for most of the folks who follow my blog), so magic feed links seemed like the best path forward.</p><p>I even got so far as to <a href="https://github.com/PlaidWeb/Publ/issues/282">draft out an implementation</a>, but there&rsquo;s a few bad issues with it which just made me opt not to.</p>

<h2 id="1266_h2_1_Feed-discovery"><a href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#1266_h2_1_Feed-discovery"></a>Feed discovery</h2><p>Right now, when people want to subscribe to a feed, they usually point their feed reader at the URL for the website, and then let the reader software discover the feed. Usually there will be a <code>&lt;link&gt;</code> tag that provides the feed URL, like:</p><figure class="blockcode"><pre class="highlight" data-language="html" data-line-numbers><span class="line" id="e1266cb1L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb1L1"></a><span class="line-content"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;alternate&quot;</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;application/atom+xml&quot;</span> <span class="na">title</span><span class="o">=</span><span class="s">&quot;Atom feed&quot;</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;feed&quot;</span> <span class="p">/&gt;</span></span></span>
</pre></figure><p>Sometimes there may be more than one of these <code>&lt;link&gt;</code> tags for different styles of feed; for example, it might have both RSS and Atom versions, or there might be a choice between full-content and summary, or a comments feed, and so on. Some feed readers will show a list and allow the user to select which feed to use, while others will simply use the first one.</p><p>In the case of a magic link, however, these links are only provided to the person who is logged in. An external feed reader won&rsquo;t be logged in, and therefore won&rsquo;t see the magic link.</p><p>So, an alternate discovery mechanism must be provided; usually this will take the form of a widget in the corner of the page where clicking on it will expand a text box you can select the (possibly really long) feed link from and then paste <em>that</em> into your feed reader. There is no standard approach to doing this, and is confusing and weird.</p><h2 id="1266_h2_2_Item-sharing"><a href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#1266_h2_2_Item-sharing"></a>Item sharing</h2><p>The bigger problem, however, and the reason I decided to abandon the project entirely, is that the way that Atom specifies item sharing makes this incredibly dangerous.</p><p>Atom provides a way of sharing items; <a href="https://github.com/fluffy-critter/Feed-on-Feeds">Feed on Feeds</a> implements this, for example. If you share an item, its Atom entry looks like this:</p><figure class="blockcode"><pre class="highlight" data-language="xml" data-line-numbers><span class="line" id="e1266cb2L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L1"></a><span class="line-content"><span class="nt">&lt;entry&gt;</span></span></span>
<span class="line" id="e1266cb2L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L2"></a><span class="line-content"><span class="nt">&lt;id&gt;</span>urn:uuid:dacd7607-380e-526d-b688-60d8d334bde7<span class="nt">&lt;/id&gt;</span></span></span>
<span class="line" id="e1266cb2L3"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L3"></a><span class="line-content"><span class="nt">&lt;link</span><span class="w"> </span><span class="na">href=</span><span class="s">&quot;https://beesbuzz.biz/comics/journal/3675-ADDitive&quot;</span><span class="w"> </span><span class="na">rel=</span><span class="s">&quot;alternate&quot;</span><span class="w"> </span><span class="na">type=</span><span class="s">&quot;text/html&quot;</span><span class="nt">/&gt;</span></span></span>
<span class="line" id="e1266cb2L4"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L4"></a><span class="line-content"><span class="nt">&lt;title</span><span class="w"> </span><span class="na">type=</span><span class="s">&quot;html&quot;</span><span class="nt">&gt;</span>Journal:<span class="w"> </span>ADDitive<span class="nt">&lt;/title&gt;</span></span></span>
<span class="line" id="e1266cb2L5"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L5"></a><span class="line-content"><span class="nt">&lt;summary</span><span class="w"> </span><span class="na">type=</span><span class="s">&quot;html&quot;</span><span class="nt">&gt;</span></span></span>
<span class="line" id="e1266cb2L6"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L6"></a><span class="line-content"><span class="cm">&lt;!-- actual item content goes here --&gt;</span></span></span>
<span class="line" id="e1266cb2L7"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L7"></a><span class="line-content"><span class="nt">&lt;/summary&gt;</span></span></span>
<span class="line" id="e1266cb2L8"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L8"></a><span class="line-content"><span class="nt">&lt;updated&gt;</span>2019-10-15T23:14:52Z<span class="nt">&lt;/updated&gt;</span></span></span>
<span class="line" id="e1266cb2L9"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L9"></a><span class="line-content"><span class="nt">&lt;source&gt;</span></span></span>
<span class="line" id="e1266cb2L10"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L10"></a><span class="line-content"><span class="w">  </span><span class="nt">&lt;id&gt;</span>https://beesbuzz.biz/<span class="nt">&lt;/id&gt;</span></span></span>
<span class="line" id="e1266cb2L11"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L11"></a><span class="line-content"><span class="w">  </span><span class="nt">&lt;link</span><span class="w"> </span><span class="na">href=</span><span class="s">&quot;https://beesbuzz.biz/&quot;</span><span class="w"> </span><span class="na">rel=</span><span class="s">&quot;alternate&quot;</span><span class="w"> </span><span class="na">type=</span><span class="s">&quot;text/html&quot;</span><span class="nt">/&gt;</span></span></span>
<span class="line" id="e1266cb2L12"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L12"></a><span class="line-content"><span class="w">  </span><span class="nt">&lt;link</span><span class="w"> </span><span class="na">href=</span><span class="s">&quot;https://beesbuzz.biz/feed&quot;</span><span class="w"> </span><span class="na">rel=</span><span class="s">&quot;self&quot;</span><span class="w"> </span><span class="na">type=</span><span class="s">&quot;application/atom+xml&quot;</span><span class="nt">/&gt;</span></span></span>
<span class="line" id="e1266cb2L13"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L13"></a><span class="line-content"><span class="w">  </span><span class="nt">&lt;title&gt;</span>busybee<span class="nt">&lt;/title&gt;</span></span></span>
<span class="line" id="e1266cb2L14"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L14"></a><span class="line-content"><span class="nt">&lt;/source&gt;</span></span></span>
<span class="line" id="e1266cb2L15"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#e1266cb2L15"></a><span class="line-content"><span class="nt">&lt;/entry&gt;</span></span></span>
</pre></figure><p>That <code>&lt;source&gt;</code> block is what to look at; namely, the <code>rel=&quot;self&quot;</code>. It provides a link back to the original feed. This means that if someone were to share an item from an authenticated feed &ndash; regardless of the privacy of the item itself &ndash; it would also share the authenticated feed URL. This can be <em>very, very bad.</em></p><h2 id="1266_h2_3_So-what-are-the-alternatives"><a href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#1266_h2_3_So-what-are-the-alternatives"></a>So what are the alternatives?</h2><p>As stated in the preamble, the two major alternatives are shared cookies, and AutoAuth. Neither is a perfect solution.</p><p>Shared cookies are great if you can synchronize your session cookies between your browser and your feed reader. (This is especially feasible if your feed reader is hosted in your browser.) Most feed readers don&rsquo;t work that way. So, you could export your cookies to be used by the feed reader (which hopefully uses the presence of a cookie to avoid deduping subscriptions! I&rsquo;m pretty sure Feed On Feeds doesn&rsquo;t!), but if cookies have an expiration date on them (which Publ cookies absolutely do) this means having to re-export periodically.</p><p>Some sort of feed metadata indicating that there is a login/auth mechanism available might be workable; something like <code>&lt;link rel=&quot;authenticate&quot;&gt;</code> which prompts the browser to pop up some sort of proxy popup so that it can intercept the login cookie, for example. This might be a nice middle ground to AutoAuth without requiring every user to buy in fully to the IndieWeb experience.</p><p>(And, of course, supporting AutoAuth would be ideal for those who <em>do</em>.)</p><p>I think having some sort of &ldquo;hey, please log in&rdquo; metadata in the feed is also helpful if only because it gives a cue to a subscriber that there&rsquo;s something to authenticate against in the first place. But this purpose is already served by having empty &ldquo;private post&rdquo; stub entries&hellip;</p><h2 id="1266_h2_4_Other-things-to-consider"><a href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#1266_h2_4_Other-things-to-consider"></a>Other things to consider</h2><p>While I&rsquo;m ramble-thinking about this stuff, I&rsquo;d also like to see a better mechanism for dealing with authentication around <a href="https://indieweb.org/WebSub">WebSub</a>. As far as I&rsquo;ve seen, there are three kinds of WebSub push:</p>
<ol>
<li>Full-feed &ldquo;fat ping&rdquo; (i.e. the push notification contains the entire feed content)</li>
<li>Update-only &ldquo;fat ping&rdquo; (i.e. it only contains the new/changed items)</li>
<li>Notification-only &ldquo;thin ping&rdquo; (it only sends a notification of the update and then the recipient needs to do a pull of the content, once notified)</li>
</ol>
<p>The WebSub model doesn&rsquo;t really have any provisions for determining authentication/authorization status, as there&rsquo;s no mechanism for associating authentication stuff with the subscription topic. In case 3 it doesn&rsquo;t really matter &ndash; the client will just provide its normal content-pull credentials &ndash; but in cases 1 and 2 it matters quite a lot, as the content needs to be pre-filtered through the authentication layer.</p><p>For what it&rsquo;s worth, on all of my sites I use <a href="http://superfeedr.com/">SuperFeedr</a> as my WebSub hub, which does case 2 (actually a particularly annoying version of it where it only pushes <em>new</em> items, rather than including changed items). It definitely doesn&rsquo;t provide the extensibility required for authenticated WebSub, and I doubt that this is anything they ever would add even if a standard were to be adopted. So, I think for the non-thin push case, it would become necessary to have a different hub. <a href="https://switchboard.p3k.io/">Switchboard</a> appears to do a full-content push (case 1 above) and doesn&rsquo;t currently support AutoAuth; however, given the author, I would expect it to add that functionality when it becomes more commonplace.</p><p>In the meantime, I think I&rsquo;ll continue on with my unauthorized stub entries; they&rsquo;re annoying to unauthorized users and they leak the fact I&rsquo;m posting private entries to the world, but at least they prompt people to sign in and notify folks that there might be something for them to read. And for better or worse it also works with my <a href="https://indieweb.org/POSSE">POSSE</a> setup.</p><h2 id="1266_h2_5_Conclusion"><a href="http://publ.beesbuzz.biz/blog/1266-Why-Publ-won-t-support-magic-auth-links#1266_h2_5_Conclusion"></a>Conclusion</h2><p>Software is hard.</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>v0.3.19, now with extra tagging goodness!</title>
        <link href="http://publ.beesbuzz.biz/blog/232-v0.3.19-now-with-extra-tagging-goodness" rel="alternate" type="text/html" />
        <published>2019-03-04T15:47:43-08:00</published>
        <updated>2019-03-05T01:36:55+00:00</updated>
        <id>urn:uuid:65a7908e-6d8a-5dea-b1b4-d2961d4d4024</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>I&rsquo;ve released Publ v0.3.19, which now finally has a tagging system, which is only <a href="http://publ.beesbuzz.biz/issue/22">one of the oldest issues that was still open</a>.</p><p>Here&rsquo;s a list of what&rsquo;s been added or changed since 0.3.18:</p>
<ul>
<li>The test site is now part of the Publ repository itself (as <a href="http://publ.beesbuzz.biz/blog/332-Tests-removed-from-main-site">mentioned previously</a>)</li>
<li>Added <code>crop</code> and <code>fullsize_crop</code> to <a href="http://publ.beesbuzz.biz/manual/335-Image-renditions">image renditions</a> (although I&rsquo;ve already decided the <a href="http://publ.beesbuzz.biz/issue/179">format should be different</a> after using this for a day)</li>
<li>Made <code>Path-Alias</code> <a href="http://publ.beesbuzz.biz/issue/166">less annoying</a></li>
<li>Fixed an issue with <a href="http://publ.beesbuzz.biz/issue/175">unpaged archive links getting filtered</a></li>
<li>Prune <a href="http://publ.beesbuzz.biz/issue/101">missing files from the index</a></li>
</ul>
<h3 id="232_h3_1_Credits"><a href="http://publ.beesbuzz.biz/blog/232-v0.3.19-now-with-extra-tagging-goodness#232_h3_1_Credits"></a>Credits</h3><p>I want to thank <a href="https://github.com/karinassuni">Karina Antonio</a> for <a href="https://github.com/PlaidWeb/Publ/pull/169">implementing image cropping</a>.</p>

<h3 id="232_h3_2_On-image-cropping"><a href="http://publ.beesbuzz.biz/blog/232-v0.3.19-now-with-extra-tagging-goodness#232_h3_2_On-image-cropping"></a>On image cropping</h3><p>Originally I would have implemented cropping the way Karina did, but I got it stuck in my head that it would be much more efficient to compute the source rectangle and only do a single crop operation when it came to building the rendition. My four reasons for this were:</p>
<ul>
<li>Performance (only crop once if possible)</li>
<li>Something to do with better image quality (i.e. an intuitive thing that was stuck in my brain but had nothing to do with reality)</li>
<li>Wanting to match the cropping rectangle&rsquo;s aspect to the output aspect</li>
<li>Wanting the rendition filename to only reflect the input box</li>
</ul>
<p>Performance is a non-issue; even if it did make a measurable difference, renditions are cached as long as they&rsquo;re being used, and thus don&rsquo;t actually need to be recomputed every time.</p><p>Image quality was just something stuck in my head from when I was working on the Amazon image rendering service, because of some less-than-optimal things it did internally. It&rsquo;s not an issue for how Pillow works though.</p><p>Aspect matching is still a thing I kind of wanted to do, but then that leads to a few things like, what gravity should be used when &ldquo;uncropping&rdquo; the rectangle, and what about honoring the intent of the crop for excluding stuff outside of the box, and so on? Anyway those are a lot of questions that had fiddly answers and the reality is that it&rsquo;s easier to just leave it up to the user to match the aspect as appropriate, and use <code>resize=&quot;fill&quot;</code> vs. <code>resize=&quot;fit&quot;</code> as appropriate.</p><p>And the rendition filename? Who heckin&#39; cares, the point to rendition filenames is that they&rsquo;re unique, idempotent, and debuggable, not pretty. The basic tenet of humane URLs doesn&rsquo;t apply to them.</p><p>Anyway, as mentioned above the cut I do want to make a change to how cropping works in that right now it uses Pillow&rsquo;s rectangle specification of <code>(left,top,right,bottom)</code> but after using it for a day I&rsquo;m finding that really annoying and basically all imaging software uses <code>(x,y,width,height)</code> with respect to the top-left corner, and it makes no sense to have <code>right &lt; left</code> or <code>bottom &lt; top</code> anyway. So, on the off chance you&rsquo;re using Publ for your site and trimming thumbnails of your images, I&rsquo;d recommend holding off until the next version.</p><p><mark>Update:</mark> And then about an hour later I realized that there was actually a <a href="https://github.com/PlaidWeb/Publ/compare/v0.3.19..1b404926d916541f82e81fb314feea17130c9422">really easy way</a> to make scale-cropping work correctly here and I&rsquo;m feeling silly for not noticing it before. So this actually satisfies all of my original reasons except for the cropping rectangle aspect!  Also while testing this I found a case where the <code>(x,y,w,h)</code> tuple syntax confuses the Markdown parser, so it now also accepts an <code>&#39;x,y,w,h&#39;</code> string as well.</p><h3 id="232_h3_3_The-road-to-v0.4.0"><a href="http://publ.beesbuzz.biz/blog/232-v0.3.19-now-with-extra-tagging-goodness#232_h3_3_The-road-to-v0.4.0"></a>The road to v0.4.0</h3><p>A lot has changed in Publ since v0.3.0, and I feel like a v0.4.0 release is overdue. If I were doing proper <a href="https://semver.org">semantic versioning</a> we&rsquo;d be on, like, v2.29.0 by now, but I feel like Publ is more of a stream-of-updates thing than a scheduled-release thing. So the versioning scheme is pretty ad-hoc and more represents where I feel like Publ is in terms of being a Real Professional Publishing System vs. being a toy I made for myself.</p><p>So, I have two planned version milestones, <a href="https://github.com/PlaidWeb/Publ/milestone/2">v0.4</a> and <a href="https://github.com/PlaidWeb/Publ/milestone/3">v1.0</a>. v0.4 is roughly where I feel like it should be stable enough for use by people who are into having a stable system to work with and don&rsquo;t want to deal with fiddly stuff that&rsquo;s an artifact of things being developed ad-hoc, and v1.0 is more like, hey, let&rsquo;s get all of the Big Features done and also get it incredibly polished for large-scale adoption.</p><p>So, v0.4 is almost ready for release, I think, but v1.0 is going to be much further out, since it also involves much larger feature work (such as authenticated/private content), and likely I&rsquo;ll end up establishing a closer milestone for major feature work like that but for now I&rsquo;m just using 1.0 as a bucket for &ldquo;everything that makes this a compelling blogging platform&rdquo; (i.e. stuff to get people out of silos like LiveJournal or Facebook).</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>v0.3.18, now with better asset management!</title>
        <link href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management" rel="alternate" type="text/html" />
        <published>2019-02-27T21:38:41-08:00</published>
        <updated>2019-02-27T21:38:41-08:00</updated>
        <id>urn:uuid:43c58b8f-3bb5-5a52-b08f-2259e4455216</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>I&rsquo;ve just released v0.3.18, with the following changes:</p>
<ul>
<li>Add date grouping properties to <a href="http://publ.beesbuzz.biz/api/entry#date_grouper">entry</a></li>
<li>Add a <a href="http://publ.beesbuzz.biz/api/view#all_pages"><code>pages</code> property</a> to <code>view</code></li>
<li>Provide the current <code>category</code> object to the error handler</li>
<li>Support linking to non-image/non-entry local files</li>
<li>Added, then removed, some performance micro-optimizations that only caused problems</li>
</ul>
<p>More details about the major changes below!</p><p><mark>Update:</mark> I released a hotfix as 0.3.18.1 because there was a last-minute bug that snuck in while I was trying to silence a new pylint error. Oops.</p>

<h3 id="1253_h3_1_Local-file-links"><a href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#1253_h3_1_Local-file-links"></a>Local file links</h3><p>So, as I <a href="http://publ.beesbuzz.biz/blog/478-v0.3.15-Released-finally">mentioned previously</a>, right now a lot of my work on Publ is with the purpose of updating the website of the research lab I currently work at. There&rsquo;s a <em>lot</em> of content on the site and most of it isn&rsquo;t particularly well-structured. Much of the site involves collecting publications that lab members have been involved in, and also providing the supplemental materials thereof or even the full papers in some cases.</p><p>This means there&rsquo;s a lot of assets to manage, and they aren&rsquo;t all systematically-named. Or tracked. Or easy to track down.</p><p>One of the things I&rsquo;ve wanted to do <a href="http://publ.beesbuzz.biz/issue/141">for a while</a> is to support posting images which aren&rsquo;t necessarily images that PIL can handle (such as SVGs or the like), and with a lot of the refactoring I&rsquo;d done over link handling I realized that there isn&rsquo;t really anything fundamentally different about SVGs than, say, all sorts of file types &ndash; PDFs, Javascript, source code, and so on. So, I extended the model&rsquo;s <code>Image</code> type a bit to allow for &ldquo;images&rdquo; that aren&rsquo;t actually images. (Really I should rename the class to <code>Asset</code>, which maybe I&rsquo;ll do later on.)</p><p>So, after a bunch more refactoring of how links and images are handled, link resolution is much simpler and also supports <a href="http://publ.beesbuzz.biz/_file/3f815/9/boxes.svg">any file that&rsquo;s not covered by the index</a>. But it does it in a safe way! Rather than index every possible file, it only indexes files which are pointed to by an entry, and if that file isn&rsquo;t an image, it gets assigned a fictional filename which is (essentially) unguessable but humane, and then there&rsquo;s an asset-retrieval endpoint which retrieves the file.</p><p>The end result of this is that only links to files which have been linked to on the site are available via the <code>_file</code> endpoint &ndash; it shouldn&rsquo;t be possible for people to guess at file paths and get at internal data!</p><p>Anyway, now static assets which belong to an entry can just live along with that entry!</p><p>(Assets which belong to a template should still live in the <code>static/</code> directory, though. That&rsquo;s what it&rsquo;s for, after all.)</p><h3 id="1253_h3_2_entry.date_year-et-al"><a href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#1253_h3_2_entry.date_year-et-al"></a><code>entry.date_year</code> et al</h3><p>This is also a thing I added for the lab&rsquo;s site; I needed a convenient way to group publications by year, and realized that there are other use cases which call for this as well, such as structured archive pages on a blog or the like. I wasn&rsquo;t terribly happy with adding purpose-specific properties for this but I couldn&rsquo;t find a way to make Jinja group by the result of a callable, so this was a convenient compromise.</p><h3 id="1253_h3_3_view.pages"><a href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#1253_h3_3_view.pages"></a><code>view.pages</code></h3><p>This was an artifact of the first way I tried implementing year grouping &ndash; I thought, hey, maybe I&rsquo;ll just paginate by year and then iterate over the pages. This turned out to be <em>very</em> slow, however.</p><p>It might be a useful thing for someone, though, so I left it in. I don&rsquo;t recommend using it.</p><h3 id="1253_h3_4_Future-priorities"><a href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#1253_h3_4_Future-priorities"></a>Future priorities!</h3><p>A thing which keeps on coming up is the ability to add tags to entries, and specifically a way of <a href="http://publ.beesbuzz.biz/issue/22" title="wow that one's been open a while">filtering by tag</a>. I put in what I hope is a short-term hack on the applicable templates on the lab site which looks something like:</p><figure class="blockcode"><pre class="highlight" data-language="jinja2" data-line-numbers><span class="line" id="e1253cb1L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#e1253cb1L1"></a><span class="line-content">{% for entry in view.entries %}</span></span>
<span class="line" id="e1253cb1L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#e1253cb1L2"></a><span class="line-content">{% if my_tag in(entry.get_all(&#39;Tag&#39;)) %}</span></span>
<span class="line" id="e1253cb1L3"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#e1253cb1L3"></a><span class="line-content">{{entry.body}}</span></span>
<span class="line" id="e1253cb1L4"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#e1253cb1L4"></a><span class="line-content">{% endif %}</span></span>
<span class="line" id="e1253cb1L5"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#e1253cb1L5"></a><span class="line-content">{% endfor %}</span></span>
</pre></figure><p>but I&rsquo;d really like to be able to do something like:</p><figure class="blockcode"><pre class="highlight" data-language="jinja2" data-line-numbers><span class="line" id="e1253cb2L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#e1253cb2L1"></a><span class="line-content">{% for entry in view(tag=my_tag).entries %}</span></span>
<span class="line" id="e1253cb2L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#e1253cb2L2"></a><span class="line-content">{{entry.body}}</span></span>
<span class="line" id="e1253cb2L3"><a class="line-number" href="http://publ.beesbuzz.biz/blog/1253-v0.3.18-now-with-better-asset-management#e1253cb2L3"></a><span class="line-content">{% endfor %}</span></span>
</pre></figure><p>i.e. make the database do the work. This also enables a bunch of other useful stuff like being able to finally implement tag navigation for blogs and feeds and whatever.</p><p>I don&rsquo;t think it would be that hard to implement, but I just haven&rsquo;t gotten around to it, despite having a bunch of tags on my own blog entries already. It&rsquo;s not, like, urgently needed, but now I have an impetus to actually do it.</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>v0.3.15 Released (finally!)</title>
        <link href="http://publ.beesbuzz.biz/blog/478-v0.3.15-Released-finally" rel="alternate" type="text/html" />
        <published>2019-02-13T18:20:58-08:00</published>
        <updated>2019-02-13T18:20:58-08:00</updated>
        <id>urn:uuid:767b8caf-0007-5bea-b53e-e79cc44980d9</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>It&rsquo;s been a while since I&rsquo;ve had a chance to work on Publ, but the great thing is that I actually had a reason to work on it for my day job. Which is to say I&rsquo;m finally being paid to work on Publ. ;)</p><p>Changes since 0.3.14:</p>
<ul>
<li>Add requirement for Arrow 0.13.0 (<a href="http://publ.beesbuzz.biz/issue/41">issue 41</a>)</li>
<li>Fix a dumb tpyo that was the cause of <a href="http://publ.beesbuzz.biz/issue/158">issue 158</a></li>
<li>Don&rsquo;t rewrite DRAFT files; fixes <a href="http://publ.beesbuzz.biz/issue/137">137</a></li>
<li>Move sample-site files back to the library repo rather than in the doc repo</li>
<li>Fix the way we map malformed category URLs (<a href="http://publ.beesbuzz.biz/issue/156">issue 156</a>)</li>
<li>Update upstream library versions</li>
<li>Move version number to publ module</li>
<li>Allow empty slug-text in entry route (fixes <a href="http://publ.beesbuzz.biz/issue/161">161</a>)</li>
<li>Process HTML entries, to finally handle issues <a href="http://publ.beesbuzz.biz/issue/136">136</a> and <a href="http://publ.beesbuzz.biz/issue/154">154</a>.</li>
</ul>
<p>Some more information about that last one under the cut!</p>

<p>So, my day job is currently doing programming, IT, systems support, and general technology stuff for a research lab. This lab has a somewhat large website with a lot of specialized resources on it. This website used to be managed by Movable Type, but at some point it broke, and rather than fix MT, the site was just getting incrementally updated via hand-editing the HTML, which is&hellip; not particularly ideal.</p><p>Being a large Movable Type site, there&rsquo;s a lot of HTML-specific hacks that go into making it work with MT &ndash; this was, of course, the exact reason I wrote Publ to begin with, to have something like Movable Type but more flexible and less fragile.</p><p>But being so large means that a lot of the purpose-specific HTML stuff is not particularly easy to migrate over to Markdown in one fell swoop. There&rsquo;s a <em>lot</em> of special-case <code>&lt;span&gt;</code> and <code>&lt;div&gt;</code> tags as well as a <em>lot</em> of tables involved. Pandoc would not be able to deal with this en masse.</p><p>But also, because there&rsquo;s a lot of stuff with image links and PDFs and so on, it seemed like using plain ol&#39; HTML entries was not going to really cut it either.</p><p>So looking at my options, I saw two paths forward:</p>
<ol>
<li>Do the same thing I did on <a href="http://beesbuzz.biz/">beesbuzz.biz</a> and write a bunch of special-purpose import scripts to try to massage things into working with Publ, or</li>
<li>Finally implement HTML entry processing to make links and images work right in an HTML context</li>
</ol>
<p>2 seemed like a lot less work, so that&rsquo;s what I did.</p><p>Of course, I&rsquo;m still going to need to do a lot of massaging to the various files (replacing template boilerplate with entry headers, fixing internal links, etc.), but that&rsquo;s fairly easy to do with <a href="https://www.crummy.com/software/BeautifulSoup/">BeautifulSoup</a> and the like. I also have a working-ish database dump of Movable Type from before it broke and so I might be able to simply re-export the site in a Publ entry format instead, which I did some of in the beesbuzz migration as well although at the time I had basically no plain-HTML support so it was only a partial solution at the time, but it would work a lot better now I think.</p><p>Anyway, my hope is that this will finally prove out Publ as a collaborative site-management platform, as there are others in the lab who will be managing site content. Hopefully this will also become a means for me to see what the weak spots are for semi-technical users (who are good at git but not programmers).</p><p>There&rsquo;s a few other &ldquo;fun&rdquo; things to worry about in this case because the Apache configuration is a bit of a mess and there are URL mappings to a <em>bunch</em> of different apps running in the same domain root. But I don&rsquo;t think this will be a problem.</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>v0.3.11</title>
        <link href="http://publ.beesbuzz.biz/blog/392-v0.3.11" rel="alternate" type="text/html" />
        <published>2018-12-15T01:08:43-08:00</published>
        <updated>2018-12-15T01:08:43-08:00</updated>
        <id>urn:uuid:50e6e4d7-9db1-5365-a9df-97453bc559d7</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>v0.3.11 is now released, with the following changes:</p>
<ul>
<li>A more complete fix for how to handle image sets and inline images with respect to paragraphs</li>
<li>Better cleanup for spurious empty paragraphs</li>
<li>Improved internal entry link handling</li>
</ul>
<p>Detailed descriptions of the changes are below.</p>

<h2 id="392_h2_1_Improved-entry-link-handling"><a href="http://publ.beesbuzz.biz/blog/392-v0.3.11#392_h2_1_Improved-entry-link-handling"></a>Improved entry link handling</h2><p>Entry links used to just be pretty simplistic; for example,</p><p>previously an entry link like</p><figure class="blockcode"><pre class="highlight" data-language="markdown" data-line-numbers><span class="line" id="e392cb1L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb1L1"></a><span class="line-content">[<span class="nt">foo</span>](<span class="na">123</span>)</span></span>
</pre></figure><p>would just generate</p><figure class="blockcode"><pre class="highlight" data-language="html" data-line-numbers><span class="line" id="e392cb2L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb2L1"></a><span class="line-content"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;123&quot;</span><span class="p">&gt;</span>foo<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span></span></span>
</pre></figure><p>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&rsquo;re not supposed to). Now it will generate a link like:</p><figure class="blockcode"><pre class="highlight" data-language="html" data-line-numbers><span class="line" id="e392cb3L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb3L1"></a><span class="line-content"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;/example/123-some-foo&quot;</span><span class="p">&gt;</span>foo<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span></span></span>
</pre></figure><p>or, in an absolute context (e.g. a feed),</p><figure class="blockcode"><pre class="highlight" data-language="html" data-line-numbers><span class="line" id="e392cb4L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb4L1"></a><span class="line-content"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;http://example.com/example/123-some-foo&quot;</span><span class="p">&gt;</span>foo<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span></span></span>
</pre></figure><p>But the primary improvement here is that it will also resolve links to entries by filename; for example, all of the below should work:</p><figure class="blockcode"><pre class="highlight" data-language="markdown" data-line-numbers><span class="line" id="e392cb5L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb5L1"></a><span class="line-content">[<span class="nt">some other entry</span>](<span class="na">other-entry.md</span>)</span></span>
<span class="line" id="e392cb5L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb5L2"></a><span class="line-content">[<span class="nt">in a parent directory</span>](<span class="na">../other-entry.md</span>)</span></span>
<span class="line" id="e392cb5L3"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb5L3"></a><span class="line-content">[<span class="nt">relative to content root</span>](<span class="na">/blog/other-entry.md</span>)</span></span>
</pre></figure><p>You can see <del><a href="http://publ.beesbuzz.biz/_tests/relative entry links.md">some tests of this</a></del> (UPDATE: tests have been <a href="http://publ.beesbuzz.biz/blog/332-Tests-removed-from-main-site">removed from this repo</a>). This link was, of course, generated with <code>[some tests of this](/_tests/relative entry links.md)</code> (but using <a href="http://publ.beesbuzz.biz/blog/189">the entry ID</a> should still work as well).</p><p>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&rsquo;s end.</p><h2 id="392_h2_2_Thoughs-about-future-functionali"><a href="http://publ.beesbuzz.biz/blog/392-v0.3.11#392_h2_2_Thoughs-about-future-functionali"></a>Thoughs about future functionality</h2><p>One of the things I&rsquo;ve been wanting to add since the very beginning is private content; I&rsquo;ve rambled quite a lot about how I might support that in Atom <a href="https://beesbuzz.biz/blog/4594-The-authenticated-Atom-musings-continue">over on my personal blog</a>. But I haven&rsquo;t really talked about how this will go into Publ itself.</p><p>The changes to URL resolution got me thinking a lot about the whole &ldquo;public links to private entries&rdquo; 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 <a href="http://publ.beesbuzz.biz/blog/135-v0.3.10-released">changes to caching</a> already make it so that I don&rsquo;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.</p><p>And I think that the data privacy model can be that the <code>Entry</code> object itself knows about auth &ndash; for example, it will know who the logged-in user is and whether they have access to the entry &ndash; 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 <code>/id</code> link, so no information about it leaks through that either.</p><p>There will of course be a couple of APIs to add in order to improve the view for unauthorized content, though; I&rsquo;ll probably add a property to <code>Entry</code> to indicate whether the entry is unauthorized (so the template can show a &ldquo;please log in&rdquo; thing or whatever), and then <code>view.entries</code>, <code>entry.next</code>, and <code>entry.previous</code> will gain an <code>unauthorized</code> parameter to decide whether unauthorized content should be shown in the first place. So in fact the placeholder entries wouldn&rsquo;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&rsquo;t).</p><p><code>View</code> will also probably get a <code>needs_auth</code> property, which will return <code>True</code> if the user isn&rsquo;t identified <em>and</em> there&rsquo;s private content that would appear in the view. That way, if someone isn&rsquo;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 <code>&lt;link rel=&quot;auth&quot;&gt;</code> or whatever).</p><p>Authentication itself, by the way, will absolutely be handled via <a href="https://indieweb.org/IndieAuth">IndieAuth</a> and <a href="https://indieweb.org/AutoAuth">AutoAuth</a>.</p><p>From a publisher&rsquo;s perspective I see it working like this:</p><p>First, there will be a metadata file in some as-yet-undetermined format (probably YAML or JSON) that has mappings like e.g.:</p><figure class="blockcode"><pre class="highlight" data-language="yaml" data-line-numbers><span class="line" id="e392cb6L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L1"></a><span class="line-content"><span class="nt">http://beesbuzz.biz/</span><span class="p">:</span><span class="w"> </span><span class="c1"># that&#39;s me!</span></span></span>
<span class="line" id="e392cb6L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L2"></a><span class="line-content"><span class="w">    </span><span class="l l-Scalar l-Scalar-Plain">_admin</span></span></span>
<span class="line" id="e392cb6L3"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L3"></a><span class="line-content"><span class="w">    </span><span class="l l-Scalar l-Scalar-Plain">friends</span></span></span>
<span class="line" id="e392cb6L4"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L4"></a><span class="line-content"><span class="w">    </span><span class="l l-Scalar l-Scalar-Plain">private</span></span></span>
<span class="line" id="e392cb6L5"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L5"></a><span class="line-content"><span class="nt">http://example.com/larry</span><span class="p">:</span><span class="w"> </span><span class="c1"># Larry from high school</span></span></span>
<span class="line" id="e392cb6L6"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L6"></a><span class="line-content"><span class="w">    </span><span class="l l-Scalar l-Scalar-Plain">enemies</span></span></span>
<span class="line" id="e392cb6L7"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L7"></a><span class="line-content"><span class="nt">http://example.com/alice</span><span class="p">:</span><span class="w"> </span><span class="c1"># Alistair</span></span></span>
<span class="line" id="e392cb6L8"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L8"></a><span class="line-content"><span class="w">    </span><span class="l l-Scalar l-Scalar-Plain">private</span></span></span>
<span class="line" id="e392cb6L9"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L9"></a><span class="line-content"><span class="w">    </span><span class="l l-Scalar l-Scalar-Plain">enemies</span><span class="w">  </span><span class="c1"># I&#39;m not talking to them right now...</span></span></span>
<span class="line" id="e392cb6L10"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L10"></a><span class="line-content"><span class="nt">http://example.com/nancy</span><span class="p">:</span></span></span>
<span class="line" id="e392cb6L11"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb6L11"></a><span class="line-content"><span class="w">    </span><span class="l l-Scalar l-Scalar-Plain">private</span></span></span>
</pre></figure><p>Next, private entries will get a header that indicates which identities or groups have (or don&rsquo;t have) access; for an over-complicated example:</p><figure class="blockcode"><pre class="highlight" data-language="email" data-line-numbers><span class="line" id="e392cb7L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/392-v0.3.11#e392cb7L1"></a><span class="line-content"><span class="nt">Private:</span><span class="w"> </span>private<span class="w"> </span>!enemies<span class="w"> </span>http://<span class="nf">example.com</span>/fred<span class="w"> </span>!http://<span class="nf">example.com</span>/nancy</span></span>
</pre></figure><p>which means that people in the &ldquo;private&rdquo; group can see it, unless they&rsquo;re in the &ldquo;enemies&rdquo; group, and also let Fred (who isn&rsquo;t in a group) to this entry, but don&rsquo;t allow Nancy to see it even though she&rsquo;s in the private group. (I would also probably have a special token <code>*</code> which matches anyone who has a known identity, whether they&rsquo;re in a group or not, mostly for the purpose of showing a login/logout widget on the sidebar or whatever.)</p><p>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 <code>_admin</code> group) that shows all of the information about recent access. Most likely the user table will simply have a <code>last_seen</code> column.)</p><p>Open questions:</p>
<ul>
<li>Would it be useful to assign access groups on a per-category basis, or does that just needlessly overcomplicate things?</li>
<li>What about access at the category level itself? (also probably overcomplicated)</li>
<li><p>Are there any IndieAuth endpoints out there which let people log in directly with particular OAuth identities?</p><p>Like, it&rsquo;s really annoying to require people to authenticate with a profile page that has a bidirectional <code>rel=&quot;me&quot;</code> relationship to one of the common OAuth providers (GitHub, Twitter, etc.), but none of the endpoints I&rsquo;ve seen let you just provide that provider <em>as</em> your profile link in the first place. And this presents a big barrier to entry, IMO.</p><p>It&rsquo;d also be great if these endpoints were to widen their net; so far I only see support for GitHub and Twitter, but there&rsquo;s a <em>ton</em> of folks using Mastodon now, for example.</p></li>
<li><p>How the heck am I going to test IndieAuth login while I&rsquo;m working on it? I guess I could spin up another Publ instance on my server, ugh&hellip;</p></li>
</ul>
<p>Anyway, I am pretty excited about how having proper private blogging feels like it&rsquo;s actually within my grasp!</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>v0.3.9 Released</title>
        <link href="http://publ.beesbuzz.biz/blog/1052-v0.3.9-Released" rel="alternate" type="text/html" />
        <published>2018-11-28T15:33:23-08:00</published>
        <updated>2018-11-29T00:17:53+00:00</updated>
        <id>urn:uuid:28866e54-16f4-58b5-bcfb-23111ec4e150</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>This entry marks the release of Publ v0.3.9. It has the following changes:</p>
<ul>
<li>Added <code>more_text</code> and related functionality to <a href="http://publ.beesbuzz.biz/image-renditions">image sets</a> (an example being visible <a href="http://publ.beesbuzz.biz/blog/?id=249">over here</a>)</li>
<li>Improved and simplified the caching behavior (fixing some fiddly cases around how ETags and last-modified worked, or rather <em>didn&rsquo;t</em>)</li>
</ul>
<p>I also made, and then soon reverted, a change around how entry IDs and publish dates were automatically assigned to non-published entries. I thought it was going to simplify some workflow things but it only complicated the code and added more corner cases to deal with, all for something that doesn&rsquo;t <em>actually</em> address the use case I was worried about. So never mind on that.</p><p>(What happened to v0.3.8? I goofed and forgot to merge the completed <code>more_text</code> et al changes into my build system first. Oops.)</p><p>See below for more on the caching changes.</p>

<p>Previously, I was trying to compute the ETag and Last-Modified for every page based on a rather conservative metric; basically it would try to find the most recently-modified file that was likely to affect the rendering of a page, and generate an ETag based on its file metadata and a Last-Modified based on its file modification time.</p><p>But determining which files were likely to contribute to the output is hard to do without simply running the template system, so it tried building a bunch of heuristics. And in the end it still ended up making it so that pretty much everything on the site either got the same ETag as everything else (making it not very useful for things that work by spidering the site, such as Pushl) or had a non-useful Last-Modified and this still required considerable file I/O to do.</p><p>Also it turned out that some of the caching logic was possibly doing weird things with the way that Flask-Caching works.</p><p>Now what I do is I just generate the page text and compute a hash of said text, and cache those together at the <em>template</em> rendering level, rather than at the route level. This turns out to be nearly as fast on a cache miss, and significantly faster on a cache hit, <em>and</em> the cache hits are themselves way more cacheable and there&rsquo;s fewer edge cases to worry about and so on.</p><p>I also got rid of the Last-Modified check because anything which cares about this will be using an ETag anyway, and Last-Modified logic is hard to get right.</p><p>There&rsquo;s probably a few things that could now be more efficient but those feel like micro-optimizations; for example, path redirection logic is no longer cached (but it&rsquo;s pretty fast anyway), and I feel like making the website itself more cacheable (and more <em>correctly</em> cacheable) is worth it.</p><p>At some point I do need to run some sort of profiling tool on Publ to see where any actual code bottlenecks are; right now I mostly do smoke-test-type benchmarking and occasionally check to make sure my main website isn&rsquo;t taking up significant CPU. I&rsquo;d love to see if there&rsquo;s any low-hanging fruit to make it scale even better though.</p><p><mark>Update:</mark> Now that my sites are deployed on the new version, I can share some interesting timing information.</p><p>Before, a Pushl update of beesbuzz.biz and publ.beesbuzz.biz took around 45 seconds, mostly spent downloading every single entry (because caching is hard).</p><p>After, a Pushl update takes around 4 seconds. Meaning, it&rsquo;s 10x faster &ndash; all because it can cache smarter and can simply ignore the vast majority of the feed content!</p><p>(And most of the time it takes is actually spent spinning up the <code>pipenv</code>.)</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>v0.3.3 - now with ETag and Last-Modified</title>
        <link href="http://publ.beesbuzz.biz/blog/121-v0.3.3-now-with-ETag-and-Last-Modified" rel="alternate" type="text/html" />
        <published>2018-10-01T23:16:28-07:00</published>
        <updated>2018-10-01T23:16:28-07:00</updated>
        <id>urn:uuid:6be6aebc-4646-559f-b427-a670ba4132f4</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>I&rsquo;ve started working on <a href="http://github.com/PlaidWeb/Pushl">Pushl</a> in earnest now, and one thing that was really bugging me about this is that anything which polls feeds and entries would really benefit from having client-side cache control working. Which was a big missing feature in Publ.</p><p>Well, I finally implemented it, and I&rsquo;m <a href="https://github.com/PlaidWeb/Publ/pull/130">pretty happy with how I did it</a>.</p><p>The short version: for any given view it figures out (pessimistically) what&rsquo;s the most recent file that would have affected the view (well, within reason; it only looks at the current template rather than any included templates, which is pretty difficult to do correctly) and uses that to generate an ETag (via metadata fingerprint) and a Last-Modified time (based either on the file modification time or the time the entry was actually published).</p><p>There&rsquo;s probably a few corner cases this misses but in general this makes client-side caching of feeds and such work nicely.</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>v0.3.2: a smol bugfix release</title>
        <link href="http://publ.beesbuzz.biz/blog/307-v0.3.2-a-smol-bugfix-release" rel="alternate" type="text/html" />
        <published>2018-09-25T14:55:10-07:00</published>
        <updated>2018-09-25T14:55:10-07:00</updated>
        <id>urn:uuid:5fe5f5fe-a201-5919-a071-414675d93520</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>I found a few more annoying bugs that were shaken out from the whole PonyORM transition, as well as a couple of bugs in the new <a href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1">shape functionality</a>. There&rsquo;s probably a few more of these bugs lurking in the codebase (I mean, in addition to the <a href="http://github.com/fluffy-critter/Publ/issues">existing bugs I know about</a>), but here&rsquo;s what&rsquo;s changed:</p>
<ul>
<li>Image shape bugs:

<ul>
<li>Fix some <code>FileNotFound</code> handling on images (so <code>shape</code> errors propagate correctly)</li>
<li>Make <code>img_class</code> and <code>class</code> work correctly per the documentation</li>
</ul></li>
<li>PonyORM bugs:

<ul>
<li>Put pessimistic lock around all get-or-creates, (hopefully fixing) <a href="https://github.com/fluffy-critter/Publ/issues/126">a transitory indexing error</a></li>
<li>Fix an error where <a href="https://github.com/fluffy-critter/Publ/issues/127">incomplete category paths weren&rsquo;t forwarding correctly</a></li>
</ul></li>
</ul>


<p>That last one is something where there&rsquo;s probably a few other lurking similar things in the codebase; peewee allows you to check for the existence of any matching record with:</p><figure class="blockcode"><pre class="highlight" data-language="python" data-line-numbers><span class="line" id="e307cb1L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/307-v0.3.2-a-smol-bugfix-release#e307cb1L1"></a><span class="line-content"><span class="n">record</span> <span class="o">=</span> <span class="n">ModelClass</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="n">value</span><span class="p">)</span></span></span>
<span class="line" id="e307cb1L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/307-v0.3.2-a-smol-bugfix-release#e307cb1L2"></a><span class="line-content"><span class="k">if</span> <span class="n">record</span><span class="p">:</span></span></span>
<span class="line" id="e307cb1L3"><a class="line-number" href="http://publ.beesbuzz.biz/blog/307-v0.3.2-a-smol-bugfix-release#e307cb1L3"></a><span class="line-content">    <span class="c1"># a record exists</span></span></span>
</pre></figure><p>which happens to also be a valid expression in PonyORM (one of the few places where they have API in common), <em>but</em> PonyORM only lets you use <code>get</code> to retrieve a single value. In PonyORM you instead have to do something a bit different to see if <em>any</em> item matches; for example, this is what Publ does now:</p><figure class="blockcode"><pre class="highlight" data-language="python" data-line-numbers><span class="line" id="e307cb2L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/307-v0.3.2-a-smol-bugfix-release#e307cb2L1"></a><span class="line-content"><span class="k">if</span> <span class="n">pony</span><span class="o">.</span><span class="n">orm</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="n">e</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">ModelClass</span> <span class="k">if</span> <span class="n">e</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">value</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span></span></span>
<span class="line" id="e307cb2L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/307-v0.3.2-a-smol-bugfix-release#e307cb2L2"></a><span class="line-content">    <span class="c1"># a record exists</span></span></span>
</pre></figure><p>which happens to be somewhat more efficient (although it&rsquo;s basically a micro-optimization).</p><p>I suppose I should simply audit all uses of <code>.get()</code> since <em>most</em> of them are for single-item lookups but there&rsquo;s probably a few places where I&rsquo;m using it as a rough <code>.exists()</code> equivalent, which was never really great anyway.</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>The shape of the float (v0.3.1)</title>
        <link href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1" rel="alternate" type="text/html" />
        <published>2018-09-20T22:58:10-07:00</published>
        <updated>2018-09-20T22:58:10-07:00</updated>
        <id>urn:uuid:fe9982b7-455a-52ee-8007-db46c4f63ad4</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p><a href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1"><img src="http://publ.beesbuzz.biz/static/_img/88/afb1/woo-ghost_73933777ff.png" width="182" height="195" loading="lazy" class="inset-right" style="shape-outside: url('http://publ.beesbuzz.biz/static/_img/88/afb1/woo-ghost_73933777ff.png')" alt="woo-ghost.png" title="a tightly-wrapped ghost!"></a></p><p>Did you know that CSS3 has a style called <code>shape-outline</code>? It&rsquo;s pretty neat, it makes it so that a floated object gets a shape based on the alpha channel of its specified image. But it&rsquo;s kind of a pain to set up; in plain HTML it looks something like this:</p><figure class="blockcode"><pre class="highlight" data-language="html" data-line-numbers><span class="line" id="e660cb1L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb1L1"></a><span class="line-content"><span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;/path/to/image.png&quot;</span> <span class="na">width</span><span class="o">=</span><span class="s">&quot;320&quot;</span> <span class="na">height</span><span class="o">=</span><span class="s">&quot;320&quot;</span></span></span>
<span class="line" id="e660cb1L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb1L2"></a><span class="line-content">    <span class="na">style</span><span class="o">=</span><span class="s">&quot;shape-outline:url(&#39;/path/to/image.png&#39;);float: left&quot;</span><span class="p">&gt;</span></span></span>
</pre></figure><p>and if you want a different shape mask for your image than its own alpha channel, you have to do a bunch of stuff like making sure that the image sizes are the same and whatever.</p>

<p><a href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1"><img src="http://publ.beesbuzz.biz/static/_img/b5/0098/rawr_fe8a4fcea1_320x235.jpg" width="320" height="235" srcset="http://publ.beesbuzz.biz/static/_img/b5/0098/rawr_fe8a4fcea1_320x235.jpg 1x, http://publ.beesbuzz.biz/static/_img/b5/0098/rawr_fe8a4fcea1.jpg 2x" loading="lazy" class="inset-left" style="shape-outside: url('http://publ.beesbuzz.biz/static/_img/90/cc67/rawr-mask_fd223776fc_320x235.png')" alt="rawr.jpg" title="rawr, now with extra wrapping"></a></p><p>But in Publ there is now an additional attribute you can set on an image, <code>shape</code>, which is, I think, <a href="http://publ.beesbuzz.biz/image-renditions#style">pretty easy to work with</a>.</p><p>For example, the code for the little ghost in the intro is just:</p><figure class="blockcode"><figcaption><a href="http://publ.beesbuzz.biz/static/_img/88/afb1/woo-ghost_73933777ff.png"></a></figcaption><pre class="highlight" data-language="markdown" data-line-numbers><span class="line" id="e660cb2L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb2L1"></a><span class="line-content"></span></span>
</pre></figure><p>and the code for this rawr right here is:</p><figure class="blockcode"><figcaption><a href="http://publ.beesbuzz.biz/static/_img/b5/0098/rawr_fe8a4fcea1_320x235.jpg"></a></figcaption><pre class="highlight" data-language="markdown" data-line-numbers><span class="line" id="e660cb3L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb3L1"></a><span class="line-content"></span></span>
</pre></figure><p>See, the rawr image is a .jpg file (which is why its box still overwrites the code blocks here, since there&rsquo;s no transparency), and it&rsquo;s pretty sparse, so I made a mask image for it, which looks like this:</p><p><a href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1"><img src="http://publ.beesbuzz.biz/static/_img/90/cc67/rawr-mask_fd223776fc_320x235.png" width="320" height="235" srcset="http://publ.beesbuzz.biz/static/_img/90/cc67/rawr-mask_fd223776fc_320x235.png 1x, http://publ.beesbuzz.biz/static/_img/90/cc67/rawr-mask_fd223776fc.png 2x" loading="lazy" alt="rawr-mask.png" title="the rawr mask"></a></p><p>On that note I also fixed a bug where you couldn&rsquo;t add a background to a transparent paletted PNG (oops).</p><p><a href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1"><img src="http://publ.beesbuzz.biz/static/_img/02/68fa/notsmiley_72735c3f5a_200x200.png" width="200" height="200" srcset="http://publ.beesbuzz.biz/static/_img/02/68fa/notsmiley_72735c3f5a_200x200.png 1x, http://publ.beesbuzz.biz/static/_img/02/68fa/notsmiley_72735c3f5a_400x400.png 2x" loading="lazy" class="inset-left" style="shape-outside: url('http://publ.beesbuzz.biz/static/_img/90/cc67/rawr-mask_fd223776fc_200x147.png')" alt="notsmiley.png" title="a smiley shaped like a rawr"></a><a href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1"><img src="http://publ.beesbuzz.biz/static/_img/b5/0098/rawr_fe8a4fcea1_200x147.jpg" width="200" height="147" srcset="http://publ.beesbuzz.biz/static/_img/b5/0098/rawr_fe8a4fcea1_200x147.jpg 1x, http://publ.beesbuzz.biz/static/_img/b5/0098/rawr_fe8a4fcea1_400x293.jpg 2x" loading="lazy" class="inset-right" style="shape-outside: url('http://publ.beesbuzz.biz/static/_img/02/68fa/notsmiley_72735c3f5a_200x200.png')" alt="rawr.jpg" title="a rawr shaped like a smiley"></a></p><p>You can also mix-and-match shapes and masks, as I have done here where the not-smiley has the rawr mask and vice-versa. This can get really confusing, especially if the images are different sizes, but Publ attempts to make a best attempt to size them consistently with one another. You might just want to always have your mask image have the same aspect ratio as the base image, however, just to keep things a bit more sensible. Also I am mostly writing this extra-verbose text to have extra stuff to wrap around the images. While I&rsquo;m here I&rsquo;d might as well mention that mask images can come from any of the same sources as rendition images, <em>but</em> non-rendition images won&rsquo;t be subject to the same sizing (as CSS3 does not provide any means of resizing the outline) so for example if you have your mask stored as a static image (i.e. <code>@layout/thing-mask.png</code>) it <em>won&rsquo;t</em> be scaled along with the image as it&rsquo;s being laid out. Although if the image being laid out is also a static image then it may or may not actually be sized at the same scale. I&rsquo;m not sure; the spec is pretty vague about this and kind of handwaves about it. So really you only want to set shape masks on local/rendered images, and most of the time you&rsquo;ll probably want to use the simple <code>shape=True</code> form since that&rsquo;s the easiest to deal with.</p><p>And, note that the output shape will always be in the same format as the input image (i.e. a .png or a .gif or whatever), regardless of the ouput format set on the image tag; for example, <code>![](foo.png{shape=True,format=&#39;jpg&#39;})</code> will still serve up a PNG of the image. If your PNG is big (and that&rsquo;s why you&rsquo;re telling it to render as a JPEG), your shape mask will also be pretty big. So, for shaped images it&rsquo;s often a good idea to make a separate PNG8 for the shape mask anyway.</p><p>I have considered making the shape mask only write out a monochrome PNG that only preserves the shape in the alpha channel, but I wanted to keep support for one of the other CSS attributes, <code>shape-image-threshold</code>, which lets you specify the alpha threshold to use for the mask. Always flattening to a monochrome PNG wouldn&rsquo;t allow for that. So, I opted to keep it simple for now, but this is certainly something to possibly revisit later. Perhaps as a compromise I&rsquo;ll make it an RGBA PNG that is filled only with a solid color but preserves the original alpha channel.</p><p>Anyway! With all that said, you still need to set the stylesheet rules yourself. Well, you don&rsquo;t <em>need</em> to; you can certainly do something like:</p><figure class="blockcode"><figcaption><a href="http://publ.beesbuzz.biz/blog/foo.png{style=&#34;float:left&#34;,shape=True}"></a></figcaption><pre class="highlight" data-language="markdown" data-line-numbers><span class="line" id="e660cb4L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb4L1"></a><span class="line-content"></span></span>
</pre></figure><p>but for a nice responsive design you should instead do:</p><figure class="blockcode"><figcaption><a href="http://publ.beesbuzz.biz/blog/foo.png{img_class=&#34;inset-left&#34;,shape=True}"></a></figcaption><pre class="highlight" data-language="markdown" data-line-numbers><span class="line" id="e660cb5L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb5L1"></a><span class="line-content"></span></span>
</pre></figure><p>and then have a CSS rule like, for example:</p><figure class="blockcode"><pre class="highlight" data-language="css" data-line-numbers><span class="line" id="e660cb6L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb6L1"></a><span class="line-content"><span class="p">.</span><span class="nc">inset-left</span><span class="w"> </span><span class="p">{</span></span></span>
<span class="line" id="e660cb6L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb6L2"></a><span class="line-content"><span class="w">    </span><span class="k">float</span><span class="p">:</span><span class="w"> </span><span class="kc">left</span><span class="p">;</span></span></span>
<span class="line" id="e660cb6L3"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb6L3"></a><span class="line-content"><span class="w">    </span><span class="k">shape-margin</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="kt">ex</span><span class="p">;</span></span></span>
<span class="line" id="e660cb6L4"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb6L4"></a><span class="line-content"><span class="w">    </span><span class="k">margin</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="kt">ex</span><span class="p">;</span></span></span>
<span class="line" id="e660cb6L5"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb6L5"></a><span class="line-content"><span class="p">}</span></span></span>
</pre></figure><p>and then you have the ability to override that rule with <code>@media</code> queries or whatever.</p><p>Anyway, if you want to diagnose the shape margins, most modern browsers&#39; DOM/element/etc. inspectors will show you both the outline and its margin; for example, here&rsquo;s Safari&rsquo;s DOM inspector showing the outline of the ghost:</p><p><a href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1"><img src="http://publ.beesbuzz.biz/static/_img/55/79f8/ghost-inspector_dd3cf70bce_214x211.png" width="214" height="211" srcset="http://publ.beesbuzz.biz/static/_img/55/79f8/ghost-inspector_dd3cf70bce_214x211.png 1x, http://publ.beesbuzz.biz/static/_img/55/79f8/ghost-inspector_dd3cf70bce_428x423.png 2x" loading="lazy" alt="ghost-inspector.png" title="the ghost's shape"></a></p><p>Anyway, the astute observer of the above might notice two new image format options, <code>img_class</code> and <code>style</code>. Previously there was only <code>div_class</code> which adds a style rule to the image set container, but <code>img_class</code> adds a CSS class to the individual <code>&lt;img&gt;</code> tags, and <code>style</code> adds a CSS rule to the image (but not to the <code>div</code>); <code>img_style</code> is also an alias for <code>style</code>. And, for the sake of symmetry I also added <code>div_style</code> even though it probably should never be used. If both <code>style</code> and <code>img_style</code> are specified, they will be combined together.</p><p>Note that the stacking behavior for these attributes can be a little counterintuitive. For an example of how this works:</p><figure class="blockcode"><figcaption>[{div<em>class=&ldquo;foo&rdquo;,img</em>class=&ldquo;bar&rdquo;,img<em>style=&ldquo;top img</em>style&rdquo;,style=&ldquo;top style&rdquo;}](</figcaption><pre class="highlight" data-language="markdown" data-line-numbers><span class="line" id="e660cb7L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb7L1"></a><span class="line-content">img-1.png{img_style=&quot;inner img_style&quot;} |</span></span>
<span class="line" id="e660cb7L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb7L2"></a><span class="line-content">    img-2.png{style=&quot;inner style&quot;}</span></span>
<span class="line" id="e660cb7L3"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb7L3"></a><span class="line-content">    )</span></span>
</pre></figure><p>becomes (roughly):</p><figure class="blockcode"><pre class="highlight" data-language="html" data-line-numbers><span class="line" id="e660cb8L1"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb8L1"></a><span class="line-content"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;foo&quot;</span><span class="p">&gt;</span></span></span>
<span class="line" id="e660cb8L2"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb8L2"></a><span class="line-content"><span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;img-1.png&quot;</span> <span class="na">style</span><span class="o">=</span><span class="s">&quot;inner img_style;top style&quot;</span><span class="p">&gt;</span></span></span>
<span class="line" id="e660cb8L3"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb8L3"></a><span class="line-content"><span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;img-2.png&quot;</span> <span class="na">style</span><span class="o">=</span><span class="s">&quot;top img_style;inner style&quot;</span><span class="p">&gt;</span></span></span>
<span class="line" id="e660cb8L4"><a class="line-number" href="http://publ.beesbuzz.biz/blog/660-The-shape-of-the-float-v0.3.1#e660cb8L4"></a><span class="line-content"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span>
</pre></figure><p>which is to say, <code>img_style</code> and <code>style</code> both override individually and then at the end they combine together. I am sure there is something useful for someone in here, but honestly I don&rsquo;t really care for the idea of people setting inline styles in the first place, so I&rsquo;m not too concerned about how crappy <a href="http://publ.beesbuzz.biz/image-renditions">the docs</a> are at the moment.</p><p>Anyway, if you really want to use <code>img_style</code> and <code>style</code> my general guidance would be:</p>
<ul>
<li>Put <code>div_style</code> and <code>img_style</code> in the alt-text section (i.e. in the <code>[]</code>s)</li>
<li>Put <code>style</code> in on the individual images (i.e. the <code>()</code>s)</li>
</ul>
<p>&hellip; and oh god I&rsquo;m just realizing how terrible my docs are and how much I&rsquo;d love to have an end-user of Publ to actually give doc feedback or maybe a proper technical writer to write the docs to make a lick of sense to someone who isn&rsquo;t me. Sigh.</p><p>Anyway, tl;dr: Publ now makes it easy to tightly wrap text around floated images.</p><p>Oh, and I also fixed a regression in the PonyORM migration that made <code>DRAFT</code> and <code>DELETED</code>/<code>GONE</code> publish statuses not work right. Oops.</p>

]]>
        </content>
    </entry>
    

    
</feed>