add post editing
This commit is contained in:
parent
738b4163a8
commit
e7260090ac
1
app.lua
1
app.lua
@ -35,6 +35,7 @@ app:include("apps.users", {path = "/user"})
|
|||||||
app:include("apps.topics", {path = "/topics"})
|
app:include("apps.topics", {path = "/topics"})
|
||||||
app:include("apps.threads", {path = "/threads"})
|
app:include("apps.threads", {path = "/threads"})
|
||||||
app:include("apps.mod", {path = "/mod"})
|
app:include("apps.mod", {path = "/mod"})
|
||||||
|
app:include("apps.post", {path = "/post"})
|
||||||
|
|
||||||
app:get("/", function(self)
|
app:get("/", function(self)
|
||||||
return {redirect_to = self:url_for("all_topics")}
|
return {redirect_to = self:url_for("all_topics")}
|
||||||
|
75
apps/post.lua
Normal file
75
apps/post.lua
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
local app = require("lapis").Application()
|
||||||
|
|
||||||
|
local db = require("lapis.db")
|
||||||
|
local constants = require("constants")
|
||||||
|
|
||||||
|
local util = require("util")
|
||||||
|
|
||||||
|
local models = require("models")
|
||||||
|
local Posts = models.Posts
|
||||||
|
local Threads = models.Threads
|
||||||
|
|
||||||
|
|
||||||
|
app:get("single_post", "/:post_id", function(self)
|
||||||
|
local query = constants.FULL_POSTS_QUERY .. "WHERE posts.id = ?"
|
||||||
|
local p = db.query(query, self.params.post_id)
|
||||||
|
if p then
|
||||||
|
self.post = p[1]
|
||||||
|
self.thread = Threads:find({id = self.post.thread_id})
|
||||||
|
self.page_title = self.post.username .. "'s post in " .. self.thread.title
|
||||||
|
end
|
||||||
|
|
||||||
|
return {render = "post.single-post"}
|
||||||
|
end)
|
||||||
|
|
||||||
|
app:get("edit_post", "/:post_id/edit", function(self)
|
||||||
|
local user = util.get_logged_in_user(self)
|
||||||
|
if not user then
|
||||||
|
return {redirect_to = self:url_for"all_topics"}
|
||||||
|
end
|
||||||
|
|
||||||
|
local editing_query = constants.FULL_POSTS_QUERY .. "WHERE posts.id = ?"
|
||||||
|
local p = db.query(editing_query, self.params.post_id)
|
||||||
|
if not p then
|
||||||
|
return {redirect_to = self:url_for"all_topics"}
|
||||||
|
end
|
||||||
|
if p[1].user_id ~= user.id then
|
||||||
|
return {redirect_to = self:url_for"all_topics"}
|
||||||
|
end
|
||||||
|
self.me = user
|
||||||
|
self.editing_post = p[1]
|
||||||
|
self.thread = Threads:find({id = self.editing_post.thread_id})
|
||||||
|
|
||||||
|
local thread_predicate = constants.FULL_POSTS_QUERY .. "WHERE posts.thread_id = ?\n"
|
||||||
|
|
||||||
|
local context_prev_query = thread_predicate .. "AND posts.created_at < ? ORDER BY posts.created_at DESC LIMIT 2"
|
||||||
|
local context_next_query = thread_predicate .. "AND posts.created_at > ? ORDER BY posts.created_at ASC LIMIT 2"
|
||||||
|
|
||||||
|
self.prev_context = db.query(context_prev_query, self.thread.id, self.editing_post.created_at)
|
||||||
|
self.next_context = db.query(context_next_query, self.thread.id, self.editing_post.created_at)
|
||||||
|
|
||||||
|
return {render = "post.edit-post"}
|
||||||
|
end)
|
||||||
|
|
||||||
|
app:post("edit_post", "/:post_id/edit", function(self)
|
||||||
|
local user = util.get_logged_in_user(self)
|
||||||
|
if not user then
|
||||||
|
return {redirect_to = self:url_for("all_topics")}
|
||||||
|
end
|
||||||
|
|
||||||
|
local post = Posts:find({id = self.params.post_id})
|
||||||
|
if not post then
|
||||||
|
return {redirect_to = self:url_for("all_topics")}
|
||||||
|
end
|
||||||
|
|
||||||
|
if post.user_id ~= user.id then
|
||||||
|
return {redirect_to = self:url_for("all_topics")}
|
||||||
|
end
|
||||||
|
|
||||||
|
util.update_post(post, self.params.new_content)
|
||||||
|
local thread = Threads:find({id = post.thread_id})
|
||||||
|
local link = self:url_for("thread", {slug = thread.slug}, {after = post.id}) .. "#post-" .. post.id
|
||||||
|
return {redirect_to = link}
|
||||||
|
end)
|
||||||
|
|
||||||
|
return app
|
@ -1,5 +1,6 @@
|
|||||||
local app = require("lapis").Application()
|
local app = require("lapis").Application()
|
||||||
local lapis_util = require("lapis.util")
|
local lapis_util = require("lapis.util")
|
||||||
|
local constants = require("constants")
|
||||||
|
|
||||||
local db = require("lapis.db")
|
local db = require("lapis.db")
|
||||||
local util = require("util")
|
local util = require("util")
|
||||||
@ -89,23 +90,9 @@ app:get("thread", "/:slug", function(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- self.page = math.max(1, math.min(self.page, self.pages))
|
-- self.page = math.max(1, math.min(self.page, self.pages))
|
||||||
local posts = db.query([[
|
local query = (constants.FULL_POSTS_QUERY ..
|
||||||
SELECT
|
"WHERE posts.thread_id = ? ORDER BY posts.created_at ASC LIMIT ? OFFSET ?")
|
||||||
posts.id, posts.created_at, post_history.content, post_history.edited_at, users.username, users.status, avatars.file_path AS avatar_path
|
local posts = db.query(query, thread.id, POSTS_PER_PAGE, (self.page - 1) * POSTS_PER_PAGE)
|
||||||
FROM
|
|
||||||
posts
|
|
||||||
JOIN
|
|
||||||
post_history ON posts.current_revision_id = post_history.id
|
|
||||||
JOIN
|
|
||||||
users ON posts.user_id = users.id
|
|
||||||
LEFT JOIN
|
|
||||||
avatars ON users.avatar_id = avatars.id
|
|
||||||
WHERE
|
|
||||||
posts.thread_id = ?
|
|
||||||
ORDER BY
|
|
||||||
posts.created_at ASC
|
|
||||||
LIMIT ? OFFSET ?
|
|
||||||
]], thread.id, POSTS_PER_PAGE, (self.page - 1) * POSTS_PER_PAGE)
|
|
||||||
self.topic = Topics:find(thread.topic_id)
|
self.topic = Topics:find(thread.topic_id)
|
||||||
self.me = util.get_logged_in_user_or_transient(self)
|
self.me = util.get_logged_in_user_or_transient(self)
|
||||||
self.posts = posts
|
self.posts = posts
|
||||||
|
@ -8,6 +8,19 @@ Constants.PermissionLevel = {
|
|||||||
ADMIN = 4,
|
ADMIN = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Constants.FULL_POSTS_QUERY = [[
|
||||||
|
SELECT
|
||||||
|
posts.id, posts.created_at, post_history.content, post_history.edited_at, users.username, users.status, avatars.file_path AS avatar_path, posts.thread_id, users.id AS user_id, post_history.original_markup
|
||||||
|
FROM
|
||||||
|
posts
|
||||||
|
JOIN
|
||||||
|
post_history ON posts.current_revision_id = post_history.id
|
||||||
|
JOIN
|
||||||
|
users ON posts.user_id = users.id
|
||||||
|
LEFT JOIN
|
||||||
|
avatars ON users.avatar_id = avatars.id
|
||||||
|
]]
|
||||||
|
|
||||||
Constants.PermissionLevelString = {
|
Constants.PermissionLevelString = {
|
||||||
[Constants.PermissionLevel.GUEST] = "Guest",
|
[Constants.PermissionLevel.GUEST] = "Guest",
|
||||||
[Constants.PermissionLevel.USER] = "User",
|
[Constants.PermissionLevel.USER] = "User",
|
||||||
|
@ -377,3 +377,23 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus
|
|||||||
.draggable-topic.dragged {
|
.draggable-topic.dragged {
|
||||||
background-color: rgb(177, 206, 204.5);
|
background-color: rgb(177, 206, 204.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editing {
|
||||||
|
background-color: rgb(217.26, 220.38, 213.42);
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-explain {
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-edit-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: baseline;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.post-edit-form > textarea {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
@ -381,3 +381,24 @@ input[type="text"], input[type="password"], textarea, select {
|
|||||||
background-color: $button_color;
|
background-color: $button_color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editing {
|
||||||
|
background-color: $light;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-explain {
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-edit-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: baseline;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&>textarea{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
21
util.lua
21
util.lua
@ -242,6 +242,27 @@ function util.create_post(thread_id, user_id, content, markup_language)
|
|||||||
return post
|
return post
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function util.update_post(post, new_content, markup_language)
|
||||||
|
markup_language = markup_language or "babycode"
|
||||||
|
db.query("BEGIN")
|
||||||
|
|
||||||
|
local parsed_content = ""
|
||||||
|
if markup_language == "babycode" then
|
||||||
|
parsed_content = babycode.to_html(new_content, html_escape)
|
||||||
|
end
|
||||||
|
|
||||||
|
local revision = PostHistory:create({
|
||||||
|
post_id = post.id,
|
||||||
|
content = parsed_content,
|
||||||
|
is_initial_revision = false,
|
||||||
|
original_markup = new_content,
|
||||||
|
markup_language = markup_language
|
||||||
|
})
|
||||||
|
|
||||||
|
post:update({current_revision_id = revision.id})
|
||||||
|
db.query("COMMIT")
|
||||||
|
end
|
||||||
|
|
||||||
function util.transfer_and_delete_user(user)
|
function util.transfer_and_delete_user(user)
|
||||||
local deleted_user = Users:find({
|
local deleted_user = Users:find({
|
||||||
username = "DeletedUser",
|
username = "DeletedUser",
|
||||||
|
16
views/post/edit-post.etlua
Normal file
16
views/post/edit-post.etlua
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<% for _, post in ipairs(prev_context) do %>
|
||||||
|
<% render("views.threads.post", {post = post, edit = false, is_latest = false, no_reply = true}) %>
|
||||||
|
<% end %>
|
||||||
|
<span class="context-explain">
|
||||||
|
<span>↑↑↑</span><i>Context</i><span>↑↑↑</span>
|
||||||
|
</span>
|
||||||
|
<% if infobox then %>
|
||||||
|
<% render("views.common.infobox", infobox) %>
|
||||||
|
<% end %>
|
||||||
|
<% render("views.threads.post", {post = editing_post, edit = true, is_latest = false, no_reply = true}) %>
|
||||||
|
<span class="context-explain">
|
||||||
|
<span>↓↓↓</span><i>Context</i><span>↓↓↓</span>
|
||||||
|
</span>
|
||||||
|
<% for _, post in ipairs(next_context) do %>
|
||||||
|
<% render("views.threads.post", {post = post, edit = false, is_latest = false, no_reply = true}) %>
|
||||||
|
<% end %>
|
9
views/post/single-post.etlua
Normal file
9
views/post/single-post.etlua
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<% if not post then %>
|
||||||
|
<% render("views.common.infobox", {kind = constants.InfoboxKind.ERROR, msg = "Post not found"}) %>
|
||||||
|
<% else %>
|
||||||
|
<div class=darkbg>
|
||||||
|
<h1 class=thread-title><%= post.username .. "'s post in " .. thread.title %></h1>
|
||||||
|
</div>
|
||||||
|
<% render("views.threads.post", {post = post, edit = false, is_latest = false, no_reply = true}) %>
|
||||||
|
<a class=linkbutton href="<%= url_for("thread", {slug = thread.slug}, {after = post.id}) .. "#post-" .. post.id %>">View in context</a>
|
||||||
|
<% end %>
|
@ -1,4 +1,10 @@
|
|||||||
<div class="post" id="post-<%= post.id %>">
|
<%
|
||||||
|
local pc = "post"
|
||||||
|
if edit then
|
||||||
|
pc = pc .. " editing"
|
||||||
|
end
|
||||||
|
%>
|
||||||
|
<div class="<%= pc %>" id="post-<%= post.id %>">
|
||||||
<div class="usercard">
|
<div class="usercard">
|
||||||
<a href="<%= url_for("user", {username = post.username}) %>" style="display: contents;">
|
<a href="<%= url_for("user", {username = post.username}) %>" style="display: contents;">
|
||||||
<img src="<%= post.avatar_path %>" class="avatar">
|
<img src="<%= post.avatar_path %>" class="avatar">
|
||||||
@ -8,19 +14,52 @@
|
|||||||
<em class="user-status"><%= post.status %></em>
|
<em class="user-status"><%= post.status %></em>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="post-content-container"<%= is_latest and 'id=latest-post' or "" %>>
|
<div class="post-content-container"<%= is_latest and 'id=latest-post' or "" %>>
|
||||||
<div class="post-info">
|
<div class="post-info">
|
||||||
<div><a href="<%= "#post-" .. post.id %>" title="Permalink"><i>
|
<a href="<%= url_for("thread", {slug = thread.slug}, {page = page}) .. "#post-" .. post.id %>" title="Permalink"><i>
|
||||||
<% if tonumber(post.edited_at) > tonumber(post.created_at) then -%>
|
<% if tonumber(post.edited_at) > tonumber(post.created_at) then -%>
|
||||||
Edited at <%= os.date("%c", post.edited_at) %>
|
Edited at <%= os.date("%c", post.edited_at) %>
|
||||||
<% else -%>
|
<% else -%>
|
||||||
Posted at <%= os.date("%c", post.created_at) %>
|
Posted at <%= os.date("%c", post.created_at) %>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
</i></a></div>
|
</i></a>
|
||||||
<div><button>Reply</button></div>
|
<span>
|
||||||
|
<%
|
||||||
|
local show_edit = me.id == post.user_id and not me:is_guest() and not ntob(thread.is_locked) and not no_reply
|
||||||
|
if show_edit then
|
||||||
|
%>
|
||||||
|
<a class="linkbutton" href="<%= url_for("edit_post", {post_id = post.id}) %>">Edit</a>
|
||||||
|
<% end %>
|
||||||
|
<%
|
||||||
|
local show_reply = true
|
||||||
|
if ntob(thread.is_locked) and not me:is_mod() then
|
||||||
|
show_reply = false
|
||||||
|
elseif me:is_guest() then
|
||||||
|
show_reply = false
|
||||||
|
elseif edit then
|
||||||
|
show_reply = false
|
||||||
|
elseif no_reply then
|
||||||
|
show_reply = false
|
||||||
|
end
|
||||||
|
if show_reply then
|
||||||
|
%>
|
||||||
|
<button>Reply</button>
|
||||||
|
<% end %>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="post-content">
|
<div class="post-content">
|
||||||
<%- post.content %>
|
<% if not edit then %>
|
||||||
|
<%- post.content %>
|
||||||
|
<% else %>
|
||||||
|
<form class="post-edit-form" method="post">
|
||||||
|
<textarea name="new_content" required><%- post.original_markup %></textarea>
|
||||||
|
<span>
|
||||||
|
<input type=submit value="Save">
|
||||||
|
<a class="linkbutton warn" href="<%= url_for("thread", {slug = thread.slug}, {page = page}) .. "#post-" .. post.id %>">Cancel</a>
|
||||||
|
</span>
|
||||||
|
</form>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user