Finished up unlisted posts

Why does anon even want this feature?
This commit is contained in:
Robin Malley 2021-01-11 03:34:22 +00:00
parent 18f47bf708
commit 1a2244b686
23 changed files with 178 additions and 48 deletions

View File

@ -47,6 +47,7 @@ domain * {
route /_edit edit_story
route /_bio edit_bio
route /_login login
route /_logout logout
route ^/_claim claim
route /_download download
route /_preview preview
@ -59,6 +60,7 @@ domain * {
}
params get /_download {
validate story v_storyid
validate pwd v_hex_128
}
params post /_edit {
validate title v_any
@ -95,6 +97,7 @@ domain * {
params post ^/[^_].* {
validate text v_any
validate postas v_subdomain
validate pwd v_hex_128
}
params post /_login {
validate user v_subdomain

View File

@ -18,6 +18,8 @@ local function download_get(req)
local path = http_request_get_path(req)
http_request_populate_qs(req)
local story = assert(http_argument_get_string(req,"story"))
local hashstr = http_argument_get_string(req,"pwd")
local ihash = hashstr and util.decode_unlisted(hashstr)
story = util.decodeentities(story)
local story_id = util.decode_id(story)
stmnt_download:bind_names{
@ -31,7 +33,14 @@ local function download_get(req)
return
end
assert(err == sql.ROW, "after doing download sql, result was not a row, was:" .. tostring(err))
local txt_compressed, title = unpack(stmnt_download:get_values())
local txt_compressed, title, unlisted, hash = unpack(stmnt_download:get_values())
unlisted = unlisted == 1
if unlisted and hash ~= ihash then
--Unlisted and hash was incorrect, pretend we don't have it
http_response(req,404,pages.nostory{path=story})
stmnt_download:reset()
return
end
local text = zlib.decompress(txt_compressed)
stmnt_download:reset()
http_response_header(req,"Content-Type","application/octet-stream")

View File

@ -45,7 +45,8 @@ local function edit_get(req)
end
assert(err == sql.ROW)
local data = stmnt_edit:get_values()
local txt_compressed, markup, isanon, title = unpack(data)
local txt_compressed, markup, isanon, title, unlisted = unpack(data)
print("from query, unlisted was:",unlisted)
local text = zlib.decompress(txt_compressed)
local tags = tags.get(story_id)
local tags_txt = table.concat(tags,";")
@ -59,7 +60,8 @@ local function edit_get(req)
domain = config.domain,
story = story_id,
err = "",
tags = tags_txt
tags = tags_txt,
unlisted = unlisted
}
http_response(req,200,ret)
end

View File

@ -18,6 +18,7 @@ function configure(...)
stmnt_author_of = assert(db.conn:prepare(queries.select_author_of_post))
stmnt_update_raw = assert(db.conn:prepare(queries.update_raw))
stmnt_update = assert(db.conn:prepare(queries.update_post))
stmnt_hash = assert(db.conn:prepare(queries.select_post_hash))
return oldconfigure(...)
end
@ -33,6 +34,7 @@ local function edit_post(req)
local pasteas = assert(http_argument_get_string(req,"pasteas"))
local markup = assert(http_argument_get_string(req,"markup"))
local unlisted = http_argument_get_string(req,"unlisted") == "on"
print("unlisted was:",unlisted)
local tags_str = http_argument_get_string(req,"tags")
stmnt_author_of:bind_names{
id = storyid
@ -61,13 +63,23 @@ local function edit_post(req)
assert(stmnt_update:bind(1,title) == sql.OK)
assert(stmnt_update:bind_blob(2,compr) == sql.OK)
assert(stmnt_update:bind(3,pasteas == "anonymous" and 1 or 0) == sql.OK)
assert(stmnt_update:bind(4,storyid) == sql.OK)
assert(stmnt_update:bind(5,unlisted) == sql.OK)
assert(stmnt_update:bind(4,unlisted) == sql.OK)
assert(stmnt_update:bind(5,storyid) == sql.OK)
assert(util.do_sql(stmnt_update) == sql.DONE, "Failed to update text")
stmnt_update:reset()
tagslib.set(storyid,tags)
local id_enc = util.encode_id(storyid)
local hash
local loc = string.format("https://%s/%s",config.domain,id_enc)
if unlisted then
stmnt_hash:bind_names{id=storyid}
local err = util.do_sql(stmnt_hash)
if err ~= sql.ROW then
error("Failed to get a post's hash while trying to make it unlisted")
end
local hash = stmnt_hash:get_value(0)
loc = loc .. "?pwd=" .. util.encode_unlisted(hash)
end
--Turning something from not unlisted to unlisted should dirty all these
--places anyway, so the post can now be hidden.
cache.dirty(string.format("%s/%s",config.domain,id_enc)) -- This place to read this post

View File

@ -7,6 +7,7 @@ local util = require("util")
local config = require("config")
local pages = require("pages")
local libtags = require("tags")
local session = require("session")
local stmnt_index, stmnt_author, stmnt_author_bio
@ -21,7 +22,7 @@ function configure(...)
return oldconfigure(...)
end
local function get_site_home(req)
local function get_site_home(req, loggedin)
log(LOG_DEBUG,"Cache miss, rendering site index")
stmnt_index:bind_names{}
local latest = {}
@ -38,14 +39,17 @@ local function get_site_home(req)
end
return pages.index{
domain = config.domain,
stories = latest
stories = latest,
loggedin = loggedin
}
end
local function get_author_home(req)
print("Looking at author home...")
local host = http_request_get_host(req)
local subdomain = host:match("([^\\.]+)")
stmnt_author_bio:bind_names{author=subdomain}
local err = util.do_sql(stmnt_author_bio)
local author, authorid = session.get(req)
if err == sql.DONE then
log(LOG_INFO,"No such author:" .. subdomain)
stmnt_author_bio:reset()
@ -59,19 +63,35 @@ local function get_author_home(req)
stmnt_author_bio:reset()
stmnt_author:bind_names{author=subdomain}
local stories = {}
for id, title, time, hits in util.sql_rows(stmnt_author) do
table.insert(stories,{
url = util.encode_id(id),
title = title,
author=subdomain,
posted = os.date("%B %d %Y",tonumber(time)),
tags = libtags.get(id),
hits = hits,
})
for id, title, time, hits, unlisted, hash in util.sql_rows(stmnt_author) do
print("Looking at:",id,title,time,hits,unlisted)
if unlisted == 1 and author == subdomain then
local url = util.encode_id(id) .. "?pwd=" .. util.encode_unlisted(hash)
table.insert(stories,{
url = url,
title = title,
author=subdomain,
posted = os.date("%B %d %Y",tonumber(time)),
tags = libtags.get(id),
hits = hits,
unlisted = true,
})
elseif unlisted == 0 then
table.insert(stories,{
url = util.encode_id(id),
title = title,
author=subdomain,
posted = os.date("%B %d %Y",tonumber(time)),
tags = libtags.get(id),
hits = hits,
unlisted = false,
})
end
end
return pages.author_index{
domain=config.domain,
author=subdomain,
loggedin = author,
stories=stories,
bio=bio
}
@ -82,19 +102,28 @@ local function index_get(req)
local method = http_method_text(req)
local host = http_request_get_host(req)
local subdomain = host:match("([^\\.]+)")
local author, authorid = session.get(req)
local text
if host == config.domain then
if host == config.domain and author == nil then
--Default home page
local cachepath = string.format("%s",config.domain)
text = cache.render(cachepath, function()
return get_site_home(req)
end)
else
elseif host == config.domain and author then
--Display home page with "log out" button
text = cache.render(config.domain .. "-logout", function()
return get_site_home(req,true)
end)
elseif host ~= config.domain and author ~= subdomain then
--author home page
local cachepath = string.format("%s.%s",subdomain,config.domain)
text = cache.render(cachepath, function()
return get_author_home(req)
end)
elseif host ~= config.domain and author == subdomain then
--author's home page for the author, don't cache, display unlisted
text = get_author_home(req)
end
assert(text)
http_response(req,200,text)

View File

@ -0,0 +1,11 @@
local session = require("session")
local config = require("config")
local function logout(req)
local author, authorid = session.get(req)
session.finish(authorid)
http_response_header(req,"Location","https://" .. config.domain)
http_response(req,303,"")
end
return logout

View File

@ -13,6 +13,7 @@ local function paste_get(req)
http_response(req,303,"")
return
elseif host == config.domain and author == nil then
print("doing anon paste")
text = cache.render(string.format("%s/_paste",host),function()
log(LOG_DEBUG, "Cache missing, rendering post page")
return assert(pages.paste{
@ -22,6 +23,7 @@ local function paste_get(req)
end)
http_response(req,200,text)
elseif host ~= config.domain and author then
print("doing author paste")
text = assert(pages.author_paste{
domain = config.domain,
user = author,

View File

@ -102,6 +102,7 @@ local function author_paste(req,ps)
}
end
local asanon = assert(http_argument_get_string(req,"pasteas"))
local textsha3 = sha3(ps.text .. get_random_bytes(32))
--No need to check if the author is posting to the
--"right" sudomain, just post it to the one they have
--the session key for.
@ -111,12 +112,15 @@ local function author_paste(req,ps)
assert(stmnt_paste:bind(4,asanon == "anonymous") == sql.OK)
assert(stmnt_paste:bind_blob(5,"") == sql.OK)
util.sqlbind(stmnt_paste,"bind",6,ps.unlisted)
util.sqlbind(stmnt_paste,"bind_blob",7,sha3(ps.text))
util.sqlbind(stmnt_paste,"bind_blob",7,textsha3)
err = util.do_sql(stmnt_paste)
stmnt_paste:reset()
if err == sql.DONE then
local rowid = stmnt_paste:last_insert_rowid()
local url = util.encode_id(rowid)
if ps.unlisted then
url = url .. "?pwd=" .. util.encode_unlisted(textsha3)
end
assert(stmnt_raw:bind(1,rowid) == sql.OK)
assert(stmnt_raw:bind_blob(2,ps.raw) == sql.OK)
assert(stmnt_raw:bind(3,ps.markup) == sql.OK)

View File

@ -41,8 +41,6 @@ local function populate_ps_story(req,ps)
stmnt_read:bind_names{
id = ps.storyid,
}
print("populating, hash was:",ps.hash)
stmnt_read:bind(2,ps.hash or "")
local err = util.do_sql(stmnt_read)
if err == sql.DONE then
--We got no story
@ -53,9 +51,15 @@ local function populate_ps_story(req,ps)
--If we've made it here, we have a story. Populate our settings
--with title, text, ect.
assert(err == sql.ROW)
local title, storytext, tauthor, isanon, authorname, views = unpack(
local title, storytext, tauthor, isanon, authorname, views, unlisted, hash = unpack(
stmnt_read:get_values()
)
ps.unlisted = unlisted == 1
if ps.unlisted and hash ~= ps.hash then
log(LOG_DEBUG,"Tried to get story id:" .. ps.storyid .. " but it was unlisted and hash was incorrect.")
stmnt_read:reset()
return false
end
ps.title = title
ps.text = zlib.decompress(storytext)
ps.tauthor = tauthor
@ -101,7 +105,6 @@ local function read_get(req)
ps.storyid = util.decode_id(ps.idp)
add_view(ps.storyid)
--If we're logged in, set author and authorid
local author, authorid = session.get(req)
if author and authorid then
@ -119,12 +122,11 @@ local function read_get(req)
--If this post is unlisted, get the hash
local hashstr = http_argument_get_string(req,"pwd")
print("hashstr was:",hashstr)
if hashstr then
ps.hash = util.decode_unlisted(hashstr)
ps.hashstr = hashstr
end
local text
--normal story display
if (not ps.loggedauthor) then

View File

@ -24,6 +24,7 @@ local function read_post(req)
local author, authorid = session.get(req)
local comment_text = assert(http_argument_get_string(req,"text"))
local pasteas = assert(http_argument_get_string(req,"postas"))
local hashstr = http_argument_get_string(req,"pwd")
local idp = string.sub(path,2)--remove leading "/"
local id = util.decode_id(idp)
local isanon = 1
@ -42,9 +43,10 @@ local function read_post(req)
if err ~= sql.DONE then
http_response(req,500,"Internal error, failed to post comment. Go back and try again.")
else
local needspwd = hashstr and "&pwd=" .. hashstr or ""
--When we post a comment, we need to dirty the cache for the "comments displayed" page.
cache.dirty(string.format("%s%s?comments=1",host,path))
local redir = string.format("https://%s%s?comments=1", config.domain, path)
cache.dirty(string.format("%s%s?comments=1%s",host,path,needspwd))
local redir = string.format("https://%s%s?comments=1%s", config.domain, path, needspwd)
http_response_header(req,"Location",redir)
http_response(req,303,"")
end

View File

@ -29,6 +29,7 @@ local endpoint_names = {
paste = {"get","post"},
download = {"get"},
login = {"get","post"},
logout = {"get"},
edit = {"get","post"},
claim = {"get","post"},
search = {"get"},
@ -102,6 +103,10 @@ function login(req)
end
end
function logout(req)
endpoints.logout_get(req)
end
--Edit a story
function edit(req)
local method = http_method_text(req)

View File

@ -9,6 +9,7 @@ local stmnt_get_session, stmnt_insert_session
function configure(...)
stmnt_get_session = assert(db.conn:prepare(queries.select_valid_sessions))
stmnt_insert_session = assert(db.conn:prepare(queries.insert_session))
stmnt_delete_session = assert(db.conn:prepare(queries.delete_session))
return oldconfigure(...)
end
@ -61,4 +62,19 @@ function session.start(who)
return session
end
--[[
End a session, log someone out
]]
function session.finish(who,sessionid)
stmnt_delete_session:bind_names{
authorid = who,
sessionid = sessionid
}
local err = util.do_sql(stmnt_delete_session)
stmnt_delete_session:reset()
assert(err == sql.DONE)
return true
end
return session

View File

@ -6,7 +6,7 @@
<form action="https://<%= user %>.<%= domain %>/_edit" method="post" class="container">
<fieldset>
<div class="row">
<input type="text" name="title" placeholder="Title" class="column column-80" value="<%= title %>"></input>
<input type="text" name="title" placeholder="Title" class="column column-70" value="<%= title %>"></input>
<input type="hidden" name="story" value="<%= story %>">
<select id="pasteas" name="pasteas" class="column column-10">
<% if isanon then %>
@ -21,6 +21,18 @@
<option value="plain">Plain</option>
<option value="imageboard">Imageboard</option>
</select>
<div class="column column-10">
<label for="unlisted" class="label-inline">Unlisted</label>
<input
type="checkbox"
name="unlisted"
id="unlisted"
<% if unlisted then %>
checked
<% end %>
>
</input>
</div>
</div>
<div class="row">
<input type="text" name="tags" value="<%= tags %>" placeholder="Tags (semicolon;seperated)" class="column"></input>

View File

@ -1,5 +1,9 @@
<tr><td>
<% if unlisted then %>
&#9940;
<% end %>
</td><td>
<a href="<%= story.url %>">
<%- story.title %>
</a>

View File

@ -17,6 +17,12 @@
By <a href="https://<%= author %>.<%= domain %>"><%= author %></a>
<% end -%>
</h3>
<ul class="tag-list">
<% for _,tag in pairs(tags) do -%>
<{system cat src/pages/parts/taglist.etlua}>
<% end -%>
</ul>
<%- text %>
</article>
@ -24,23 +30,26 @@
<p><%= views %> Hits</p>
<ul class="tag-list">
<% for _,tag in pairs(tags) do -%>
<{system cat src/pages/parts/taglist.etlua}>
<% end -%>
</ul>
<form action="https://<%= domain %>/_download" method="get">
<input type="hidden" name="story" value="<%= idp %>"/>
<% if unlisted then %>
<input type="hidden" name="pwd" value="<%= hashstr %>"/>
<% end %>
<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">
<% if unlisted then %>
<input type="hidden" name="pwd" value="<%= hashstr %>"/>
<% end %>
<input type="submit" value="load comments" class="button">
</fieldset></form>
<% else %>
<form action="https://<%= domain %>/<%= idp %>" method="POST">
<% if unlisted then %>
<input type="hidden" name="pwd" value="<%= hashstr %>"/>
<% end %>
<textarea name="text" cols=60 rows=10 class="column"></textarea>
</div><% if iam then %>
<select id="postas" name="postas">

View File

@ -9,6 +9,7 @@ FROM
posts,authors
WHERE
authors.id = posts.authorid
AND posts.unlisted = 0
<% for field, values in pairs(result) do -%>
<% for _,value in pairs(values) do -%>
<% local pn,expr,value = unpack(value) -%>

View File

@ -20,6 +20,7 @@ int edit_story(struct http_request *);
int edit_bio(struct http_request *);
int read_story(struct http_request *);
int login(struct http_request *);
int logout(struct http_request *);
int claim(struct http_request *);
int download(struct http_request *);
int preview(struct http_request *);
@ -129,6 +130,12 @@ login(struct http_request *req){
return do_lua(req,"login");
}
int
logout(struct http_request *req){
printf("We want to log out!\n");
return do_lua(req,"logout");
}
int
claim(struct http_request *req){
printf("We want to claim!\n");

View File

@ -0,0 +1 @@
DELETE FROM sessions WHERE author = :authorid;

View File

@ -4,14 +4,15 @@ SELECT
posts.id,
posts.post_title,
posts.post_time,
posts.views
posts.views,
posts.unlisted,
posts.hash
FROM
posts,
authors
WHERE
posts.isanon = 0 AND
posts.authorid = authors.id AND
authors.name = :author AND
posts.unlisted = 0
authors.name = :author
ORDER BY
posts.post_time DESC

View File

@ -1,8 +1,7 @@
SELECT
raw_text.post_text, posts.post_title
raw_text.post_text, posts.post_title, posts.unlisted, posts.hash
FROM
raw_text, posts
WHERE
raw_text.id = posts.id AND
raw_text.id = :postid AND
posts.unlisted = 0
raw_text.id = :postid

View File

@ -1,5 +1,5 @@
SELECT
raw_text.post_text, raw_text.markup, posts.isanon, posts.post_title
raw_text.post_text, raw_text.markup, posts.isanon, posts.post_title, posts.unlisted
FROM
raw_text, posts
WHERE

View File

@ -8,14 +8,11 @@ SELECT
posts.authorid,
posts.isanon,
authors.name,
views
views,
posts.unlisted,
posts.hash
FROM
posts,authors
WHERE
posts.authorid = authors.id AND
posts.id = :id AND
(
posts.unlisted = 1 AND
posts.hash = :hash
) OR
posts.unlisted = 0;
posts.id = :id;

View File

@ -0,0 +1,2 @@
--Get just the hash from the post
SELECT hash FROM posts WHERE posts.id = :id;