Commit 5d9bdd99 by Rocky Duan

basic functionality as before: mostly untested

parent 4944363e
...@@ -4,18 +4,12 @@ gem 'rake' ...@@ -4,18 +4,12 @@ gem 'rake'
gem 'sinatra' gem 'sinatra'
gem 'activerecord'
gem 'yajl-ruby' gem 'yajl-ruby'
gem 'ancestry'
gem 'sqlite3' gem 'sqlite3'
gem 'ampex' gem 'ampex'
gem 'thumbs_up', :git => "git@github.com:dementrock/thumbs_up.git"
# ruby-mongo-driver # ruby-mongo-driver
gem 'mongo', "1.6.2" gem 'mongo', "1.6.2"
gem 'bson' gem 'bson'
...@@ -24,7 +18,7 @@ gem 'bson_ext' ...@@ -24,7 +18,7 @@ gem 'bson_ext'
gem 'mongoid', "~> 2.4.0" gem 'mongoid', "~> 2.4.0"
gem 'mongoid-tree' gem 'mongoid-tree'
gem 'voteable_mongo' gem 'voteable_mongo', :git => 'https://github.com/dementrock/voteable_mongo.git'
group :test do group :test do
gem 'rspec' gem 'rspec'
......
...@@ -3,6 +3,7 @@ require 'mongo' ...@@ -3,6 +3,7 @@ require 'mongo'
require 'mongoid' require 'mongoid'
require 'yaml' require 'yaml'
require 'logger' require 'logger'
require 'active_support/all'
require 'sinatra' require 'sinatra'
require 'mongoid/tree' require 'mongoid/tree'
require 'voteable_mongo' require 'voteable_mongo'
...@@ -21,7 +22,9 @@ namespace :db do ...@@ -21,7 +22,9 @@ namespace :db do
require_relative 'models/comment.rb' require_relative 'models/comment.rb'
require_relative 'models/comment_thread.rb' require_relative 'models/comment_thread.rb'
require_relative 'models/user.rb' require_relative 'models/user.rb'
require_relative 'models/commentable.rb'
Commentable.delete_all
Comment.delete_all Comment.delete_all
CommentThread.delete_all CommentThread.delete_all
User.delete_all User.delete_all
...@@ -33,27 +36,26 @@ namespace :db do ...@@ -33,27 +36,26 @@ namespace :db do
user = User.create!(external_id: "1") user = User.create!(external_id: "1")
def generate_comments(commentable_type, commentable_id, level_limit, user) def generate_comments(commentable_type, commentable_id, level_limit, user)
commentable = Commentable.create!(commentable_type: commentable_type, commentable_id: commentable_id)
5.times do 5.times do
comment_thread = CommentThread.new( comment_thread = commentable.comment_threads.new(
commentable_type: commentable_type, commentable_id: commentable_id, commentable_type: commentable_type, commentable_id: commentable_id,
body: "This is a post", title: "Post No.#{rand(10)}", body: "This is a post", title: "Post No.#{rand(10)}",
course_id: "1") course_id: "1")
comment_thread.author = user comment_thread.author = user
comment_thread.save! comment_thread.save!
3.times do 3.times do
comment = Comment.new(body: "top comment", course_id: "1") comment = comment_thread.comments.new(body: "top comment", course_id: "1")
comment.comment_thread = comment_thread
comment.author = user comment.author = user
comment.endorsed = [true, false].sample comment.endorsed = [true, false].sample
comment.save! comment.save!
end end
100.times do 10.times do
comment = Comment.where(comment_thread_id: comment_thread.id).reject{|c| c.depth >= level_limit}.sample comment = Comment.where(comment_thread_id: comment_thread.id).reject{|c| c.depth >= level_limit}.sample
sub_comment = Comment.new(body: "comment body", course_id: "1") sub_comment = comment.children.new(body: "comment body", course_id: "1")
sub_comment.author = user sub_comment.author = user
sub_comment.endorsed = [true, false].sample sub_comment.endorsed = [true, false].sample
sub_comment.save! sub_comment.save!
comment.children << sub_comment
end end
puts "Generating a comment thread for #{commentable_type} No.#{commentable_id}" puts "Generating a comment thread for #{commentable_type} No.#{commentable_id}"
end end
...@@ -61,28 +63,27 @@ namespace :db do ...@@ -61,28 +63,27 @@ namespace :db do
generate_comments("questions" , 1, level_limit, user) generate_comments("questions" , 1, level_limit, user)
generate_comments("questions" , 2, level_limit, user) generate_comments("questions" , 2, level_limit, user)
generate_comments("questions" , 3, level_limit, user)
generate_comments("courses" , 1, level_limit, user) generate_comments("courses" , 1, level_limit, user)
generate_comments("lectures" , 1, level_limit, user) generate_comments("lectures" , 1, level_limit, user)
generate_comments("lectures" , 2, level_limit, user) generate_comments("lectures" , 2, level_limit, user)
generate_comments("lectures" , 3, level_limit, user)
=begin
puts "voting" puts "voting"
users = [] users = []
(1..20).each do |id| (1..10).each do |id|
users << User.find_or_create_by(external_id: id.to_s) users << User.find_or_create_by(external_id: id.to_s)
end end
current = 0 CommentThread.all.each do |c|
total = Comment.count (0...10).each do |i|
users[i].vote(c, [:up, :down].sample)
end
end
Comment.all.each do |c| Comment.all.each do |c|
(0...20).each do |i| (0...10).each do |i|
users[i].vote(c, [:up, :down].sample) users[i].vote(c, [:up, :down].sample)
end end
current += 1
puts "voted #{current}/#{total}"
end end
=end
end_time = Time.now end_time = Time.now
......
require 'mongoid'
class Comment class Comment
include Mongoid::Document include Mongoid::Document
include Mongoid::Tree include Mongoid::Tree
...@@ -18,10 +16,45 @@ class Comment ...@@ -18,10 +16,45 @@ class Comment
attr_accessible :body, :course_id attr_accessible :body, :course_id
validates_presence_of :body validates_presence_of :body
validates_presence_of :course_id validates_presence_of :course_id # do we really need this?
validates_presence_of :author #validates_presence_of :author # allow anonymity?
before_destroy :delete_descendants before_destroy :delete_descendants
#after_create :create_feeds #after_create :create_feeds
def self.hash_tree(nodes)
nodes.map{|node, sub_nodes| node.to_hash.merge("children" => hash_tree(sub_nodes).compact)}
end
def subtree
arrange(descendants.order_by([[:parent_ids, :asc], [:created_at, :asc]]))
end
def to_hash(params={})
doc = as_document.slice(*%w[body course_id endorsed _id]).
merge("user_id" => author.external_id).
merge("votes" => votes.slice(*%w[count up_count down_count point]))
if params[:recursive]
doc = doc.merge("children" => self.class.hash_tree(subtree))
end
doc
end
private
# adopted and modified from https://github.com/stefankroes/ancestry/blob/master/lib/ancestry/class_methods.rb
def arrange(nodes)
# Get all nodes ordered by ancestry and start sorting them into an empty hash
nodes.inject(ActiveSupport::OrderedHash.new) do |arranged_nodes, node|
# Find the insertion point for that node by going through its ancestors
node.parent_ids.inject(arranged_nodes) do |insertion_point, parent_id|
insertion_point.each do |parent, children|
# Change the insertion point to children if node is a descendant of this parent
insertion_point = children if parent_id == parent._id
end
insertion_point
end[node] = ActiveSupport::OrderedHash.new
arranged_nodes
end
end
end end
...@@ -8,21 +8,28 @@ class CommentThread ...@@ -8,21 +8,28 @@ class CommentThread
field :title, type: String field :title, type: String
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
field :commentable_type, type: String
belongs_to :author, class_name: "User", index: true belongs_to :author, class_name: "User", index: true
belongs_to :commentable, index: true
has_many :comments, dependent: :destroy # Use destroy to envoke callback on the top-level comments has_many :comments, dependent: :destroy # Use destroy to envoke callback on the top-level comments
attr_accessible :title, :body, :course_id, :commentable_id, :commentable_type attr_accessible :title, :body, :course_id
validates_presence_of :title validates_presence_of :title
validates_presence_of :body validates_presence_of :body
validates_presence_of :course_id validates_presence_of :course_id # do we really need this?
validates_presence_of :commentable_id #validates_presence_of :author #allow anonymity?
validates_presence_of :commentable_type
index [:commentable_type, :commentable_id]
#after_create :create_feeds #after_create :create_feeds
def to_hash(params={})
doc = as_document.slice(*%w[title body course_id _id]).
merge("user_id" => author.external_id).
merge("votes" => votes.slice(*%w[count up_count down_count point]))
if params[:recursive]
doc = doc.merge("children" => comments.map{|c| c.to_hash(recursive: true)})
end
doc
end
end end
class Commentable
include Mongoid::Document
field :commentable_type, type: String
field :commentable_id, type: String
has_many :comment_threads, dependent: :destroy
attr_accessible :commentable_type, :commentable_id
validates_presence_of :commentable_type
validates_presence_of :commentable_id
validates_uniqueness_of :commentable_id, scope: :commentable_type
index [:commentable_type, :commentable_id]
def to_hash
as_document
end
end
...@@ -3,7 +3,9 @@ class User ...@@ -3,7 +3,9 @@ class User
include Mongo::Voter include Mongo::Voter
field :external_id, type: String field :external_id, type: String
has_many :comments has_many :comments
has_many :commentable
attr_accessible :external_id attr_accessible :external_id
......
...@@ -2,12 +2,87 @@ require 'spec_helper' ...@@ -2,12 +2,87 @@ require 'spec_helper'
require 'yajl' require 'yajl'
describe "app" do describe "app" do
before :each do
Comment.delete_all
CommentThread.delete_all
Commentable.delete_all
User.delete_all
commentable = Commentable.create!(commentable_type: "questions", commentable_id: "1")
user = User.create!(external_id: "1")
comment_thread = commentable.comment_threads.create!(title: "I can't solve this problem", body: "can anyone help me?", course_id: "1")
comment_thread.author = user
comment_thread.save!
comment = comment_thread.comments.create!(body: "this problem is so easy", course_id: "1")
comment.author = user
comment.save!
comment = comment.children.create!(body: "not for me!", course_id: "1")
comment.author = user
comment.save!
comment = comment_thread.comments.create!(body: "see the textbook on page 69. it's quite similar", course_id: "1")
comment.author = user
comment.save!
comment = comment.children.create!(body: "thank you!", course_id: "1")
comment.author = user
comment.save!
comment_thread = commentable.comment_threads.create!(title: "This problem is wrong", body: "it is unsolvable", course_id: "2")
comment_thread.author = user
comment_thread.save!
comment = comment_thread.comments.create!(body: "how do you know?", course_id: "1")
comment.author = user
comment.save!
comment = comment.children.create!(body: "because blablabla", course_id: "1")
comment.author = user
comment.save!
comment = comment_thread.comments.create!(body: "no wonder I can't solve it", course_id: "1")
comment.author = user
comment.save!
comment = comment.children.create!(body: "+1", course_id: "1")
comment.author = user
comment.save!
Comment.all.each do |c|
(1..10).each do |id|
User.find_or_create_by(external_id: id.to_s).vote(c, [:up, :down].sample)
end
end
CommentThread.all.each do |c|
(1..10).each do |id|
User.find_or_create_by(external_id: id.to_s).vote(c, [:up, :down].sample)
end
end
end
describe "comments" do describe "comments" do
before :each do
Comment.delete_all describe "GET /api/v1/commentables/:commentable_type/:commentable_id/comment_threads" do
CommentThread.delete_all it "get all comment threads associated with a commentable object" do
get "/api/v1/commentables/questions/1/comment_threads"
last_response.should be_ok
comment_threads = Yajl::Parser.parse last_response.body
comment_threads.length.should == 2
comment_threads.index{|c| c["body"] == "can anyone help me?"}.should_not be_nil
comment_threads.index{|c| c["body"] == "it is unsolvable"}.should_not be_nil
end
it "get all comment threads and comments associated with a commentable object" do
get "/api/v1/commentables/questions/1/comment_threads", recursive: true
last_response.should be_ok
comment_threads = Yajl::Parser.parse last_response.body
comment_threads.length.should == 2
comment_threads.index{|c| c["body"] == "can anyone help me?"}.should_not be_nil
comment_threads.index{|c| c["body"] == "it is unsolvable"}.should_not be_nil
comment_thread = comment_threads.first
comment_thread["children"].length.should == 2
end
end end
describe "POST on /api/v1/commentables/:commentable_type/:commentable_id/comments" do
=begin
describe "POST on /api/v1/commentables/:commentable_type/:commentable_id/comment_threads" do
it "should create a top-level comment with correct body, title, user_id, and course_id" do it "should create a top-level comment with correct body, title, user_id, and course_id" do
post "/api/v1/commentables/questions/1/comments", :body => "comment body", :title => "comment title", :user_id => 1, :course_id => 1 post "/api/v1/commentables/questions/1/comments", :body => "comment body", :title => "comment title", :user_id => 1, :course_id => 1
last_response.should be_ok last_response.should be_ok
...@@ -293,5 +368,6 @@ describe "app" do ...@@ -293,5 +368,6 @@ describe "app" do
last_response.should be_ok last_response.should be_ok
end end
end end
=end
end end
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