Commit 23cb2de3 by Rocky Duan

store anonymity as a separate attribute and make author required again

parent f5d3af22
...@@ -39,14 +39,14 @@ get '/api/v1/:commentable_id/threads' do |commentable_id| ...@@ -39,14 +39,14 @@ get '/api/v1/:commentable_id/threads' do |commentable_id|
end end
post '/api/v1/:commentable_id/threads' do |commentable_id| post '/api/v1/:commentable_id/threads' do |commentable_id|
thread = CommentThread.new(params.slice(*%w[title body course_id]).merge(commentable_id: commentable_id)) thread = CommentThread.new(params.slice(*%w[title body course_id anonymous]).merge(commentable_id: commentable_id))
thread.tags = params["tags"] || "" thread.tags = params["tags"] || ""
thread.author = user thread.author = user
thread.save thread.save
if thread.errors.any? if thread.errors.any?
error 400, thread.errors.full_messages.to_json error 400, thread.errors.full_messages.to_json
else else
user.subscribe(thread) if params["auto_subscribe"] and user user.subscribe(thread) if params["auto_subscribe"]
thread.to_hash.to_json thread.to_hash.to_json
end end
end end
...@@ -77,13 +77,13 @@ put '/api/v1/threads/:thread_id' do |thread_id| ...@@ -77,13 +77,13 @@ put '/api/v1/threads/:thread_id' do |thread_id|
end end
post '/api/v1/threads/:thread_id/comments' do |thread_id| post '/api/v1/threads/:thread_id/comments' do |thread_id|
comment = thread.comments.new(params.slice(*%w[body course_id])) comment = thread.comments.new(params.slice(*%w[body course_id anonymous]))
comment.author = user comment.author = user
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
else else
user.subscribe(thread) if params["auto_subscribe"] and user user.subscribe(thread) if params["auto_subscribe"]
comment.to_hash.to_json comment.to_hash.to_json
end end
end end
......
...@@ -10,15 +10,17 @@ class Comment < Content ...@@ -10,15 +10,17 @@ class Comment < Content
field :body, type: String field :body, type: String
field :course_id, type: String field :course_id, type: String
field :endorsed, type: Boolean, default: false field :endorsed, type: Boolean, default: false
field :anonymous, type: Boolean, default: false
belongs_to :author, class_name: "User", index: true belongs_to :author, class_name: "User", index: true
belongs_to :comment_thread, index: true belongs_to :comment_thread, index: true
attr_accessible :body, :course_id, :endorsed attr_accessible :body, :course_id, :endorsed, :anonymous
validates_presence_of :body validates_presence_of :body
validates_presence_of :course_id # do we really need this? validates_presence_of :course_id # do we really need this?
validates_presence_of :comment_thread validates_presence_of :comment_thread
validates_presence_of :author
before_destroy :delete_descendants # TODO async before_destroy :delete_descendants # TODO async
after_create :generate_notifications after_create :generate_notifications
...@@ -39,9 +41,9 @@ class Comment < Content ...@@ -39,9 +41,9 @@ class Comment < Content
if params[:recursive] if params[:recursive]
self.class.hash_tree(subtree(sort: sort_by_parent_and_time)).first self.class.hash_tree(subtree(sort: sort_by_parent_and_time)).first
else else
as_document.slice(*%w[body course_id endorsed created_at updated_at]) as_document.slice(*%w[body course_id endorsed anonymous created_at updated_at])
.merge("id" => _id) .merge("id" => _id)
.merge("user_id" => (author.id if author)) .merge("user_id" => author.id)
.merge("depth" => depth) .merge("depth" => depth)
.merge("thread_id" => comment_thread.id) .merge("thread_id" => comment_thread.id)
.merge("votes" => votes.slice(*%w[count up_count down_count point])) .merge("votes" => votes.slice(*%w[count up_count down_count point]))
...@@ -50,7 +52,7 @@ class Comment < Content ...@@ -50,7 +52,7 @@ class Comment < Content
private private
def generate_notifications def generate_notifications
if comment_thread.subscribers or (author.followers if author) if comment_thread.subscribers or (author.followers if not anonymous)
notification = Notification.new( notification = Notification.new(
notification_type: "post_reply", notification_type: "post_reply",
info: { info: {
...@@ -60,10 +62,10 @@ private ...@@ -60,10 +62,10 @@ private
commentable_id: comment_thread.commentable_id, commentable_id: comment_thread.commentable_id,
}, },
) )
notification.actor = author notification.actor = author if not anonymous
notification.target = self notification.target = self
receivers = comment_thread.subscribers receivers = comment_thread.subscribers
if author if not anonymous
receivers = (receivers + author.followers).uniq_by(&:id) receivers = (receivers + author.followers).uniq_by(&:id)
end end
receivers.delete(author) receivers.delete(author)
......
...@@ -11,6 +11,7 @@ class CommentThread < Content ...@@ -11,6 +11,7 @@ class CommentThread < Content
field :body, type: String field :body, type: String
field :course_id, type: String, index: true field :course_id, type: String, index: true
field :commentable_id, type: String, index: true field :commentable_id, type: String, index: true
field :anonymous, type: Boolean, default: false
include Sunspot::Mongoid include Sunspot::Mongoid
searchable do searchable do
...@@ -28,12 +29,13 @@ class CommentThread < Content ...@@ -28,12 +29,13 @@ class CommentThread < Content
belongs_to :author, class_name: "User", inverse_of: :comment_threads, index: true, autosave: true belongs_to :author, class_name: "User", inverse_of: :comment_threads, index: true, autosave: true
has_many :comments, dependent: :destroy, autosave: true# Use destroy to envoke callback on the top-level comments TODO async has_many :comments, dependent: :destroy, autosave: true# Use destroy to envoke callback on the top-level comments TODO async
attr_accessible :title, :body, :course_id, :commentable_id attr_accessible :title, :body, :course_id, :commentable_id, :anonymous
validates_presence_of :title validates_presence_of :title
validates_presence_of :body validates_presence_of :body
validates_presence_of :course_id # do we really need this? validates_presence_of :course_id # do we really need this?
validates_presence_of :commentable_id validates_presence_of :commentable_id
validates_presence_of :author
validate :tag_names_valid validate :tag_names_valid
validate :tag_names_unique validate :tag_names_unique
...@@ -69,9 +71,9 @@ class CommentThread < Content ...@@ -69,9 +71,9 @@ class CommentThread < Content
end end
def to_hash(params={}) def to_hash(params={})
doc = as_document.slice(*%w[title body course_id commentable_id created_at updated_at]) doc = as_document.slice(*%w[title body course_id anonymous commentable_id created_at updated_at])
.merge("id" => _id) .merge("id" => _id)
.merge("user_id" => (author.id if author)) .merge("user_id" => author.id)
.merge("votes" => votes.slice(*%w[count up_count down_count point])) .merge("votes" => votes.slice(*%w[count up_count down_count point]))
.merge("tags" => tags_array) .merge("tags" => tags_array)
...@@ -96,7 +98,7 @@ class CommentThread < Content ...@@ -96,7 +98,7 @@ class CommentThread < Content
private private
def generate_notifications def generate_notifications
if subscribers or (author.followers if author) if subscribers or (author.followers if not anonymous)
notification = Notification.new( notification = Notification.new(
notification_type: "post_topic", notification_type: "post_topic",
info: { info: {
...@@ -106,10 +108,10 @@ private ...@@ -106,10 +108,10 @@ private
thread_title: title, thread_title: title,
}, },
) )
notification.actor = author notification.actor = author if not anonymous
notification.target = self notification.target = self
receivers = commentable.subscribers receivers = commentable.subscribers
if author if not anonymous
receivers = (receivers + author.followers).uniq_by(&:id) receivers = (receivers + author.followers).uniq_by(&:id)
end end
receivers.delete(author) receivers.delete(author)
......
...@@ -99,12 +99,13 @@ describe "app" do ...@@ -99,12 +99,13 @@ describe "app" do
end end
it "allows anonymous comment" do it "allows anonymous comment" do
thread = CommentThread.first.to_hash(recursive: true) thread = CommentThread.first.to_hash(recursive: true)
post "/api/v1/threads/#{thread["id"]}/comments", default_params.merge(user_id: nil) post "/api/v1/threads/#{thread["id"]}/comments", default_params.merge(anonymous: true)
last_response.should be_ok last_response.should be_ok
changed_thread = CommentThread.find(thread["id"]).to_hash(recursive: true) changed_thread = CommentThread.find(thread["id"]).to_hash(recursive: true)
changed_thread["children"].length.should == thread["children"].length + 1 changed_thread["children"].length.should == thread["children"].length + 1
comment = changed_thread["children"].select{|c| c["body"] == "new comment"}.first comment = changed_thread["children"].select{|c| c["body"] == "new comment"}.first
comment.should_not be_nil comment.should_not be_nil
comment["anonymous"].should be_true
end end
it "returns 400 when the thread does not exist" do it "returns 400 when the thread does not exist" do
post "/api/v1/threads/does_not_exist/comments", default_params post "/api/v1/threads/does_not_exist/comments", default_params
......
...@@ -58,12 +58,12 @@ describe "app" do ...@@ -58,12 +58,12 @@ describe "app" do
CommentThread.where(title: "Interesting question").first.should_not be_nil CommentThread.where(title: "Interesting question").first.should_not be_nil
end end
it "allows anonymous thread" do it "allows anonymous thread" do
params = default_params.dup post '/api/v1/question_1/threads', default_params.merge(anonymous: true)
params.delete(:user_id)
post '/api/v1/question_1/threads', params
last_response.should be_ok last_response.should be_ok
CommentThread.count.should == 3 CommentThread.count.should == 3
CommentThread.where(title: "Interesting question").first.should_not be_nil c = CommentThread.where(title: "Interesting question").first
c.should_not be_nil
c["anonymous"].should be_true
end end
it "create a new comment thread for a new commentable object" do it "create a new comment thread for a new commentable object" do
post '/api/v1/does_not_exist/threads', default_params post '/api/v1/does_not_exist/threads', default_params
......
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