aboutsummaryrefslogtreecommitdiff
path: root/zzcxz.cgi
diff options
context:
space:
mode:
Diffstat (limited to 'zzcxz.cgi')
-rwxr-xr-xzzcxz.cgi260
1 files changed, 209 insertions, 51 deletions
diff --git a/zzcxz.cgi b/zzcxz.cgi
index ce4811d..72bdee5 100755
--- a/zzcxz.cgi
+++ b/zzcxz.cgi
@@ -34,15 +34,16 @@ local function html_encode(x)
end
local function parse_qs(str,sep)
- sep = sep or "&"
+ sep = sep or '&'
local function decode(str, path)
local str = str
if not path then
str = str:gsub('+', ' ')
end
- return (str:gsub("%%(%x%x)", function(c)
+ str = str:gsub("%%(%x%x)", function(c)
return string.char(tonumber(c, 16))
- end))
+ end)
+ return (str:gsub('\r\n', '\n'))
end
local values = {}
@@ -93,7 +94,13 @@ local function parse_qs(str,sep)
return values
end
-local cookies = env "HTTP_COOKIE" and parse_qs(env "HTTP_COOKIE",";%s") or {}
+local cookies = env "HTTP_COOKIE" and parse_qs(env "HTTP_COOKIE","; ") or {}
+local history = {}
+if cookies.history then
+ for page in cookies.history:gmatch "(%w%w%w%w%w)%," do
+ table.insert(history, page)
+ end
+end
local flags = {}
for k,v in pairs(cookies) do
local flag = k:match "flag_(.+)"
@@ -130,8 +137,8 @@ local base = template [[
<h1>zzcxz</h1>
<main>$content</main>
<footer>
- <div id="about-links">
- <p><a href="/">back to start</a></p>
+ <div class="links">
+ <p><a href="/g/zzcxz">back to start</a></p>
<p><a href="/about">help</a></p>
<p><a href="https://citrons.xyz/git/zzcxz.git/about">
source code
@@ -157,10 +164,6 @@ local function parse_directive(line, directives, tmp_flags)
directive = directive and directive:lower()
if not directive then
return
- elseif directive == "pagetitle" then
- if args:match "^%s*$" then return end
- if utf8.len(args) > 150 then return end
- directives.title = args
elseif directive == "redirect" then
local redirect = args:match "^%s*(%w%w%w%w%w)%s*$"
if not redirect then return end
@@ -205,8 +208,22 @@ local function convert_markup(m)
goto continue
end
if line:sub(1,1) == '#' and
- parse_directive(line, directives, tmp_flags) then
- goto continue
+ parse_directive(line, directives, tmp_flags) then
+ if directives.redirect then
+ local to = load_page(directives.redirect)
+ if to then
+ local m, d = convert_markup(to.content)
+ -- the final destination will not have a redirect
+ -- value in this directive. as such, this will store
+ -- final destination of a chain of redirects.
+ d.redirect = d.redirect or to
+ return m, d
+ else
+ directives.redirect = nil
+ end
+ else
+ goto continue
+ end
end
line = html_encode(line)
@@ -214,6 +231,9 @@ local function convert_markup(m)
table.insert(result, '<pre><code>')
code_block = true
else
+ line = line:gsub("\\\\([%[%]\\])", "&#92;%1")
+ line = line:gsub("\\([%[%]])",
+ { ['['] = "&#91;", [']'] = "&#93;" })
line = line:gsub("%[(.-)%]",
function(s)
return ('<span class="important">%s</span>'):format(s)
@@ -237,14 +257,6 @@ local function convert_markup(m)
code_block = false
end
- if directives.redirect then
- local r = directives.redirect
- return (
- '<p class="note">this action will link to ' ..
- '<a href="/g/%s" target="_blank">%s</a>.</p>'
- ):format(r, r), directives
- end
-
return table.concat(result), directives
end
local function target_requirements(p)
@@ -264,6 +276,8 @@ local function parse_page(s)
for line in (s..'\n'):gmatch "(.-\n)" do
if line:sub(1,1) == '\t' then
table.insert(content, line:sub(2))
+ elseif line:match("^!image") then
+ page.illustration = line:match "^!image%s+(%w+)"
else
local target, action = line:match "^(%w%w%w%w%w):(.-)\n$"
if action then
@@ -284,18 +298,13 @@ function load_page(p, raw)
f:close()
if not s then return nil end
if raw then return s end
- return parse_page(s)
+ local page = parse_page(s)
+ page.id = p
+ return page
end
local function new_action(page, action, result)
local _, directives = convert_markup(result)
- local old = assert(io.open('content/'..page, 'a'))
-
- if directives.redirect then
- assert(old:write(('%s:%s\n'):format(directives.redirect, action)))
- old:close()
- return directives.redirect
- end
::generate_name::
local new_name = {}
@@ -311,10 +320,11 @@ local function new_action(page, action, result)
goto generate_name
end
+ local old = assert(io.open('content/'..page, 'a'))
local new = assert(io.open('content/'..new_name, 'w'))
action = action:gsub('\n', ' ')
- assert(new:write((directives.title or action)..'\n'))
+ assert(new:write(action..'\n'))
for line in (result..'\n'):gmatch "(.-\n)" do
assert(new:write('\t' .. line))
end
@@ -332,20 +342,70 @@ local function new_action(page, action, result)
return new_name
end
+local hist_template = template [[
+ <ul class="hist-log">
+ $log
+ </ul>
+]]
+local function show_hist(show_ids)
+ local log = {}
+ if #history == 0 then return "" end
+
+ for i=#history,1,-1 do
+ local page = load_page(history[i])
+ if not page then goto continue end
+
+ -- highlight the current page
+ local title = i ~= #history and html_encode(page.title)
+ or '<strong>'..html_encode(page.title)..'</strong>'
+ if show_ids then
+ table.insert(log,
+ ('<li>%s <span class="page-id">%s</span></li>')
+ :format(title, history[i]))
+ else
+ table.insert(log, ('<li>%s</li>'):format(title))
+ end
+ ::continue::
+ end
+ return hist_template {
+ log = table.concat(log),
+ }
+end
+
local map = {}
local page_template = template [[
<h2>$title</h2>
+ $illustration
$content
+ $drawthis
<ul class="actions">
$actions
</ul>
+ $log
+]]
+local draw_this = [[
+ <p id="draw-this"><a href="$page/illustrate">illustrate this</a></p>
]]
map["^/g/(%w%w%w%w%w)$"] = function(p)
local page = load_page(p)
if not page then return not_found() end
- local _, directives = convert_markup(page.content)
+ local content, directives = convert_markup(page.content)
+
if env "REQUEST_METHOD" ~= "POST" then
+ if history[#history] ~= p then
+ table.insert(history, p)
+ end
+ if #history > 75 then
+ table.remove(history, 1)
+ end
+
+ local title = page.title
+
+ if directives.redirect then
+ page = directives.redirect
+ end
+
local actions = {}
for _,a in ipairs(page.actions) do
if target_requirements(a.target) then
@@ -357,13 +417,32 @@ map["^/g/(%w%w%w%w%w)$"] = function(p)
if not directives.deadend then
table.insert(actions,
([[
- <li><a class="important" href="%s/act#what">%s</a></li>
- ]]):format(p, #page.actions == 0 and
+ <li>
+ <a class="important" href="%s/act?back=%s#what">%s</a>
+ </li>
+ ]]):format(page.id, p, #page.actions == 0 and
"do something..." or "do something else...")
)
end
+ local illustration, draw_this
+ if page.illustration then
+ illustration = ([[
+ <img class="illustration" src="/i/%s.%s" />
+ ]]):format(page.id, page.illustration)
+ else
+-- draw_this = ([[
+-- <p id="draw-this"><a href="%s/illustrate">
+-- illustrate this
+-- </a></p>
+-- ]]):format(p)
+ end
+
local cookies = {}
+ table.insert(cookies,
+ ('history=%s; path=/; secure; max-age=99999999999')
+ :format(table.concat(history, ',')..','))
+
for flagname, text in pairs(directives.flags_updated) do
if text then
table.insert(cookies,
@@ -378,11 +457,14 @@ map["^/g/(%w%w%w%w%w)$"] = function(p)
end
return base {
- title = html_encode(page.title),
+ title = html_encode(title),
content = page_template {
- title = html_encode(page.title),
- content = convert_markup(page.content),
+ title = html_encode(title),
+ content = content,
actions = table.concat(actions),
+ illustration = illustration,
+ drawthis = draw_this,
+ log = show_hist(),
},
}, {headers = {["set-cookie"] = cookies, bees = "3.14"}}
else
@@ -430,10 +512,11 @@ local edit_template = template [[
maxlength="10000" required
>$editing</textarea>
<div class="buttons">
- <a href="../$page">cancel</a>
- <input type="submit" formaction="act#what" value="preview" />
+ <a href="$cancel">cancel</a>
+ <input type="submit" value="preview" />
$submit
</div>
+ $log
</form>
]]
local preview_template = template [[
@@ -451,12 +534,17 @@ map["^/g/(%w%w%w%w%w)/act$"] = function(p)
local _, directives = convert_markup(page.content)
if directives.deadend then return not_found() end
+ local query = parse_qs(env "QUERY_STRING" or "")
+ local cancel = '/g/'..(query.back or p)
+
if env "REQUEST_METHOD" ~= "POST" then
return base {
title = "do something new",
content = edit_template {
page = p,
content = convert_markup(page.content),
+ log = show_hist(true),
+ cancel = html_encode(cancel),
},
}
else
@@ -465,46 +553,108 @@ map["^/g/(%w%w%w%w%w)/act$"] = function(p)
form.happens = form.happens or "something"
local prev, prev_direct = convert_markup(form.happens)
-
+
+ local prev_title =
+ prev_direct.title and html_encode(prev_direct.title) or
+ html_encode(form.wyd)
+
+ if prev_direct.redirect then
+ local note =
+ ('<span class="note">previewing %s</span>')
+ :format(prev_direct.redirect.id)
+ prev = note..prev
+ end
+
return base {
title = "do something new",
content = edit_template {
page = p,
content = convert_markup(page.content),
preview = preview_template {
- title =
- prev_direct.title and html_encode(prev_direct.title)
- or html_encode(form.wyd),
+ title = prev_title,
content = prev,
},
title = html_encode(form.wyd),
editing = html_encode(form.happens),
submit = submit_template { page = p },
+ cancel = html_encode(cancel),
+ log = show_hist(true),
},
}
end
end
+local illustrate_template = template [[
+ <h2>$title</h2>
+ $content
+ <hr/>
+ <h2 id="what">what does this look like?</h2>
+ <form method="POST" action="/g/$page/illustrate"
+ enctype="multipart/form-data" id="img-form">
+ <input
+ type="file"
+ name="file"
+ accept="image/png,image/jpeg,image/gif"
+ />
+ <input type="submit" value="submit image" />
+ </form>
+]]
+-- map["^/g/(%w%w%w%w%w)/illustrate"] = function(p)
+-- local page = load_page(p)
+-- if not page then return not_found() end
+--
+-- if env "REQUEST_METHOD" ~= "POST" then
+-- return base {
+-- title = "illustration: " .. html_encode(page.title),
+-- content = illustrate_template {
+-- title = html_encode(page.title),
+-- content = convert_markup(page.content),
+-- page = p,
+-- },
+-- }
+-- else
+-- end
+-- end
+
+map["^/i/(%w%w%w%w%w).(%w+)$"] = function(p, format)
+ local page = load_page(p)
+ if not page or
+ not page.illustration or not page.illustration == format then
+ return not_found()
+ end
+ return
+ assert(io.open(('content/%s.%s'):format(p, format), 'r')),
+ { content_type = 'image/'..format }
+end
+
map["^/g/(%w%w%w%w%w)/raw$"] = function(p)
local page = load_page(p, true)
if not page then return not_found() end
- return page, { content_type = 'text/plain' }
+ return page, {
+ content_type = 'text/plain',
+ headers = { ['access-control-allow-origin'] = "*" }
+ }
end
map["^/about/?$"] = function()
- local f = assert(io.open("about.html", 'r'))
- local h = assert(f:read 'a')
- f:close()
+ return assert(io.open("about.html", 'r'))
+end
- return h
+map["^/robots.txt$"] = function()
+ return assert(io.open("robots.txt", 'r')),
+ { content_type = 'text/plain' }
end
-local function main()
- if env "PATH_INFO" == "/" then
- return redirect "/g/zzcxz"
+map["^/$"] = function()
+ if #history > 0 then
+ return redirect('/g/'..history[#history])
+ else
+ return redirect '/g/zzcxz'
end
+end
+local function main()
for k,v in pairs(map) do
local m = {(env "PATH_INFO"):match(k)}
if m[1] then
@@ -515,7 +665,7 @@ local function main()
end
local ok, content, resp = pcall(main)
-if not ok or type(content) ~= 'string' then
+if not ok or (type(content) ~= 'string' and type(content) ~= 'userdata') then
io.stderr:write(content..'\n')
content = base {
@@ -544,4 +694,12 @@ for k,v in pairs(resp.headers) do
end
print ""
-io.write(content)
+if type(content) == 'string' then
+ io.write(content)
+else
+ while 1 do
+ local data = content:read(1024)
+ if not data then break end
+ io.write(data)
+ end
+end