Allow users to edit biographies

This commit is contained in:
Robin Malley 2022-11-21 00:32:49 +00:00
parent e25d2fd06a
commit 411bcb494d
8 changed files with 56 additions and 19 deletions

View File

@ -7,7 +7,25 @@ concerns with pastebin.com taking down certain kinds of content. SMR aims to
be small, fast, and secure. It is built on top of [Kore](https://kore.io), using
[luajit](https://luajit.org) to expose a Lua programming environment. It uses
[sqlite3](https://sqlite.org) as it's database. SMR is implemented in about
3.5k SLOC and is expected to never exceed 5k SLOC. Contributions welcome.
4k SLOC and is expected to never exceed 5k SLOC. Contributions welcome.
```
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Lua 36 190 306 1993
C 4 61 116 709
HTML 18 21 0 561
SQL 36 6 35 266
JavaScript 3 19 21 203
CSS 3 4 8 73
C/C++ Header 4 3 0 46
-------------------------------------------------------------------------------
SUM: 104 304 486 3851
-------------------------------------------------------------------------------
```
## Roadmap
@ -15,13 +33,21 @@ be small, fast, and secure. It is built on top of [Kore](https://kore.io), using
* Comments (complete)
* Tags (complete)
* Search (complete)
* Archive (in progress)
* Author biographies
* Kore 4.2.0
* Archive (complete)
* Author biographies (complete)
* Kore 4.2.0 (complete)
* addon api
TODO's:
Currently, people can post comments to unlisted stories even if they don't have
* Currently, people can post comments to unlisted stories even if they don't have
the correct link.
* Find a replacement preprocessor
* The archive is currently generated weekly from a cron job, and served
syncronously. We can generate a zip file on-the-fly instead, and if the client
disconnects, it's fine to drop the whole thing.
* We can simplify a lot of error handling logic by setting sql prepared statements to reset during error unwinding.
* We can simplify a lot of business logic by having requests parse their parameters eagerly.
## Hacking

View File

@ -127,6 +127,7 @@ domain * {
methods get post
validate post text v_any
validate post author v_subdomain
}
route /_login {

View File

@ -30,7 +30,7 @@ local function bio_edit_get(req)
errcodemsg = "Not authorized",
explanation = "You must be logged in to edit your biography."
}
http_response(req,400,ret)
http_response(req,401,ret)
end
--Get the logged in author's bio to display
@ -56,7 +56,7 @@ found, please report this error.
end
assert(err == sql.ROW)
local data = stmnt_bio:get_values()
local bio = unpack(data)
local bio = zlib.decompress(data[1])
stmnt_bio:reset()
ret = pages.edit_bio{
text = bio,

View File

@ -27,16 +27,17 @@ local function edit_bio(req)
http_request_populate_post(req)
local text = assert(http_argument_get_string(req,"text"))
local markup = assert(http_argument_get_string(req,"markup"))
local parsed = parsers[markup](text)
local parsed = parsers.plain(text) -- Make sure the plain parser can deal with it, even though we don't store this result.
local compr_raw = zlib.compress(text)
local compr = zlib.compress(parsed)
assert(stmnt_update_bio:bind_blob(1,compr_raw) == sql.OK)
assert(stmnt_update_bio:bind(2, author_id) == sql.OK)
assert(util.do_sql(stmnt_update_bio) == sql.DONE, "Failed to update biography")
stmnt_update_bio:reset()
if util.do_sql(stmnt_update_bio) ~= sql.DONE then
stmnt_update_bio:reset()
error("Faled to update biography")
end
local loc = string.format("https://%s.%s",author,config.domain)
-- Dirty the cache for the author's index, the only place where the bio is displayed.
cache.dirty(string.format("%s.%s",author,config.domain))
@ -45,4 +46,4 @@ local function edit_bio(req)
return
end
return edit_post
return edit_bio

View File

@ -8,6 +8,7 @@ local config = require("config")
local pages = require("pages")
local libtags = require("tags")
local session = require("session")
local parsers = require("parsers")
local stmnt_index, stmnt_author, stmnt_author_bio
@ -57,9 +58,12 @@ local function get_author_home(req, loggedin)
author = subdomain
}
end
assert(err == sql.ROW,"failed to get author:" .. subdomain .. " error:" .. tostring(err))
if err ~= sql.ROW then
stmnt_author_bio:reset()
error(string.format("Failed to get author %q error: %q",subdomain, tostring(err)))
end
local data = stmnt_author_bio:get_values()
local bio = data[1]
local bio = parsers.plain(zlib.decompress(data[1]))
stmnt_author_bio:reset()
stmnt_author:bind_names{author=subdomain}
local stories = {}

View File

@ -96,11 +96,14 @@ for funcname, spec in pairs({
assert(_G[funcname] == nil, "Tried to overwrite an endpoint, please define endpoints exactly once")
for k,v in pairs(spec) do
assert(http_m_rev[k], "Unknown http method '" .. k .. "' defined for endpoint '" .. funcname .. "'")
assert(type(v) == "function", "Endpoint %s %s must be a function, but was a %s",funcname, k, type(v))
end
_G[funcname] = function(req)
local method = http_method_text(req)
if spec[method] == nil then
log(LOG_NOTICE,string.format("Endpoint %s called with http method %s, but no such route defined.", funcname, method))
log(LOG_WARNING,string.format("Endpoint %s called with http method %s, but no such route defined.", funcname, method))
else
log(LOG_DEBUG,string.format("Endpoint %s called with method %s",funcname,method))
end
spec[method](req)
end

View File

@ -11,8 +11,8 @@
<a href="/_login" class="button column column-0">Log in</a>
<% else %>
<a href="/_logout" class="button column column-0">Log out</a>
<a href="/_bio" class="button column column-0">Edit bio</a>
<% end %>
<a href="/_bio" class="button column column-0">Edit bio</a>
<span class="column column-0"></span>
<form action="https://<%= domain %>/_search" method="get" class="search column row">
<input class="column" type="text" name="q" placeholder="+greentext -dotr +hits>20"/>
@ -20,8 +20,8 @@
</form>
</div>
</div>
<div class="content">
<%= bio %>
<div class="container">
<%- bio %>
</div>
<div class="content">
<% if #stories == 0 then %>

View File

@ -9,7 +9,9 @@
<div class="row">
<textarea name="text" cols=80 rows=24 class="column"><%= text %></textarea><br/>
</div>
<input type="submit">
<div class="row">
<input type="submit">
</div>
</fieldset>
</form>
<{cat src/pages/parts/footer.etlua}>