Allow users to edit biographies
This commit is contained in:
parent
e25d2fd06a
commit
411bcb494d
36
README.md
36
README.md
|
@ -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
|
||||
|
||||
|
|
|
@ -127,6 +127,7 @@ domain * {
|
|||
methods get post
|
||||
|
||||
validate post text v_any
|
||||
validate post author v_subdomain
|
||||
}
|
||||
|
||||
route /_login {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
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
|
||||
|
|
|
@ -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 = {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
<% end %>
|
||||
<a href="/_bio" class="button column column-0">Edit bio</a>
|
||||
<% end %>
|
||||
<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 %>
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
<div class="row">
|
||||
<textarea name="text" cols=80 rows=24 class="column"><%= text %></textarea><br/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<input type="submit">
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
<{cat src/pages/parts/footer.etlua}>
|
||||
|
|
Loading…
Reference in New Issue