Add comments
Add comments for each paste, Also add a "Download TXT" button.
This commit is contained in:
parent
0ba9e22f70
commit
bce0788b62
19
Makefile
19
Makefile
|
@ -3,8 +3,8 @@ chroot_dir=kore_chroot/
|
|||
mirror=http://dl-cdn.alpinelinux.org/alpine/
|
||||
arch=aarch64
|
||||
version=2.10.5-r0
|
||||
#certbot_email=--register-unsafely-without-email
|
||||
certbot_email=-m you@cock.li
|
||||
certbot_email=--register-unsafely-without-email
|
||||
#certbot_email=-m you@cock.li
|
||||
domain=test.monster
|
||||
|
||||
#Probably don't change stuff past here
|
||||
|
@ -20,17 +20,18 @@ all: $(chroot_dir) smr.so $(built_files) $(built_pages) $(built_sql)
|
|||
echo $(built_files)
|
||||
kodev run
|
||||
|
||||
apk-tools-static-$(version).apk: Makefile
|
||||
wget -q $(mirror)latest-stable/main/$(arch)/apk-tools-static-$(version).apk
|
||||
apk-tools-static-$(version).apk:
|
||||
# wget -q $(mirror)latest-stable/main/$(arch)/apk-tools-static-$(version).apk
|
||||
|
||||
clean:
|
||||
kodev clean
|
||||
|
||||
$(chroot_dir): #apk-tools-static-$(version).apk
|
||||
$(chroot_dir): apk-tools-static-$(version).apk
|
||||
mkdir -p $(chroot_dir)
|
||||
mkdir -p $(chroot_dir)/pages
|
||||
mkdir -p $(chroot_dir)/sql
|
||||
#cd $(chroot_dir) && tar -xvzf ../../apk-tools-static-*.apk
|
||||
mkdir -p $(chroot_dir)/data
|
||||
#cd $(chroot_dir) && tar -xvzf ../apk-tools-static-*.apk
|
||||
#cd $(chroot_dir) && sudo ./sbin/apk.static -X $(mirror)latest-stable/main -U --allow-untrusted --root $(chroot_dir) --no-cache --initdb add alpine-base
|
||||
#ln -s /dev/urandom $(chroot_dir)/dev/random #Prevent an attacker with access to the chroot from exhausting our entropy pool and causing a dos
|
||||
#ln -s /dev/urandom $(chroot_dir)/dev/urandom
|
||||
|
@ -39,13 +40,16 @@ $(chroot_dir): #apk-tools-static-$(version).apk
|
|||
#mount -t proc none $(chroot_dir)/proc
|
||||
#mount -o bind /sys $(chroot_dir)/sys
|
||||
#cp /etc/resolv.conf $(chroot_dir)/etc/resolv.conf
|
||||
#echo "$(mirror)/$(branch)/main" > $(chroot)/etc/apk/repositories
|
||||
#echo "$(mirror)/$(branch)/community" >> $(chroot)/etc/apk/repositories
|
||||
#cp /etc/apk/repositories $(chroot_dir)/etc/apk/repositories
|
||||
#mkdir $(chroot_dir)/var/sm
|
||||
## Things to build lua libraries
|
||||
#chroot $(chroot_dir) apk add luarocks5.1 sqlite sqlite-dev lua5.1-dev build-base zlib zlib-dev
|
||||
#chroot $(chroot_dir) luarocks-5.1 install etlua
|
||||
#chroot $(chroot_dir) luarocks-5.1 install lsqlite3
|
||||
#chroot $(chroot_dir) luarocks-5.1 install lzlib ZLIB_LIBDIR=/lib #for some reason lzlib looks in /usr/lib for libz, when it needs to look at /lib
|
||||
#chroot $(chroot_dir) luarocks-5.1 install lpeg
|
||||
#chroot $(chroot_dir) luarocks-5.1 install lua-zlib ZLIB_LIBDIR=/lib #for some reason lzlib looks in /usr/lib for libz, when it needs to look at /lib
|
||||
## Once we've built + installed everything, delete extra stuff from the chroot
|
||||
#chroot $(chroot_dir) apk del sqlite-dev lua5.1-dev build-base zlib-dev
|
||||
## SSL certificates, if you don't trust EFF (they have an antifa black block member as their favicon at time of writing) you may want to replace this.
|
||||
|
@ -56,6 +60,7 @@ $(chroot_dir): #apk-tools-static-$(version).apk
|
|||
code : $(built_files)
|
||||
|
||||
$(built_files): $(chroot_dir)%.lua : src/lua/%.lua
|
||||
echo built files: $(built_files)
|
||||
cp $^ $@
|
||||
|
||||
$(built_pages): $(chroot_dir)pages/%.etlua : src/pages/%.etlua
|
||||
|
|
|
@ -25,8 +25,9 @@ mime_add=css:text/css
|
|||
dev {
|
||||
# These flags are added to the shared ones when
|
||||
# you build the "dev" flavor.
|
||||
ldflags=-llua
|
||||
ldflags=-llua5.1
|
||||
cflags=-g -Wextra
|
||||
cflags=-I/usr/include/lua5.1
|
||||
cxxflags=-g -Wextra
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@ server tls {
|
|||
seccomp_tracing yes
|
||||
load ./smr.so
|
||||
root kore_chroot
|
||||
runas root
|
||||
#keymgr_runas demo
|
||||
#keymgr_root ./
|
||||
runas robin
|
||||
keymgr_runas robin
|
||||
keymgr_root .
|
||||
workers 1
|
||||
|
||||
http_body_max 8388608
|
||||
|
@ -20,12 +20,13 @@ validator v_any regex .*
|
|||
validator v_storyid regex [a-zA-Z0-9]+
|
||||
validator v_subdomain regex [a-z0-9]{1,30}
|
||||
validator v_markup regex (plain|imageboard)
|
||||
validator v_bool regex (0|1)
|
||||
|
||||
domain * {
|
||||
attach tls
|
||||
|
||||
certfile server.pem
|
||||
certkey key.pem
|
||||
certfile cert/server.pem
|
||||
certkey cert/key.pem
|
||||
|
||||
#I run kore behind a lighttpd reverse proxy, so this is a bit useless to me
|
||||
accesslog /dev/null
|
||||
|
@ -40,12 +41,16 @@ domain * {
|
|||
route /_bio edit_bio
|
||||
route /_login login
|
||||
route /_claim claim
|
||||
route /_download download
|
||||
# Leading ^ is needed for dynamic routes, kore says the route is dynamic if it does not start with '/'
|
||||
route ^/[^_].* read_story
|
||||
|
||||
params get /_edit {
|
||||
validate story v_storyid
|
||||
}
|
||||
params get /_download {
|
||||
validate story v_storyid
|
||||
}
|
||||
params post /_edit {
|
||||
validate title v_any
|
||||
validate story v_storyid
|
||||
|
@ -59,9 +64,14 @@ domain * {
|
|||
validate pasteas v_subdomain
|
||||
validate markup v_markup
|
||||
}
|
||||
#params get /[^_].* {
|
||||
params get ^/[^_].* {
|
||||
validate comments v_bool
|
||||
#validate story v_storyid
|
||||
#}
|
||||
}
|
||||
params post ^/[^_].* {
|
||||
validate text v_any
|
||||
validate postas v_subdomain
|
||||
}
|
||||
params post /_login {
|
||||
validate user v_subdomain
|
||||
validate pass v_any
|
||||
|
@ -69,4 +79,5 @@ domain * {
|
|||
params post /_claim {
|
||||
validate user v_any
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
borrowed sha3 implementation from keccak.team
|
||||
borrowed sha3 implementation from https://keccak.team
|
||||
*/
|
||||
#ifdef BUILD_PROD
|
||||
#include <luajit.h>
|
||||
|
|
230
src/lua/init.lua
230
src/lua/init.lua
|
@ -1,6 +1,9 @@
|
|||
print("Really fast print from init.lua")
|
||||
|
||||
local et = require("etlua")
|
||||
local sql = require("lsqlite3")
|
||||
local zlib = require("zlib")
|
||||
|
||||
if PRODUCTION then
|
||||
local function print() end --squash prints
|
||||
end
|
||||
|
@ -50,6 +53,7 @@ local stmnt_author_create, stmnt_author_acct, stmnt_author_bio
|
|||
local stmnt_cache, stmnt_insert_cache, stmnt_dirty_cache
|
||||
local stmnt_get_session, stmnt_insert_session
|
||||
local stmnt_edit, stmnt_update, stmnt_update_raw, stmnt_author_of
|
||||
local stmnt_comments, stmnt_comment_insert
|
||||
--see https://perishablepress.com/stop-using-unsafe-characters-in-urls/
|
||||
--no underscore because we use that for our operative pages
|
||||
local url_characters =
|
||||
|
@ -82,8 +86,10 @@ end
|
|||
print("Hello from init.lua")
|
||||
function configure()
|
||||
db = sqlassert(sql.open("data/posts.db"))
|
||||
--db = sqlassert(sql.open_memory())
|
||||
cache = sqlassert(sql.open_memory())
|
||||
print("Compiled pages...")
|
||||
--Test that compression works
|
||||
local msg = "test message"
|
||||
local one = zlib.compress(msg)
|
||||
local two = zlib.decompress(one)
|
||||
|
@ -132,6 +138,8 @@ function configure()
|
|||
--Select the data we need to read a story (and maybe display an edit
|
||||
--button
|
||||
stmnt_read = assert(db:prepare(queries.select_post))
|
||||
stmnt_comments = assert(db:prepare(queries.select_comments))
|
||||
stmnt_comment_insert = assert(db:prepare(queries.insert_comment))
|
||||
--TODO: actually let authors edit their bio
|
||||
stmnt_author_bio = assert(db:prepare([[
|
||||
SELECT authors.biography FROM authors WHERE authors.name = :author;
|
||||
|
@ -158,6 +166,8 @@ function configure()
|
|||
stmnt_raw = assert(db:prepare(queries.insert_raw))
|
||||
--Get the data we need to display the edit screen
|
||||
stmnt_edit = assert(db:prepare(queries.select_edit))
|
||||
--Get the data we need when someone wants to download a paste
|
||||
stmnt_download = assert(db:prepare(queries.select_download))
|
||||
--When we update a post, store the plaintext again
|
||||
stmnt_update_raw = assert(db:prepare(queries.update_raw))
|
||||
--Should we really reset the update time every time someone makes a post?
|
||||
|
@ -172,7 +182,7 @@ function configure()
|
|||
FROM cache
|
||||
WHERE
|
||||
path = :path AND
|
||||
((dirty = 0) OR (strftime('%s','now') - updated) < 10)
|
||||
((dirty = 0) OR (strftime('%s','now') - updated) < 2)
|
||||
;
|
||||
]])
|
||||
stmnt_insert_cache = cache:prepare([[
|
||||
|
@ -189,6 +199,7 @@ function configure()
|
|||
]])
|
||||
--[=[
|
||||
]=]
|
||||
print("finished running configure()")
|
||||
end
|
||||
print("Created configure function")
|
||||
|
||||
|
@ -232,6 +243,7 @@ local function do_sql(stmnt)
|
|||
end
|
||||
|
||||
local function dirty_cache(url)
|
||||
print("Dirtying cache:",url)
|
||||
stmnt_dirty_cache:bind_names{
|
||||
path = url
|
||||
}
|
||||
|
@ -475,25 +487,33 @@ function paste(req)
|
|||
if method == "GET" then
|
||||
--Get the paste page
|
||||
if host == domain then
|
||||
--For an anonymous user
|
||||
ret = render(string.format("%s/_paste",host),function()
|
||||
print("Cache missing, rendering post page")
|
||||
return pages.paste{
|
||||
domain = domain,
|
||||
err = "",
|
||||
}
|
||||
end)
|
||||
local author,_ = get_session(req)
|
||||
if author then
|
||||
http_response_header(req,"Location",string.format("https://%s.%s/_paste",author,domain))
|
||||
http_response(req,303,"")
|
||||
return
|
||||
else
|
||||
--For an anonymous user
|
||||
ret = render(string.format("%s/_paste",host),function()
|
||||
print("Cache missing, rendering post page")
|
||||
return pages.paste{
|
||||
domain = domain,
|
||||
err = "",
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
else
|
||||
--Or for someone that's logged in
|
||||
print("Looks like a logged in user wants to paste!")
|
||||
local subdomain = host:match("([^\\.]+)")
|
||||
local subdomain = host:match("([^%.]+)")
|
||||
local author,_ = get_session(req)
|
||||
print("subdomain:",subdomain,"author:",author)
|
||||
--If they try to paste as an author, but are on the
|
||||
--wrong subdomain, or or not logged in, redirect them
|
||||
--to the right place. Their own subdomain for authors
|
||||
--or the anonymous paste page for not logged in users.
|
||||
if author == nil then
|
||||
print("sessionid was nil")
|
||||
http_response_header(req,"Location","https://"..domain.."/_paste")
|
||||
http_response(req,303,"")
|
||||
return
|
||||
|
@ -557,7 +577,6 @@ function paste(req)
|
|||
if err ~= sql.DONE then
|
||||
print("Failed to save raw text, but paste still went though")
|
||||
end
|
||||
print("Successful paste, rowid:", rowid)
|
||||
local url = encode_id(rowid)
|
||||
local loc = string.format("https://%s/%s",domain,url)
|
||||
http_response_header(req,"Location",loc)
|
||||
|
@ -570,7 +589,7 @@ function paste(req)
|
|||
elseif err == sql.ERROR or err == sql.MISUSE then
|
||||
ret = "Failed to paste: " .. tostring(err)
|
||||
else
|
||||
error("Error pasting:",err)
|
||||
error("Error pasting:" .. tostring(err))
|
||||
end
|
||||
stmnt_paste:reset()
|
||||
|
||||
|
@ -636,11 +655,15 @@ function paste(req)
|
|||
end
|
||||
|
||||
--A helper function for below
|
||||
local function read_story(host,path,idp)
|
||||
return render(string.format("%s%s",host,path),function()
|
||||
print("Trying to read, id is",idp,":",decode_id(idp))
|
||||
local function read_story(host,path,idp,show_comments,iam)
|
||||
local cachestr
|
||||
if show_comments then
|
||||
cachestr = string.format("%s%s?comments=1",host,path)
|
||||
else
|
||||
cachestr = string.format("%s%s",host,path)
|
||||
end
|
||||
local readstoryf = function()
|
||||
local id = decode_id(idp)
|
||||
print("id:",id,type(id))
|
||||
stmnt_read:bind_names{
|
||||
id = id
|
||||
}
|
||||
|
@ -653,6 +676,20 @@ local function read_story(host,path,idp)
|
|||
end
|
||||
assert(err == sql.ROW,"Could not get row:" .. tostring(id) .. " Error:" .. tostring(err))
|
||||
local title, text, authorid, isanon, authorname = unpack(stmnt_read:get_values())
|
||||
stmnt_comments:bind_names{
|
||||
id = id
|
||||
}
|
||||
err = do_sql(stmnt_comments)
|
||||
local comments = {}
|
||||
while err ~= sql.DONE do
|
||||
local com_author, com_isanon, com_text = unpack(stmnt_comments:get_values())
|
||||
table.insert(comments,{
|
||||
author = com_author,
|
||||
isanon = com_isanon == 1, --int to boolean
|
||||
text = com_text
|
||||
})
|
||||
err = stmnt_comments:step()
|
||||
end
|
||||
text = zlib.decompress(text)
|
||||
stmnt_read:reset()
|
||||
return pages.read{
|
||||
|
@ -661,61 +698,108 @@ local function read_story(host,path,idp)
|
|||
text = text,
|
||||
idp = idp,
|
||||
isanon = isanon == 1,
|
||||
author = authorname
|
||||
author = authorname,
|
||||
comments = comments,
|
||||
show_comments = show_comments,
|
||||
iam = iam,
|
||||
}
|
||||
end)
|
||||
|
||||
end
|
||||
--Don't cache if we're logged in, someone might see dirty cache information on the page.
|
||||
if not iam then
|
||||
return render(cachestr,readstoryf)
|
||||
else
|
||||
return readstoryf()
|
||||
end
|
||||
end
|
||||
|
||||
function read(req)
|
||||
local host = http_request_get_host(req)
|
||||
local path = http_request_get_path(req)
|
||||
local idp = string.sub(path,2)--remove leading "/"
|
||||
assert(string.len(path) > 0,"Tried to read 0-length story id")
|
||||
local author, authorid = get_session(req)
|
||||
local text
|
||||
if author then
|
||||
--We're logged in as someone
|
||||
local id = decode_id(idp)
|
||||
stmnt_read:bind_names{
|
||||
id = id
|
||||
}
|
||||
local err = do_sql(stmnt_read)
|
||||
if err == sql.DONE then
|
||||
--We got no story
|
||||
stmnt_read:reset()
|
||||
text = pages.nostory{
|
||||
path = path
|
||||
local method = http_method_text(req)
|
||||
if method == "GET" then
|
||||
local idp = string.sub(path,2)--remove leading "/"
|
||||
assert(string.len(path) > 0,"Tried to read 0-length story id")
|
||||
local author, authorid = get_session(req)
|
||||
http_request_populate_qs(req)
|
||||
local show_comments = http_argument_get_string(req,"comments")
|
||||
--parameters needed for the read page
|
||||
local text
|
||||
if author then
|
||||
--We're logged in as someone
|
||||
local id = decode_id(idp)
|
||||
stmnt_read:bind_names{
|
||||
id = id
|
||||
}
|
||||
else
|
||||
assert(err == sql.ROW)
|
||||
local title, storytext, tauthor, isanon, authorname = unpack(stmnt_read:get_values())
|
||||
storytext = zlib.decompress(storytext)
|
||||
stmnt_read:reset()
|
||||
if tauthor == authorid then
|
||||
print("we're the author!")
|
||||
--The story exists and we're logged in as the
|
||||
--owner, display the edit button
|
||||
text = pages.read{
|
||||
domain = domain,
|
||||
title = title,
|
||||
text = storytext,
|
||||
idp = idp,
|
||||
isanon = isanon == 1,
|
||||
author = authorname,
|
||||
owner = true
|
||||
local err = do_sql(stmnt_read)
|
||||
if err == sql.DONE then
|
||||
--We got no story
|
||||
stmnt_read:reset()
|
||||
text = pages.nostory{
|
||||
path = path
|
||||
}
|
||||
|
||||
else
|
||||
print("we're not the author!")
|
||||
text = read_story(host,path,idp)
|
||||
--If we can edit this story, we don't want to cache
|
||||
--the page, since it'll have an edit button on it.
|
||||
assert(err == sql.ROW)
|
||||
local title, storytext, tauthor, isanon, authorname = unpack(stmnt_read:get_values())
|
||||
storytext = zlib.decompress(storytext)
|
||||
stmnt_read:reset()
|
||||
if tauthor == authorid then
|
||||
--The story exists and we're logged in as the
|
||||
--owner, display the edit button
|
||||
text = pages.read{
|
||||
domain = domain,
|
||||
title = title,
|
||||
text = storytext,
|
||||
idp = idp,
|
||||
isanon = isanon == 1,
|
||||
author = authorname,
|
||||
iam = authorname,
|
||||
owner = true
|
||||
}
|
||||
|
||||
else
|
||||
text = read_story(host,path,idp,show_comments,author)
|
||||
end
|
||||
end
|
||||
else
|
||||
--We're not logged in as anyone
|
||||
http_request_populate_qs(req)
|
||||
text = read_story(host,path,idp,show_comments,author)
|
||||
end
|
||||
assert(text)
|
||||
http_response(req,200,text)
|
||||
return
|
||||
elseif method == "POST" then
|
||||
--We're posting a comment
|
||||
http_request_populate_post(req)
|
||||
http_populate_cookies(req)
|
||||
local author, authorid = get_session(req)
|
||||
local comment_text = assert(http_argument_get_string(req,"text"))
|
||||
local pasteas = assert(http_argument_get_string(req,"postas"))
|
||||
local idp = string.sub(path,2)--remove leading "/"
|
||||
local id = decode_id(idp)
|
||||
local isanon = 1
|
||||
if author and pasteas ~= "Anonymous" then
|
||||
isanon = 0
|
||||
end
|
||||
stmnt_comment_insert:bind_names{
|
||||
postid=id,
|
||||
authorid = author and authorid or -1,
|
||||
isanon = isanon,
|
||||
comment_text = comment_text,
|
||||
}
|
||||
local err = do_sql(stmnt_comment_insert)
|
||||
stmnt_comment_insert:reset()
|
||||
if err ~= sql.DONE then
|
||||
http_response(req,500,"Internal error, failed to post comment. Go back and try again.")
|
||||
else
|
||||
dirty_cache(string.format("%s%s?comments=1",host,path))
|
||||
local redir = string.format("https://%s%s?comments=1", domain, path)
|
||||
http_response_header(req,"Location",redir)
|
||||
http_response(req,303,"")
|
||||
end
|
||||
else
|
||||
text = read_story(host,path,idp)
|
||||
end
|
||||
assert(text)
|
||||
http_response(req,200,text)
|
||||
end
|
||||
|
||||
function login(req)
|
||||
|
@ -883,4 +967,30 @@ function teardown()
|
|||
print("Finished lua teardown")
|
||||
end
|
||||
|
||||
function download(req)
|
||||
local host = http_request_get_host(req)
|
||||
local path = http_request_get_path(req)
|
||||
print("host:",host,"path:",path)
|
||||
http_request_populate_qs(req)
|
||||
local story = assert(http_argument_get_string(req,"story"))
|
||||
local story_id = decode_id(story)
|
||||
stmnt_download:bind_names{
|
||||
postid = story_id
|
||||
}
|
||||
local err = do_sql(stmnt_download)
|
||||
if err == sql.DONE then
|
||||
--No rows, story not found
|
||||
http_responose(req,404,pages.nostory{path=story})
|
||||
stmnt_download:reset()
|
||||
return
|
||||
end
|
||||
local txt_compressed, title = unpack(stmnt_download:get_values())
|
||||
local text = zlib.decompress(txt_compressed)
|
||||
stmnt_download:reset()
|
||||
http_response_header(req,"Content-Type","application/octet-stream")
|
||||
local nicetitle = title:gsub("%W","_")
|
||||
http_response_header(req,"Content-Disposition","attachment; filename=\"" .. nicetitle .. ".txt\"")
|
||||
http_response(req,200,text)
|
||||
end
|
||||
|
||||
print("Done with init.lua")
|
||||
|
|
|
@ -61,10 +61,10 @@ local grammar = P{
|
|||
heading = wrap("==",[[<h2>%s</h2>]]),
|
||||
strike = wrap("~~",[[<s>%s</s>]]),
|
||||
code = tag("code",[[<pre><code>%s</code></pre>]]),
|
||||
greentext = P"> " * Cs((V"marked" + word)^0) / function(a)
|
||||
greentext = P">" * (B"\n>" + B">") * Cs((V"marked" + word)^0) / function(a)
|
||||
return string.format([[<span class="greentext">>%s</span>]],a)
|
||||
end,
|
||||
pinktext = P"< " * Cs((V"marked" + word)^0) / function(a)
|
||||
pinktext = P"<" * (B"\n<" + B"<") * Cs((V"marked" + word)^0) / function(a)
|
||||
return string.format([[<span class="pinktext"><%s</span>]],a)
|
||||
end,
|
||||
marked = V"spoiler" + V"bold" + V"italic" + V"underline" + V"heading" + V"strike" + V"spoiler2" + V"code",
|
||||
|
@ -76,36 +76,39 @@ local grammar = P{
|
|||
chunk = V"line"^0 * V"plainline" * V"ending"
|
||||
}
|
||||
|
||||
--local text = [[
|
||||
--this is **a big** test with ''italics''!
|
||||
--we need to > sanitize < things that could be tags
|
||||
--like really <b> badly </b>
|
||||
--words can include any'single item without=penalty
|
||||
--Can you use '''one tag ==within== another tag'''?
|
||||
--let's see if [spoiler]spoiler tags work[/spoiler]
|
||||
--things might even __go over
|
||||
--multiple lines__ blah
|
||||
--Let's test out those [code]
|
||||
--code tag,s and see how well
|
||||
--they work
|
||||
--here's ome
|
||||
--preformated <with injection>
|
||||
--text
|
||||
--[/code]
|
||||
--> Or have blank lines
|
||||
--[=[
|
||||
local text = [[
|
||||
<pinktext on the first line
|
||||
this is **a big** test with ''italics''!
|
||||
we need to > sanitize < things that could be tags
|
||||
like really <b> badly </b>
|
||||
words can include any'single item without=penalty
|
||||
Can you use '''one tag ==within== another tag'''?
|
||||
let's see if [spoiler]spoiler tags work[/spoiler]
|
||||
things might even __go over
|
||||
multiple lines__ blah
|
||||
Let's test out those [code]
|
||||
code tag,s and see how well
|
||||
they work
|
||||
here's ome
|
||||
preformated <with injection>
|
||||
text
|
||||
[/code]
|
||||
>Or have blank lines
|
||||
|
||||
--one important thing is that greentext > should not start in the middle of a line
|
||||
--> this next line is a green text, what if I include **markup** inside it?
|
||||
--< and after '''it is''' a pinktext
|
||||
--> because of some of these restrictions **bold text
|
||||
--cannot go over multiple lines** in a green text
|
||||
--__and finally__ there might be some text with '''
|
||||
--incomplete syntax <b> with injection</b> !!!!
|
||||
--]]
|
||||
one important thing is that greentext > should not start in the middle of a line
|
||||
>this next line is a green text, what if I include **markup** inside it?
|
||||
<and after '''it is''' a pinktext
|
||||
>because of some of these restrictions **bold text
|
||||
cannot go over multiple lines** in a green text
|
||||
>greentext on the last line
|
||||
<pinktext on the last line
|
||||
]]
|
||||
]=]
|
||||
|
||||
return function(text)
|
||||
return table.concat({grammar:match(text .. "\n")}," ")
|
||||
end
|
||||
--for k,v in pairs({grammar:match(text)}) do
|
||||
--print(k,":",v)
|
||||
-- print(k,":",v)
|
||||
--end
|
||||
|
|
|
@ -11,24 +11,67 @@
|
|||
<nav>
|
||||
<a href="https://<%= domain %>"><%= domain %></a>/<a href="https://<%= domain %>/<%= idp %>"><%= idp %></a>
|
||||
</nav>
|
||||
<% if owner then %>
|
||||
<% if owner then -%>
|
||||
<form action="https://<%= domain %>/_edit" method="get"><fieldset>
|
||||
<input type="hidden" name="story" value="<%= idp %>"/>
|
||||
<input type="submit" value="edit" class="button"/>
|
||||
</fieldset></form>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
<article>
|
||||
<h2 class="title">
|
||||
<%- title %>
|
||||
</h2>
|
||||
<h3>
|
||||
<% if isanon then %>
|
||||
<% if isanon then -%>
|
||||
By Anonymous
|
||||
<% else %>
|
||||
<% else -%>
|
||||
By <a href="https://<%= author %>.<%= domain %>"><%= author %></a>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
</h3>
|
||||
<%- text %>
|
||||
</article>
|
||||
<form action="https://<%= domain %>/_download" method="get">
|
||||
<input type="hidden" name="story" value="<%= idp %>"/>
|
||||
<input type="submit" value="Download TXT" class="button"/>
|
||||
</form>
|
||||
<% if not show_comments then -%>
|
||||
<form action="https://<%= domain %>/<%= idp %>"><fieldset>
|
||||
<input type="hidden" name="comments" value="1">
|
||||
<input type="submit" value="load comments" class="button">
|
||||
</fieldset></form>
|
||||
<% else %>
|
||||
<form action="https://<%= domain %>/<%= idp %>" method="POST">
|
||||
<textarea name="text" cols=60 rows=10 class="column"></textarea>
|
||||
</div><% if iam then %>
|
||||
<select id="postas" name="postas">
|
||||
<option value="Anonymous">Anonymous</option>
|
||||
<option value="<%= iam %>"><%= iam %></option>
|
||||
</select>
|
||||
<input type="submit" value="post" class="button">
|
||||
<% else %>
|
||||
<input type="hidden" name="postas" value="Anonymous">
|
||||
<input type="submit" value="post" class="button">
|
||||
<% end %>
|
||||
</form>
|
||||
<% if comments and #comments == 0 then %>
|
||||
<p><i>No comments yet</i></p>
|
||||
<% else %>
|
||||
<section>
|
||||
<% for _,comment in pairs(comments) do %>
|
||||
<article>
|
||||
<% if comment.isanon then %>
|
||||
<p><b>Anonymous</b></p>
|
||||
<% else %>
|
||||
<p><b><%= comment.author %></b></p>
|
||||
<% end %>
|
||||
<p><%= comment.text %></p>
|
||||
</article>
|
||||
<% end %>
|
||||
</section>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
|
||||
</main></body>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ int edit_bio(struct http_request *);
|
|||
int read_story(struct http_request *);
|
||||
int login(struct http_request *);
|
||||
int claim(struct http_request *);
|
||||
int download(struct http_request *);
|
||||
int style(struct http_request *);
|
||||
int miligram(struct http_request *);
|
||||
int do_lua(struct http_request *req, const char *name);
|
||||
|
@ -107,6 +108,12 @@ claim(struct http_request *req){
|
|||
return do_lua(req,"claim");
|
||||
}
|
||||
|
||||
int
|
||||
download(struct http_request *req){
|
||||
printf("We want to do download!\n");
|
||||
return do_lua(req,"download");
|
||||
}
|
||||
|
||||
int
|
||||
home(struct http_request *req){
|
||||
return do_lua(req,"home");
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
INSERT INTO comments(
|
||||
postid,
|
||||
author,
|
||||
isanon,
|
||||
comment_text,
|
||||
hashedip,
|
||||
post_time
|
||||
) VALUES (
|
||||
:postid,
|
||||
:authorid,
|
||||
:isanon,
|
||||
:comment_text,
|
||||
'',
|
||||
strftime('%s','now')
|
||||
);
|
|
@ -0,0 +1,11 @@
|
|||
SELECT
|
||||
authors.name,
|
||||
comments.isanon,
|
||||
comments.comment_text
|
||||
FROM
|
||||
comments,
|
||||
authors
|
||||
WHERE
|
||||
comments.author = authors.id AND
|
||||
comments.postid = :id
|
||||
ORDER BY post_time DESC;
|
|
@ -0,0 +1,7 @@
|
|||
SELECT
|
||||
raw_text.post_text, posts.post_title
|
||||
FROM
|
||||
raw_text, posts
|
||||
WHERE
|
||||
raw_text.id = posts.id AND
|
||||
raw_text.id = :postid
|
Loading…
Reference in New Issue