Commit 0ce290be by Rocky Duan

single subscription model working

parent f60b0f0f
......@@ -28,6 +28,7 @@ namespace :test do
Commentable.delete_all
User.delete_all
Notification.delete_all
Subscription.delete_all
commentable = Commentable.create!(commentable_type: "questions", commentable_id: "1")
......@@ -68,6 +69,7 @@ namespace :db do
User.create_indexes
Commentable.create_indexes
Notification.create_indexes
Subscription.create_indexes
Delayed::Backend::Mongoid::Job.create_indexes
puts "finished"
end
......@@ -78,6 +80,8 @@ namespace :db do
Comment.delete_all
CommentThread.delete_all
User.delete_all
Notification.delete_all
Subscription.delete_all
beginning_time = Time.now
......@@ -86,7 +90,7 @@ namespace :db do
users = (1..10).map {|id| User.find_or_create_by(external_id: id.to_s)}
10.times do
users.sample.follow(users.sample)
users.sample.subscribe(users.sample)
end
def generate_comments(commentable_type, commentable_id, level_limit, users)
......
......@@ -115,28 +115,28 @@ end
post '/api/v1/users/:user_id/subscriptions' do |user_id|
user = User.find_or_create_by(external_id: user_id)
case params["subscribed_type"]
source = case params["subscribed_type"]
when "user"
user.follow(User.find_or_create_by(external_id: params["subscribed_id"]))
User.find_or_create_by(external_id: params["subscribed_id"])
when "thread"
user.subscribe_comment_thread(CommentThread.find(params["subscribed_id"]))
CommentThread.find(params["subscribed_id"])
else
user.subscribe_commentable(Commentable.find_or_create_by(commentable_type: params["subscribed_type"], commentable_id: params["subscribed_id"]))
Commentable.find_or_create_by(commentable_type: params["subscribed_type"], commentable_id: params["subscribed_id"])
end
user.reload.to_hash.to_json
user.subscribe(source).to_hash.to_json
end
delete '/api/v1/users/:user_id/subscriptions' do |user_id|
user = User.find_or_create_by(external_id: user_id)
case params["subscribed_type"]
source = case params["subscribed_type"]
when "user"
user.unfollow(User.find_or_create_by(external_id: params["subscribed_id"]))
User.find_or_create_by(external_id: params["subscribed_id"])
when "thread"
user.unsubscribe_comment_thread(CommentThread.find(params["subscribed_id"]))
CommentThread.find(params["subscribed_id"])
else
user.unsubscribe_commentable(Commentable.find_or_create_by(commentable_type: params["subscribed_type"], commentable_id: params["subscribed_id"]))
Commentable.find_or_create_by(commentable_type: params["subscribed_type"], commentable_id: params["subscribed_id"])
end
user.reload.to_hash.to_json
user.unsubscribe(source).to_hash.to_json
end
if env.to_s == "development"
......@@ -146,6 +146,7 @@ if env.to_s == "development"
Commentable.delete_all
User.delete_all
Notification.delete_all
Subscription.delete_all
{}.to_json
end
end
......
......@@ -73,7 +73,7 @@ private
def auto_subscribe_comment_thread
if CommentService.config["auto_subscribe_comment_threads"] and author
author.subscribe_comment_thread(get_comment_thread)
author.subscribe(get_comment_thread)
end
end
......
......@@ -12,7 +12,8 @@ class CommentThread
belongs_to :author, class_name: "User", inverse_of: :comment_threads, index: true, autosave: true
belongs_to :commentable, index: true, autosave: true
has_many :comments, dependent: :destroy, autosave: true# Use destroy to envoke callback on the top-level comments TODO async
has_and_belongs_to_many :subscribers, class_name: "User", inverse_of: :subscribed_comment_threads, autosave: true
#has_many :subscriptions, as: :source
#has_and_belongs_to_many :subscribers, class_name: "User", inverse_of: :subscribed_comment_threads, autosave: true
attr_accessible :title, :body, :course_id
......@@ -22,7 +23,15 @@ class CommentThread
validates_presence_of :author if not CommentService.config["allow_anonymity"]
after_create :handle_after_create
def subscriptions
Subscription.where(source_id: self.id, source_type: self.class)
end
def subscribers
subscriptions.map{|s| User.find(s.subscriber_id)}
end
def to_hash(params={})
doc = as_document.slice(*%w[title body course_id _id]).
merge("user_id" => (author.id if author)).
......@@ -47,7 +56,7 @@ private
)
notification.actor = author
notification.target = self
notification.receivers << (commentable.subscribers + (author.followers if author).to_a).uniq_by(&:id)
notification.receivers << (commentable.subscribers + author.followers).uniq_by(&:id)
notification.receivers.delete(author) if not CommentService.config["send_notifications_to_author"] and author
notification.save!
end
......@@ -55,7 +64,7 @@ private
def auto_subscribe_comment_thread
if CommentService.config["auto_subscribe_comment_threads"] and author
author.subscribe_comment_thread(self)
author.subscribe(self)
end
end
......
......@@ -5,7 +5,7 @@ class Commentable
field :commentable_id, type: String
has_many :comment_threads, dependent: :destroy
has_and_belongs_to_many :subscribers, class_name: "User", inverse_of: :subscribed_commentables, autosave: true
has_many :subscriptions, as: :source
attr_accessible :commentable_type, :commentable_id
......@@ -15,6 +15,14 @@ class Commentable
index [[:commentable_type, Mongo::ASCENDING], [:commentable_id, Mongo::ASCENDING]]
def subscriptions
Subscription.where(source_id: self.id, source_type: self.class)
end
def subscribers
subscriptions.map{|s| User.find(s.subscriber_id)}
end
def to_hash(params={})
as_document.slice(*%w[_id commentable_type commentable_id])
end
......
class Subscription
include Mongoid::Document
include Mongoid::Timestamps
field :subscriber_id, type: String
field :source_id, type: String
field :source_type, type: String
index [[:subscriber_id, Mongo::ASCENDING], [:source_id, Mongo::ASCENDING], [:source_type, Mongo::ASCENDING]]
index [[:source_id, Mongo::ASCENDING], [:source_type, Mongo::ASCENDING]]
index :subscriber_id
def to_hash
as_document
end
end
......@@ -8,8 +8,6 @@ class User
has_many :comment_threads, inverse_of: :author
has_many :activities, class_name: "Notification", inverse_of: :actor
has_and_belongs_to_many :notifications, inverse_of: :receivers
has_and_belongs_to_many :followers, class_name: "User", inverse_of: :followings, autosave: true
has_and_belongs_to_many :followings, class_name: "User", inverse_of: :followers
validates_presence_of :external_id
validates_uniqueness_of :external_id
......@@ -18,38 +16,26 @@ class User
as_document.slice(*%w[_id external_id])
end
def follow(user)
if id != user.id and not followings.include? user
followings << user
end
def subscriptions
Subscription.where(subscriber_id: self.id)
end
def unfollow(user)
followings.delete(user)
def follower_subscriptions
Subscription.where(source_id: self.id, source_type: self.class)
end
def self.subscribing(class_plural_sym)
class_plural = class_plural_sym.to_s
class_single = class_plural.singularize
class_name = class_single.camelize
subscribed_symbol = "subscribed_#{class_plural}".intern
has_and_belongs_to_many subscribed_symbol, class_name: class_name, inverse_of: :subscribers
self.class_eval <<-END
def subscribe_#{class_single}(subscribing_object)
if not subscribed_#{class_plural}.include? subscribing_object
subscribed_#{class_plural} << subscribing_object
end
end
def unsubscribe_#{class_single}(subscribing_object)
subscribed_#{class_plural}.delete(subscribing_object)
end
END
def followers
follower_subscriptions.map{|s| User.find(s.subscriber_id)}
end
subscribing :comment_threads
subscribing :commentables
def subscribe(source)
Subscription.find_or_create_by(subscriber_id: self._id.to_s, source_id: source._id.to_s, source_type: source.class.to_s)
end
def unsubscribe(source)
subscription = Subscription.where(subscriber_id: self._id.to_s, source_id: source._id.to_s, source_type: source.class.to_s).first
subscription.destroy
subscription
end
end
......@@ -14,6 +14,7 @@ def init_without_subscriptions
Commentable.delete_all
User.delete_all
Notification.delete_all
Subscription.delete_all
commentable = Commentable.new(commentable_type: "questions", commentable_id: "1")
commentable.save!
......@@ -78,19 +79,21 @@ def init_with_subscriptions
Commentable.delete_all
User.delete_all
Notification.delete_all
Subscription.delete_all
user1 = User.create!(external_id: "1")
user2 = User.create!(external_id: "2")
user2.followings << user1
user2.subscribe(user1)
commentable = Commentable.new(commentable_type: "questions", commentable_id: "1")
commentable.subscribers << [user1, user2]
user1.subscribe(commentable)
user2.subscribe(commentable)
commentable.save!
thread = commentable.comment_threads.new(title: "I can't solve this problem", body: "can anyone help me?", course_id: "1")
thread.author = user1
thread.subscribers << user2
user2.subscribe(thread)
thread.save!
comment = thread.comments.new(body: "this problem is so easy", course_id: "1")
......
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