Commit d6b7d903 by wajeeha-khalid

jia/MA-1815 retrieve count for child comments

parent 156456ec
...@@ -78,6 +78,7 @@ post "#{APIPREFIX}/threads/:thread_id/comments" do |thread_id| ...@@ -78,6 +78,7 @@ post "#{APIPREFIX}/threads/:thread_id/comments" do |thread_id|
comment.anonymous_to_peers = bool_anonymous_to_peers || false comment.anonymous_to_peers = bool_anonymous_to_peers || false
comment.author = user comment.author = user
comment.comment_thread = thread comment.comment_thread = thread
comment.child_count = 0
comment.save comment.save
if comment.errors.any? if comment.errors.any?
error 400, comment.errors.full_messages.to_json error 400, comment.errors.full_messages.to_json
......
get "#{APIPREFIX}/comments/:comment_id" do |comment_id| get "#{APIPREFIX}/comments/:comment_id" do |comment_id|
comment.to_hash(recursive: bool_recursive).to_json @comment = comment
comment_hash = @comment.to_hash(recursive: bool_recursive)
verify_or_fix_cached_comment_count(@comment, comment_hash)
comment_hash.to_json
end end
put "#{APIPREFIX}/comments/:comment_id" do |comment_id| put "#{APIPREFIX}/comments/:comment_id" do |comment_id|
...@@ -31,16 +34,31 @@ post "#{APIPREFIX}/comments/:comment_id" do |comment_id| ...@@ -31,16 +34,31 @@ post "#{APIPREFIX}/comments/:comment_id" do |comment_id|
sub_comment.anonymous_to_peers = bool_anonymous_to_peers || false sub_comment.anonymous_to_peers = bool_anonymous_to_peers || false
sub_comment.author = user sub_comment.author = user
sub_comment.comment_thread = comment.comment_thread sub_comment.comment_thread = comment.comment_thread
sub_comment.child_count = 0
sub_comment.save sub_comment.save
if sub_comment.errors.any? if sub_comment.errors.any?
error 400, sub_comment.errors.full_messages.to_json error 400, sub_comment.errors.full_messages.to_json
else else
user.subscribe(comment.comment_thread) if bool_auto_subscribe comment.update_cached_child_count
sub_comment.to_hash.to_json if comment.errors.any?
error 400, comment.errors.full_messages.to_json
else
user.subscribe(comment.comment_thread) if bool_auto_subscribe
sub_comment.to_hash.to_json
end
end end
end end
delete "#{APIPREFIX}/comments/:comment_id" do |comment_id| delete "#{APIPREFIX}/comments/:comment_id" do |comment_id|
parent_id = comment.parent_id
comment.destroy comment.destroy
unless parent_id.nil?
begin
parent_comment = Comment.find(parent_id)
parent_comment.update_cached_child_count
rescue Mongoid::Errors::DocumentNotFound
pass
end
end
comment.to_hash.to_json comment.to_hash.to_json
end end
...@@ -19,6 +19,16 @@ helpers do ...@@ -19,6 +19,16 @@ helpers do
@comment ||= Comment.find(params[:comment_id]) @comment ||= Comment.find(params[:comment_id])
end end
def verify_or_fix_cached_comment_count(comment, comment_hash)
# if child count cached value gets stale; re-calculate and update it
unless comment_hash["children"].nil?
if comment_hash["child_count"] != comment_hash["children"].length
comment.update_cached_child_count
comment_hash["child_count"] = comment.get_cached_child_count
end
end
end
def source def source
@source ||= case params["source_type"] @source ||= case params["source_type"]
when "user" when "user"
......
...@@ -20,6 +20,7 @@ class Comment < Content ...@@ -20,6 +20,7 @@ class Comment < Content
field :commentable_id, type: String field :commentable_id, type: String
field :at_position_list, type: Array, default: [] field :at_position_list, type: Array, default: []
field :sk, type: String, default: nil field :sk, type: String, default: nil
field :child_count, type: Integer
index({author_id: 1, course_id: 1}) index({author_id: 1, course_id: 1})
index({_type: 1, comment_thread_id: 1, author_id: 1, updated_at: 1}) index({_type: 1, comment_thread_id: 1, author_id: 1, updated_at: 1})
...@@ -91,20 +92,31 @@ class Comment < Content ...@@ -91,20 +92,31 @@ class Comment < Content
self.class.hash_tree(subtree_hash).first self.class.hash_tree(subtree_hash).first
else else
as_document.slice(*%w[body course_id endorsed endorsement anonymous anonymous_to_peers created_at updated_at at_position_list]) as_document.slice(*%w[body course_id endorsed endorsement anonymous anonymous_to_peers created_at updated_at at_position_list])
.merge('id' => _id) .merge("id" => _id)
.merge('user_id' => author_id) .merge("user_id" => author_id)
.merge('username' => author_username) .merge("username" => author_username)
.merge('depth' => depth) .merge("depth" => depth)
.merge('closed' => comment_thread.nil? ? false : comment_thread.closed) .merge("closed" => comment_thread.nil? ? false : comment_thread.closed)
.merge('thread_id' => comment_thread_id) .merge("thread_id" => comment_thread_id)
.merge('parent_id' => parent_ids[-1]) .merge("parent_id" => parent_ids[-1])
.merge('commentable_id' => comment_thread.nil? ? nil : comment_thread.commentable_id) .merge("commentable_id" => comment_thread.nil? ? nil : comment_thread.commentable_id)
.merge('votes' => votes.slice(*%w[count up_count down_count point])) .merge("votes" => votes.slice(*%w[count up_count down_count point]))
.merge('abuse_flaggers' => abuse_flaggers) .merge("abuse_flaggers" => abuse_flaggers)
.merge('type' => 'comment') .merge("type" => "comment")
.merge("child_count" => get_cached_child_count)
end end
end end
def get_cached_child_count
update_cached_child_count if self.child_count.nil?
self.child_count
end
def update_cached_child_count
child_comments_count = Comment.where({"parent_id" => self._id}).count()
self.set(child_count: child_comments_count)
end
def commentable_id def commentable_id
#we need this to have a universal access point for the flag rake task #we need this to have a universal access point for the flag rake task
if self.comment_thread_id if self.comment_thread_id
......
...@@ -15,7 +15,7 @@ describe 'Comment API' do ...@@ -15,7 +15,7 @@ describe 'Comment API' do
last_response.content_type.should == 'application/json;charset=utf-8' last_response.content_type.should == 'application/json;charset=utf-8'
end end
it 'retrieve information of a single comment' do it 'retrieves information of a single comment' do
comment = thread.comments.first comment = thread.comments.first
get "/api/v1/comments/#{comment.id}" get "/api/v1/comments/#{comment.id}"
last_response.should be_ok last_response.should be_ok
...@@ -27,9 +27,10 @@ describe 'Comment API' do ...@@ -27,9 +27,10 @@ describe 'Comment API' do
retrieved['votes']['point'].should == comment.votes_point retrieved['votes']['point'].should == comment.votes_point
retrieved['depth'].should == comment.depth retrieved['depth'].should == comment.depth
retrieved['parent_id'].should == comment.parent_ids.map(&:to_s)[-1] retrieved['parent_id'].should == comment.parent_ids.map(&:to_s)[-1]
retrieved["child_count"].should == comment.children.length
end end
it 'retrieve information of a single comment with its sub comments' do it 'retrieves information of a single comment with its sub comments' do
comment = thread.comments.first comment = thread.comments.first
get "/api/v1/comments/#{comment.id}", recursive: true get "/api/v1/comments/#{comment.id}", recursive: true
last_response.should be_ok last_response.should be_ok
...@@ -41,12 +42,30 @@ describe 'Comment API' do ...@@ -41,12 +42,30 @@ describe 'Comment API' do
retrieved_children = retrieved['children'] retrieved_children = retrieved['children']
retrieved_children.length.should == comment.children.length retrieved_children.length.should == comment.children.length
retrieved["child_count"].should == comment.children.length
comment.children.each_with_index do |child, index| comment.children.each_with_index do |child, index|
expect(retrieved_children[index]).to include('body' => child.body, 'parent_id' => comment.id.to_s) expect(retrieved_children[index]).to include('body' => child.body, 'parent_id' => comment.id.to_s)
end end
end end
it 'retrieves information of a single comment and fixes incorrect child count' do
comment = thread.comments.first
comment.set(child_count: 2000)
comment_hash = comment.to_hash(recursive: true)
comment_hash["child_count"].should == 2000
get "/api/v1/comments/#{comment.id}", recursive: true
last_response.should be_ok
retrieved = parse last_response.body
retrieved["child_count"].should == comment.children.length
comment.set(child_count: nil)
get "/api/v1/comments/#{comment.id}"
last_response.should be_ok
retrieved = parse last_response.body
retrieved["child_count"].should == comment.children.length
end
it 'returns 400 when the comment does not exist' do it 'returns 400 when the comment does not exist' do
get '/api/v1/comments/does_not_exist' get '/api/v1/comments/does_not_exist'
last_response.status.should == 400 last_response.status.should == 400
...@@ -147,10 +166,12 @@ describe 'Comment API' do ...@@ -147,10 +166,12 @@ describe 'Comment API' do
comment.reload comment.reload
comment.children.length.should == previous_child_count + 1 comment.children.length.should == previous_child_count + 1
comment.child_count.should == previous_child_count + 1
sub_comment = comment.children.order_by(created_at: :desc).first sub_comment = comment.children.order_by(created_at: :desc).first
sub_comment.body.should == body sub_comment.body.should == body
sub_comment.course_id.should == course_id sub_comment.course_id.should == course_id
sub_comment.author.should == user sub_comment.author.should == user
sub_comment.child_count.should == 0
end end
it 'returns 400 when the comment does not exist' do it 'returns 400 when the comment does not exist' do
...@@ -180,7 +201,7 @@ describe 'Comment API' do ...@@ -180,7 +201,7 @@ describe 'Comment API' do
end end
describe 'DELETE /api/v1/comments/:comment_id' do describe 'DELETE /api/v1/comments/:comment_id' do
it 'delete the comment and its sub comments' do it 'deletes the comment and its sub comments' do
comment = thread.comments.first comment = thread.comments.first
cnt_comments = comment.descendants_and_self.length cnt_comments = comment.descendants_and_self.length
prev_count = Comment.count prev_count = Comment.count
......
...@@ -703,11 +703,13 @@ describe "app" do ...@@ -703,11 +703,13 @@ describe "app" do
orig_count = thread.comment_count orig_count = thread.comment_count
post "/api/v1/threads/#{thread.id}/comments", default_params post "/api/v1/threads/#{thread.id}/comments", default_params
last_response.should be_ok last_response.should be_ok
retrieved = parse last_response.body
changed_thread = CommentThread.find(thread.id) changed_thread = CommentThread.find(thread.id)
changed_thread.comment_count.should == orig_count + 1 changed_thread.comment_count.should == orig_count + 1
comment = changed_thread.comments.select { |c| c["body"] == "new comment" }.first comment = changed_thread.comments.select { |c| c["body"] == "new comment" }.first
comment.should_not be_nil comment.should_not be_nil
comment.author_id.should == user.id comment.author_id.should == user.id
retrieved["child_count"].should == 0
end end
it "allows anonymous comment" do it "allows anonymous comment" do
thread = CommentThread.first thread = CommentThread.first
......
...@@ -69,4 +69,32 @@ describe Comment do ...@@ -69,4 +69,32 @@ describe Comment do
end end
end end
end end
describe '#child_count' do
context 'with course_thread' do
it 'returns cached child count' do
comment = make_comment(author, course_thread, "comment")
child_comment = make_comment(author, comment, "comment")
expect(comment.get_cached_child_count).to eq(1)
end
it 'returns cached child count' do
comment = make_comment(author, course_thread, "comment")
child_comment = make_comment(author, comment, "comment")
comment.child_count = nil
expect(comment.get_cached_child_count).to eq(1)
end
it 'updates cached child count' do
comment = make_comment(author, course_thread, "comment")
expect(comment.get_cached_child_count).to eq(0)
comment.child_count = 2
expect(comment.get_cached_child_count).to eq(2)
comment.update_cached_child_count
expect(comment.get_cached_child_count).to eq(0)
end
end
end
end end
...@@ -251,8 +251,9 @@ def check_comment(comment, hash, is_json, recursive=false) ...@@ -251,8 +251,9 @@ def check_comment(comment, hash, is_json, recursive=false)
hash["username"].should == comment.author_username hash["username"].should == comment.author_username
hash["endorsed"].should == comment.endorsed hash["endorsed"].should == comment.endorsed
hash["endorsement"].should == comment.endorsement hash["endorsement"].should == comment.endorsement
children = Comment.where({"parent_id" => comment.id}).sort({"sk" => 1}).to_a
hash["child_count"].should == children.length
if recursive if recursive
children = Comment.where({"parent_id" => comment.id}).sort({"sk" => 1}).to_a
hash["children"].length.should == children.length hash["children"].length.should == children.length
hash["children"].each_with_index do |child_hash, i| hash["children"].each_with_index do |child_hash, i|
check_comment(children[i], child_hash, is_json) check_comment(children[i], child_hash, is_json)
...@@ -330,6 +331,7 @@ def make_comment(author, parent, text) ...@@ -330,6 +331,7 @@ def make_comment(author, parent, text)
else else
coll = parent.children coll = parent.children
thread = parent.comment_thread thread = parent.comment_thread
parent.set(child_count: coll.length + 1)
end end
comment = coll.new(body: text, course_id: parent.course_id) comment = coll.new(body: text, course_id: parent.course_id)
comment.author = author comment.author = author
...@@ -390,6 +392,7 @@ def create_comment_thread_and_comments ...@@ -390,6 +392,7 @@ def create_comment_thread_and_comments
# Create a comment along with a nested child comment # Create a comment along with a nested child comment
comment = create(:comment, comment_thread: thread) comment = create(:comment, comment_thread: thread)
create(:comment, parent: comment) create(:comment, parent: comment)
comment.set(child_count: 1)
thread thread
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment