Implements edit history.

This commit is contained in:
Dominik Picheta 2018-05-18 14:03:35 +01:00
commit d5f1c674c5
5 changed files with 73 additions and 9 deletions

View file

@ -889,14 +889,14 @@ proc selectUser(userRow: seq[string], avatarSize: int=80): User =
)
proc selectPost(postRow: seq[string], skippedPosts: seq[int],
replyingTo: Option[PostLink]): Post =
replyingTo: Option[PostLink], history: seq[PostInfo]): Post =
return Post(
id: postRow[0].parseInt,
replyingTo: replyingTo,
author: selectUser(@[postRow[5], postRow[6], postRow[7], postRow[8]]),
likes: @[], # TODO:
seen: false, # TODO:
history: @[], # TODO:
history: history,
info: PostInfo(
creation: postRow[2].parseInt,
content: postRow[1].rstToHtml()
@ -926,6 +926,20 @@ proc selectReplyingTo(replyingTo: string): Option[PostLink] =
author: some(selectUser(@[row[3], row[4], row[5], row[6]]))
))
proc selectHistory(postId: int): seq[PostInfo] =
const historyQuery = sql"""
select strftime('%s', creation), content from postRevision
where original = ?
order by creation asc;
"""
result = @[]
for row in getAllRows(db, historyQuery, $postId):
result.add(PostInfo(
creation: row[0].parseInt(),
content: row[1].rstToHtml()
))
proc selectThread(threadRow: seq[string]): Thread =
const postsQuery =
sql"""select count(*), strftime('%s', creation) from post
@ -1032,7 +1046,15 @@ proc updatePost(c: TForumData, postId: int, content: string,
raise newForumError("Message needs to be valid RST", @["msg"])
# Update post.
exec(db, crud(crUpdate, "post", "content"), content, $postId)
# - We create a new postRevision entry for our edit.
exec(
db,
crud(crCreate, "postRevision", "content", "original"),
content,
$postId
)
# - We set the FTS to the latest content as searching for past edits is not
# supported.
exec(db, crud(crUpdate, "post_fts", "content"), content, $postId)
# Check if post is the first post of the thread.
if subject.isSome():
@ -1234,7 +1256,8 @@ routes:
if addDetail:
let replyingTo = selectReplyingTo(rows[i][4])
let post = selectPost(rows[i], skippedPosts, replyingTo)
let history = selectHistory(rows[i][0].parseInt())
let post = selectPost(rows[i], skippedPosts, replyingTo, history)
list.posts.add(post)
skippedPosts = @[]
else:
@ -1261,7 +1284,8 @@ routes:
var list: seq[Post] = @[]
for row in db.getAllRows(postsQuery):
list.add(selectPost(row, @[], selectReplyingTo(row[4])))
let history = selectHistory(row[0].parseInt())
list.add(selectPost(row, @[], selectReplyingTo(row[4]), history))
resp $(%list), "application/json"
@ -1271,10 +1295,15 @@ routes:
cond postId != -1
let postQuery = sql"""
select content from post where id = ?;
select content from (
select content, creation from post where id = ?
union
select content, creation from postRevision where original = ?
)
order by creation desc limit 1;
"""
let content = getValue(db, postQuery, postId)
let content = getValue(db, postQuery, postId, postId)
if content.len == 0:
resp Http404, "Post not found"
else:

View file

@ -58,6 +58,9 @@ when defined(js):
(s: int, r: kstring) => onEditPost(s, r, state))
proc render*(state: EditBox, post: Post): VNode =
if state.status != Http200:
return renderError("Couldn't retrieve raw post")
if state.rawContent.isNone() or state.post.id != post.id:
state.post = post
state.rawContent = none[kstring]()

View file

@ -317,6 +317,19 @@ $views-color: #545d70;
transform: rotate(180deg);
}
}
.post-history {
display: inline-block;
margin-right: $control-padding-x;
i {
font-size: 90%;
}
.edit-count {
margin-right: $control-padding-x-sm/2;
}
}
}
}

View file

@ -28,6 +28,9 @@ type
postId*: int
author*: Option[User] ## Only used for `replyingTo`.
proc lastEdit*(post: Post): PostInfo =
post.history[^1]
proc isModerated*(post: Post): bool =
## Determines whether the specified thread is under moderation.
post.author.rank <= Moderated

View file

@ -119,7 +119,10 @@ when defined(js):
let list = state.list.get()
for i in 0 ..< list.posts.len:
if list.posts[i].id == id:
list.posts[i].info.content = content
list.posts[i].history.add(PostInfo(
creation: getTime().toUnix(),
content: content
))
break
proc onReplyClick(e: Event, n: VNode, p: Option[Post]) =
@ -219,6 +222,14 @@ when defined(js):
a(href=renderPostUrl(replyingTo)):
italic(class="fas fa-reply")
renderUserMention(replyingTo.author.get())
if post.history.len > 0:
let title = post.lastEdit.creation.fromUnix().local.
format("'Last modified' MMM d, yyyy HH:mm")
tdiv(class="post-history", title=title):
span(class="edit-count"):
text $post.history.len
italic(class="fas fa-pencil-alt")
let title = post.info.creation.fromUnix().local.
format("MMM d, yyyy HH:mm")
a(href=renderPostUrl(post, thread), title=title):
@ -227,7 +238,12 @@ when defined(js):
if state.editing.isSome() and state.editing.get() == post:
render(state.editBox, postCopy)
else:
verbatim(post.info.content)
let content =
if post.history.len > 0:
post.lastEdit.content
else:
post.info.content
verbatim(content)
genPostButtons(postCopy, currentUser)