diff options
Diffstat (limited to 'zzcxz.cgi')
| -rwxr-xr-x | zzcxz.cgi | 260 |
1 files changed, 209 insertions, 51 deletions
@@ -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("\\\\([%[%]\\])", "\%1") + line = line:gsub("\\([%[%]])", + { ['['] = "[", [']'] = "]" }) 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 |
