Commit 6ed5011e by Rocky Duan

use observers

parent 38e5086f
......@@ -22,6 +22,10 @@ Mongoid.logger.level = Logger::INFO
Dir[File.dirname(__FILE__) + '/lib/**/*.rb'].each {|file| require file}
Dir[File.dirname(__FILE__) + '/models/*.rb'].each {|file| require file}
Dir[File.dirname(__FILE__) + '/models/observers/*.rb'].each {|file| require file}
Mongoid.observers = PostReplyObserver, PostTopicObserver, AtUserObserver
Mongoid.instantiate_observers
api_prefix = CommentService::API_PREFIX
......@@ -227,7 +231,6 @@ end
put "#{api_prefix}/users/:user_id" do |user_id|
user.update_attributes(params.slice(*%w[username email]))
user.save
if user.errors.any?
error 400, user.errors.full_messages.to_json
else
......
......@@ -12,6 +12,7 @@ class Comment < Content
field :course_id, type: String
field :endorsed, type: Boolean, default: false
field :anonymous, type: Boolean, default: false
field :at_position_list, type: Array, default: []
belongs_to :author, class_name: "User", index: true
belongs_to :comment_thread, index: true
......@@ -26,7 +27,6 @@ class Comment < Content
counter_cache :comment_thread
before_destroy :delete_descendants # TODO async
after_create :generate_notifications
def self.hash_tree(nodes)
nodes.map{|node, sub_nodes| node.to_hash.merge("children" => hash_tree(sub_nodes).compact)}
......@@ -53,30 +53,4 @@ class Comment < Content
end
end
private
def generate_notifications
if comment_thread.subscribers or (author.followers if not anonymous)
notification = Notification.new(
notification_type: "post_reply",
info: {
thread_id: comment_thread.id,
thread_title: comment_thread.title,
comment_id: id,
commentable_id: comment_thread.commentable_id,
},
)
notification.actor = author if not anonymous
notification.target = self
receivers = comment_thread.subscribers
if not anonymous
receivers = (receivers + author.followers).uniq_by(&:id)
end
receivers.delete(author)
notification.receivers << receivers
notification.save!
end
end
handle_asynchronously :generate_notifications
end
......@@ -13,6 +13,7 @@ class CommentThread < Content
field :course_id, type: String
field :commentable_id, type: String
field :anonymous, type: Boolean, default: false
field :at_position_list, type: Array, default: []
include Sunspot::Mongoid
searchable do
......@@ -47,8 +48,6 @@ class CommentThread < Content
validate :tag_names_valid
validate :tag_names_unique
after_create :generate_notifications
def self.new_dumb_thread(options={})
c = self.new
c.title = options[:title] || "title"
......@@ -106,28 +105,6 @@ class CommentThread < Content
end
private
def generate_notifications
if subscribers or (author.followers if not anonymous)
notification = Notification.new(
notification_type: "post_topic",
info: {
commentable_id: commentable_id,
#commentable_type: commentable.commentable_type,
thread_id: id,
thread_title: title,
},
)
notification.actor = author if not anonymous
notification.target = self
receivers = commentable.subscribers
if not anonymous
receivers = (receivers + author.followers).uniq_by(&:id)
end
receivers.delete(author)
notification.receivers << receivers
notification.save!
end
end
RE_HEADCHAR = /[a-z0-9]/
RE_ENDONLYCHAR = /\+/
......@@ -149,6 +126,4 @@ private
errors.add :tags, "must be unique"
end
end
handle_asynchronously :generate_notifications
end
class Content
include Mongoid::Document
AT_NOTIFICATION_REGEX = /(?<=^|\s)(@[A-Za-z0-9_]+)(?!\w)/
private
def self.get_marked_text(text)
counter = -1
text.gsub AT_NOTIFICATION_REGEX do
counter += 1
"#{$1}_#{counter}"
end
end
def self.get_at_position_list(text)
list = []
text.gsub AT_NOTIFICATION_REGEX do
parts = $1.rpartition('_')
username = parts.first[1..-1]
user = User.where(username: username).first
if user
list << [parts.last.to_i, parts.first[1..-1], user.id]
end
end
list
end
def self.get_valid_at_position_list(text)
html = Nokogiri::HTML(RDiscount.new(self.get_marked_text(text)).to_html)
html.xpath('//code').each do |c|
c.children = ''
end
self.get_at_position_list html.to_s
end
end
require 'set'
class AtUserObserver < Mongoid::Observer
observe :comment, :comment_thread
def after_create(content)
self.class.delay.process_at_notifications(content)
end
def self.process_at_notifications(content)
text = content.body
content_type = content.respond_to?(:title) ? :thread : :comment
text = content.title + "\n\n" + text if content_type == :thread
at_positions = self.get_valid_at_position_list text
prev_at_positions = content.at_position_list
content.update_attributes!(at_position_list: at_positions)
prev_user_ids = prev_at_positions.map { |x| x[:user_id] }.to_set
current_user_ids = at_positions.map { |x| x[:user_id] }.to_set
new_user_ids = current_user_ids - prev_user_ids
unless new_user_ids.empty?
notification = Notification.new(
notification_type: "at_user",
info: {
content_id: content.id,
content_type: content_type,
thread_title: content_type == :thread ? content.title : content.comment_thread.title,
}
)
notification.actor = content.author if not content.anonymous
notification.target = content
receivers = new_user_ids.map { |id| User.find(id) }
receivers.delete(content.author)
notification.receiverss << receivers
notification.save!
end
end
private
AT_NOTIFICATION_REGEX = /(?<=^|\s)(@[A-Za-z0-9_]+)(?!\w)/
def self.get_marked_text(text)
counter = -1
text.gsub AT_NOTIFICATION_REGEX do
counter += 1
"#{$1}_#{counter}"
end
end
def self.get_at_position_list(text)
list = []
text.gsub AT_NOTIFICATION_REGEX do
parts = $1.rpartition('_')
username = parts.first[1..-1]
user = User.where(username: username).first
if user
list << { position: parts.last.to_i, username: parts.first[1..-1], user_id: user.id }#parts.last.to_i, parts.first[1..-1], user.id]
end
end
list
end
def self.get_valid_at_position_list(text)
html = Nokogiri::HTML(RDiscount.new(self.get_marked_text(text)).to_html)
html.xpath('//code').each do |c|
c.children = ''
end
self.get_at_position_list html.to_s
end
end
class PostReplyObserver < Mongoid::Observer
observe :comment
def after_create(comment)
self.class.delay.generate_notifications(comment)
end
def self.generate_notifications(comment)
if comment.comment_thread.subscribers or (comment.author.followers if not comment.anonymous)
notification = Notification.new(
notification_type: "post_reply",
info: {
thread_id: comment.comment_thread.id,
thread_title: comment.comment_thread.title,
comment_id: comment.id,
commentable_id: comment.comment_thread.commentable_id,
},
)
notification.actor = comment.author if not comment.anonymous
notification.target = comment
receivers = comment.comment_thread.subscribers
if not comment.anonymous
receivers = (receivers + comment.author.followers).uniq_by(&:id)
end
receivers.delete(comment.author)
notification.receivers << receivers
notification.save!
end
end
end
class PostTopicObserver < Mongoid::Observer
observe :comment_thread
def after_create(comment_thread)
self.class.delay.generate_notifications(comment_thread)
end
def self.generate_notifications(comment_thread)
if comment_thread.commentable.subscribers or (author.followers if not anonymous)
notification = Notification.new(
notification_type: "post_topic",
info: {
commentable_id: comment_thread.commentable_id,
#commentable_type: commentable.commentable_type,
thread_id: comment_thread.id,
thread_title: comment_thread.title,
},
)
notification.actor = comment_thread.author if not comment_thread.anonymous
notification.target = comment_thread
receivers = comment_thread.commentable.subscribers
if not comment_thread.anonymous
receivers = (receivers + comment_thread.author.followers).uniq_by(&:id)
end
receivers.delete(comment_thread.author)
notification.receivers << receivers
notification.save!
end
end
end
......@@ -39,8 +39,8 @@ what is the 'at' symbol doing there? @dementrock
describe "#get_valid_at_position_list(text)" do
it "returns the list of positions for the valid @ notifications, filtering out the ones in code blocks" do
list = Content.get_valid_at_position_list(@text)
list.should include [0, "tom", "1"]
list.should include [1, "pi314", "2"]
list.should include({ position: 0, username: "tom", user_id: "1" })
list.should include({ position: 1, username: "pi314", user_id: "2" })
list.length.should == 2
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