Add a delete button.

Add a delete button to posts that will show up if the user is logged in
and is the owner of a post. If javascript is enabled, the user will be
prompted for conformation before deleting a post.
This commit is contained in:
Robin Malley 2021-10-11 00:59:50 +00:00
parent 81ad49ae80
commit 069c75b72e
8 changed files with 143 additions and 17 deletions

View File

@ -0,0 +1,36 @@
/*
There's a delete buttotn to delete a post. If javascript is enabled, replace
the button with one that will ask for confirmation before deleting.
*/
function delete_intervine(){
var forms = document.getElementsByTagName("form");
if(forms.length == 0){return;}//Don't load if the story is missing.
var delete_form;
for(var i = 0; i < forms.length; i++){
if(forms[i].action.endsWith("_delete")){
delete_form = forms[i];
break;
}
}
if(delete_form == null){return;}//Don't load if we're not logged in
var delete_parent = delete_form.parentNode;
delete_parent.removeChild(delete_form);
var delete_wrapper = document.createElement("div");
var delete_button = document.createElement("button");
delete_button.classList.add("button");
delete_button.classList.add("column");
delete_button.classList.add("column-0");
delete_button.textContent = "Delete";
delete_button.addEventListener("click",function(){
if(confirm("Are you sure you want to delete this story?")){
document.documentElement.appendChild(delete_form);
delete_form.submit();
}
});
delete_parent.appendChild(delete_wrapper);
delete_wrapper.appendChild(delete_button);
}
document.addEventListener("DOMContentLoaded",delete_intervine,false);

View File

@ -46,6 +46,7 @@ domain * {
route /_faq asset_serve_faq_html
route /_js/suggest_tags.js asset_serve_suggest_tags_js
route /_js/bookmark.js asset_serve_bookmark_js
route /_js/intervine_deletion.js asset_serve_intervine_deletion_js
route /favicon.ico asset_serve_favicon_ico
route /_paste post_story
route /_edit edit_story
@ -58,6 +59,7 @@ domain * {
route /_search search
route /_archive archive
route /_api api
route /_delete delete
# Leading ^ is needed for dynamic routes, kore says the route is dynamic if it does not start with '/'
route ^/[^_].* read_story
@ -119,4 +121,7 @@ domain * {
validate call v_any
validate data v_any
}
params post /_delete {
validate story v_storyid
}
}

View File

@ -0,0 +1,64 @@
local tags = require("tags")
local util = require("util")
local pages = require("pages")
local config = require("config")
local session = require("session")
local db = require("db")
local queries = require("queries")
local sql = require("lsqlite3")
local cache = require("cache")
local oldconfigure = configure
local stmnt_delete
function configure(...)
stmnt_delete = assert(db.conn:prepare(queries.delete_post),db.conn:errmsg())
return oldconfigure(...)
end
local function delete_post(req)
local host = http_request_get_host(req)
local path = http_request_get_path(req)
http_request_populate_post(req)
local storystr = assert(http_argument_get_string(req,"story"))
print("Looking at storystr:",storystr)
local storyid = util.decode_id(storystr)
local author, authorid = session.get(req)
if not author then
http_response(req, 401, pages.error{
errcode = 401,
errcodemsg = "Not authorized",
explanation = "You must be logged in to delete posts. You are either not logged in or your session has expired.",
should_traceback = true
})
return
end
log(LOG_DEBUG,string.format("Deleting post %d with proposed owner %d",storyid, authorid))
stmnt_delete:bind_names{
postid = storyid,
authorid = authorid
}
local err = util.do_sql(stmnt_delete)
if err ~= sql.DONE then
log(LOG_DEBUG,string.format("Failed to delete: %d:%s",err, db.conn:errmsg()))
http_response(req,500,pages.error{
errcode = 500,
errcodemsg = "Internal error",
explanation = "Failed to delete posts from database:" .. db.conn:errmsg(),
should_traceback = true,
})
stmnt_delete:reset()
else
local loc = string.format("https://%s/%s",config.domain,storystr)
http_response_header(req,"Location",loc)
http_response(req,303,"")
stmnt_delete:reset()
cache.dirty(string.format("%s",config.domain))
cache.dirty(string.format("%s-logout",config.domain))
cache.dirty(string.format("%s.%s",author,config.domain))
cache.dirty(string.format("%s",storystr))
cache.dirty(string.format("%s?comments=1",storystr))
end
end
return delete_post

View File

@ -99,7 +99,8 @@ local function read_get(req)
path = http_request_get_path(req),
method = http_method_text(req),
extra_load = {
'<script src="/_js/bookmark.js"></script>'
'<script src="/_js/bookmark.js"></script>',
'<script src="/_js/intervine_deletion.js"></script>',
}
}
local err

View File

@ -35,6 +35,7 @@ local endpoint_names = {
search = {"get"},
archive = {"get"},
api = {"get"},
delete = {"post"},
}
local endpoints = {}
for name, methods in pairs(endpoint_names) do
@ -119,6 +120,10 @@ function edit(req)
end
end
function delete(req)
endpoints.delete_post(req)
end
--TODO
function edit_bio()
error("Not yet implemented")

View File

@ -3,10 +3,16 @@
<a href="https://<%= domain %>"><%= domain %></a>/<a href="https://<%= domain %>/<%= idp %>"><%= idp %></a>
</nav>
<% if owner then -%>
<div class="row">
<form action="https://<%= domain %>/_edit" method="get"><fieldset>
<input type="hidden" name="story" value="<%= idp %>"/>
<input type="submit" value="edit" class="button"/>
<input type="submit" value="edit" class="button column column-0"/>
</fieldset></form>
<form action="https://<%= domain %>/_delete" method="post"><fieldset>
<input type="hidden" name="story" value="<%= idp %>"/>
<input type="submit" value="delete" class="button column column-0"/>
</fieldset></form>
</div>
<% end -%>
<article>
<h2 class="title"> <%- title %> </h2>

View File

@ -29,6 +29,7 @@ int archive(struct http_request *);
int api(struct http_request *);
int style(struct http_request *);
int miligram(struct http_request *);
int delete(struct http_request *);
int do_lua(struct http_request *req, const char *name);
int errhandeler(lua_State *);
lua_State *L;
@ -56,26 +57,26 @@ KORE_SECCOMP_FILTER("app",
);
int
errhandeler(lua_State *L){
printf("Error: %s\n",lua_tostring(L,1));//"error"
lua_getglobal(L,"debug");//"error",{debug}
lua_getglobal(L,"print");//"error",{debug},print()
lua_getfield(L,-2,"traceback");//"error",{debug},print(),traceback()
lua_call(L,0,1);//"error",{debug},print(),"traceback"
lua_call(L,1,0);//"error",{debug}
errhandeler(lua_State *state){
printf("Error: %s\n",lua_tostring(state,1));//"error"
lua_getglobal(state,"debug");//"error",{debug}
lua_getglobal(state,"print");//"error",{debug},print()
lua_getfield(state,-2,"traceback");//"error",{debug},print(),traceback()
lua_call(state,0,1);//"error",{debug},print(),"traceback"
lua_call(state,1,0);//"error",{debug}
printf("Called print()\n");
lua_getfield(L,-1,"traceback");//"error",{debug},traceback()
lua_getfield(state,-1,"traceback");//"error",{debug},traceback()
printf("got traceback\n");
lua_call(L,0,1);//"error",{debug},"traceback"
lua_pushstring(L,"\n");
lua_call(state,0,1);//"error",{debug},"traceback"
lua_pushstring(state,"\n");
printf("called traceback\n");
lua_pushvalue(L,-4);//"error",{debug},"traceback","error"
lua_pushvalue(state,-4);//"error",{debug},"traceback","error"
printf("pushed error\n");
lua_concat(L,3);//"error",{debug},"traceback .. error"
lua_concat(state,3);//"error",{debug},"traceback .. error"
printf("concated\n");
int ref = luaL_ref(L,LUA_REGISTRYINDEX);//"error",{debug}
lua_pop(L,2);//
lua_rawgeti(L,LUA_REGISTRYINDEX,ref);//"traceback .. error"
int ref = luaL_ref(state,LUA_REGISTRYINDEX);//"error",{debug}
lua_pop(state,2);//
lua_rawgeti(state,LUA_REGISTRYINDEX,ref);//"traceback .. error"
return 1;
}
@ -179,6 +180,11 @@ home(struct http_request *req){
return do_lua(req,"home");
}
int
delete(struct http_request *req){
return do_lua(req,"delete");
}
void
kore_worker_configure(void){
printf("Configuring worker...\n");

3
src/sql/delete_post.sql Normal file
View File

@ -0,0 +1,3 @@
DELETE FROM posts
WHERE posts.id = :postid AND
posts.authorid = :authorid