💾 Archived View for gemini.conman.org › extensions › GLV-1 › handlers › blog.lua captured on 2021-12-03 at 14:04:38.

View Raw

More Information

⬅️ Previous capture (2020-10-31)

➡️ Next capture (2021-12-17)

🚧 View Differences

-=-=-=-=-=-=-

-- ***********************************************************************
--
-- Copyright 2020 by Sean Conner.
--
-- This program is free software: you can redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the
-- Free Software Foundation, either version 3 of the License, or (at your
-- option) any later version.
--
-- This program is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-- Public License for more details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program.  If not, see <http://www.gnu.org/licenses/>.
--
-- Comments, questions and criticisms can be sent to: sean@conman.org
--
-- =======================================================================
--
-- Code to handle blog requests.
--
-- ***********************************************************************
-- luacheck: globals init handler
-- luacheck: ignore 611 631

local syslog   = require "org.conman.syslog"
local date     = require "org.conman.date"
local url      = require "org.conman.parsers.url.data"
               + require "org.conman.parsers.url.gopher"
               + require "org.conman.parsers.url"
local io       = require "io"
local os       = require "os"
local string   = require "string"
local readfile = require "GLV-1.handlers.file"
local html     = require "org.conman.app.port70.handlers.blog.html"
local uurl     = require "GLV-1.url-util" -- "org.conman.app.port70.handlers.blog.url-util"
local format   = require "org.conman.app.GLV-1.handlers.blog.format"
local blog     = require "org.conman.app.mod_blog"

local require  = require
local ipairs   = ipairs
local tonumber = tonumber

_ENV = {}

-- ***********************************************************************
-- usage:       init()
-- desc:        Intialize the handler module
-- ***********************************************************************

function init(conf)
  conf.blog = blog.init(conf.config)
  conf.url  = url:match(conf.url)
  return true
end

-- ***********************************************************************

function handler(config,_,_,match,ios)
  local first = blog.bookend("first")
  local last  = blog.bookend("last")
  local port do
    if config.url.port == 1965 then
      port = ""
    else
      port = string.format(":%d",config.url.port)
    end
  end
  
  -- ----------------------------------------------------------------
  
  local function affiliate(location)
    for _,aff in ipairs(config.blog.affiliate) do
      if location.scheme == aff.proto then
        return string.format(aff.link,location.path)
      end
    end
    return uurl.toa(location)
  end
  
  -- ----------------------------------------------------------------
  
  local function xlat_links(when,links)
    for i,link in ipairs(links) do
      local u = url:match(link)
      
      if u.scheme then
        local ltxt = affiliate(u)
        ios:write(string.format("=> %s [%d] %s\n",ltxt,i,ltxt))
        
      else
        local t = blog.tumbler.new(link,first,last)
        if t then
          local ltxt = config.url.path .. link
          ios:write(string.format("=> %s [%d] %s\n",ltxt,i,ltxt))
        else
          if link:match "^/" then
            if link:find("/thisday",1,true) then
              local ltxt = config.url.path .. link:sub(2,-1)
              ios:write(string.format("=> %s [%d] %s\n",ltxt,i.ltxt))
            else
              ios:write(string.format("[%d] %s%s\n",i,config.blog.url,link:sub(2,-1)))
            end
          else
            if link:find("parallel/",1,true) then
              ios:write(string.format("[%d] %s%s\n",i,config.blog.url,link))
            else
              local filename = string.format(
                "%s%04d/%02d/%02d/%s",
                config.url.path,
                when.year,
                when.month,
                when.day,
                link
              )
              ios:write(string.format("=> %s [%d] %s\n",filename,i,filename))
            end
          end
        end
      end
    end
  end
  
  -- ----------------------------------------------------------------
  
  local function display(tumbler)
    local function geminilink(entry)
      return string.format("gemini://%s%s/%s%04d/%02d/%02d.%d",
                config.url.host,
                port,
                config.url.path,
                entry.when.year,
                entry.when.month,
                entry.when.day,
                entry.when.part
        )
    end
    
    for entry in blog.entries(tumbler) do
      local x = html(entry.body)
      local text,links = format(x)
      ios:write("# ",entry.title,"\n")
      
      if tumbler.range then
        ios:write("## ",os.date("%A, %B %d, %Y",os.time(tumbler.start)),"\n")
        ios:write("=> ",geminilink(entry),"\n\n")
      end
      
      ios:write(text)
      xlat_links(tumbler.start,links)
      ios:write("\n")
    end
    return 20
  end
  
  -- ----------------------------------------------------------------
  
  local function thisday(req)
    local month,day = req:match("^thisday/?(%d+)/(%d+)")
    if not month then
      local now = os.date("*t")
      month = now.month
      day   = now.day
    else
      month = tonumber(month)
      day   = tonumber(day)
    end
    
    local bytes = ios.__wbytes
    
    for year = first.year , last.year do
      local x = string.format("%04d/%02d/%02d",year,month,day)
      local tumbler = blog.tumbler.new(x,first,last)
      if tumbler then
        tumbler.range = true
        display(tumbler)
      end
    end
    
    if ios.__wbytes == bytes then
      ios:write("There are no entries for this date.\n")
    end
    
    return 20
  end
  
  -- ----------------------------------------------------------------
  -- If the request is empty, display the year menu
  -- ----------------------------------------------------------------
  
  if match[2] == "" then
    ios:write("20 text/gmeini\r\n")
    for i = last.year , first.year , -1 do
      ios:write(string.format("=> %s%04d %04d\n",config.url.path,i,i))
    end
    return 20
  end
  
  -- ----------------------------------------------------------------
  -- There's a tumbler.  Parse and handle
  -- ----------------------------------------------------------------
  
  local tumbler = blog.tumbler.new(match[2],first,last)
  if not tumbler then
    if match[2]:match "^thisday" then
      ios:write("20 text/gemini\r\n")
      return thisday(match[2])
    else
      ios:write("51\r\n")
      return 51
    end
  end
  
  if tumbler.redirect then
    ios:write(string.format("31 %s%s\r\n",config.url.path,blog.tumbler.canonical(tumbler)))
    return 31
  end
  
  if tumbler.file and tumbler.filename ~= "" then
    local filename = blog.filename(tumbler)
    if filename:match("%.x%-html$") then
      local f,err = io.open(filename,"rb")
      if not f then
        syslog('error',"%s: %s",filename,err)
        ios:write("51\r\n")
        return 51
      end
      
      ios:write("20 text/gemini\r\n")
      local text,links = format(html(f:read("a")))
      ios:write(text)
      xlat_links(tumbler.start,links)
      f:close()
      return 20
    else
      local conf = { file = blog.filename(tumbler) }
      readfile.init(conf)
      return readfile.handler(conf,_,_,_,ios)
    end
    
  elseif tumbler.range then
    ios:write("20 text/gemini\r\n")
    return display(tumbler)
    
  elseif tumbler.ustart == 'year' then
    local when = { year = tumbler.start.year , month = 1 , day = 1 }
    ios:write("20 text/gemini\r\n")
    
    for i = 1 , 12 do
      if tumbler.start.year == first.year and i                  >= first.month
      or tumbler.start.year == last.year  and i                  <= last.month
      or tumbler.start.year >  first.year and tumbler.start.year <  last.year then
        when.month = i
        local d = os.time(when)
        ios:write(string.format("=> %s%04d/%02d %s\n",config.url.path,when.year,i,os.date("%B",d)))
      end
    end
    return 20
    
  elseif tumbler.ustart == 'month' then
    ios:write("20 text/gemini\r\n")
    local entries
    for day = 1 , date.daysinmonth(tumbler.start) do
      tumbler.start.day = day
      local list = blog.day_titles(tumbler.start)
      if #list > 0 then
        entries = true
        ios:write(string.format("=> %s%04d/%02d/%02d %04d/%02d/%02d\n",config.url.path,tumbler.start.year,tumbler.start.month,day,tumbler.start.year,tumbler.start.month,tumbler.start.day))
        
        for i,title in ipairs(list) do
          ios:write(string.format("=> %s%04d/%02d/%02d.%d %s\n",config.url.path,tumbler.start.year,tumbler.start.month,day,i,title))
        end
      end
    end
    
    if not entries then
      ios:write("There are no entries this month\n")
    end
    return 20
    
  elseif tumbler.ustart == 'day' then
    ios:write("20 text/gemini\r\n")
    local list = blog.day_titles(tumbler.start)
    for i,title in ipairs(list) do
      ios:write(string.format("=> %s%04d/%02d/%02d.%d %s\n",config.url.path,tumbler.start.year,tumbler.start.month,tumbler.start.day,i,title))
    end
    return 20
    
  else
    ios:write("20 text/gemini\r\n")
    return display(tumbler)
  end
end

-- ***********************************************************************

return _ENV