Commit 6a27f7aa by Kevin Chugh

fix mega merge conflicts

parents 605fc702 ac7a0a32
...@@ -30,4 +30,6 @@ benchmark_log ...@@ -30,4 +30,6 @@ benchmark_log
bin/ bin/
log/ log/
/.redcar #redcar
.redcar/
/nbproject
get "#{APIPREFIX}/threads" do # retrieve threads by course get "#{APIPREFIX}/threads" do # retrieve threads by course
handle_threads_query(CommentThread.where(course_id: params["course_id"])) #if a group id is sent, then process the set of threads with that group id or with no group id
if params["group_id"]
threads = CommentThread.any_of(
{:course_id => params["course_id"],:group_id => params[:group_id]},
{:course_id => params["course_id"],:group_id.exists => false},
)
else
threads = CommentThread.where(course_id: params["course_id"])
#else process them all
end
handle_threads_query(threads)
end end
get "#{APIPREFIX}/threads/:thread_id" do |thread_id| get "#{APIPREFIX}/threads/:thread_id" do |thread_id|
...@@ -14,12 +24,13 @@ get "#{APIPREFIX}/threads/:thread_id" do |thread_id| ...@@ -14,12 +24,13 @@ get "#{APIPREFIX}/threads/:thread_id" do |thread_id|
end end
put "#{APIPREFIX}/threads/:thread_id" do |thread_id| put "#{APIPREFIX}/threads/:thread_id" do |thread_id|
thread.update_attributes(params.slice(*%w[title body closed commentable_id])) thread.update_attributes(params.slice(*%w[title body closed commentable_id group_id]))
if params["tags"] if params["tags"]
thread.tags = params["tags"] thread.tags = params["tags"]
thread.save thread.save
end end
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
......
...@@ -4,16 +4,27 @@ delete "#{APIPREFIX}/:commentable_id/threads" do |commentable_id| ...@@ -4,16 +4,27 @@ delete "#{APIPREFIX}/:commentable_id/threads" do |commentable_id|
end end
get "#{APIPREFIX}/:commentable_id/threads" do |commentable_id| get "#{APIPREFIX}/:commentable_id/threads" do |commentable_id|
if params["group_id"]
handle_threads_query(commentable.comment_threads) threads = CommentThread.any_of(
{:commentable_id => commentable_id, :group_id => params[:group_id]},
{:commentable_id => commentable_id, :group_id.exists => false},
)
else
threads = commentable.comment_threads
end
handle_threads_query(threads)
end end
post "#{APIPREFIX}/:commentable_id/threads" do |commentable_id| post "#{APIPREFIX}/: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 ]).merge(commentable_id: commentable_id))
thread.anonymous = bool_anonymous || false thread.anonymous = bool_anonymous || false
thread.anonymous_to_peers = bool_anonymous_to_peers || false thread.anonymous_to_peers = bool_anonymous_to_peers || false
thread.tags = params["tags"] || "" thread.tags = params["tags"] || ""
if params["group_id"]
thread.group_id = params["group_id"]
end
thread.author = user thread.author = user
thread.save thread.save
if thread.errors.any? if thread.errors.any?
......
put "#{APIPREFIX}/threads/:thread_id/pin" do |thread_id|
pin thread
end
put "#{APIPREFIX}/threads/:thread_id/unpin" do |thread_id|
unpin thread
end
...@@ -18,7 +18,7 @@ module CommentService ...@@ -18,7 +18,7 @@ module CommentService
API_PREFIX = "/api/#{API_VERSION}" API_PREFIX = "/api/#{API_VERSION}"
end end
if ["staging", "production", "loadtest"].include? environment if ["staging", "production", "loadtest", "edgestage","edgeprod"].include? environment
require 'newrelic_rpm' require 'newrelic_rpm'
end end
...@@ -61,6 +61,7 @@ require './api/comments' ...@@ -61,6 +61,7 @@ require './api/comments'
require './api/users' require './api/users'
require './api/votes' require './api/votes'
require './api/flags' require './api/flags'
require './api/pins'
require './api/notifications_and_subscriptions' require './api/notifications_and_subscriptions'
if RACK_ENV.to_s == "development" if RACK_ENV.to_s == "development"
......
...@@ -30,6 +30,32 @@ production: ...@@ -30,6 +30,32 @@ production:
safe: true safe: true
consistency: strong consistency: strong
edgeprod:
sessions:
default:
hosts:
- sayid.member1.mongohq.com:10001
username: <%= ENV['MONGOHQ_USER'] %>
password: <%= ENV['MONGOHQ_PASS'] %>
database: app10640640
options:
skip_version_check: true
safe: true
consistency: strong
edgestage:
sessions:
default:
hosts:
- vincent.mongohq.com:10001
username: <%= ENV['MONGOHQ_USER'] %>
password: <%= ENV['MONGOHQ_PASS'] %>
database: app10640673
options:
skip_version_check: true
safe: true
consistency: strong
staging: staging:
sessions: sessions:
default: default:
......
...@@ -258,3 +258,14 @@ loadtest: ...@@ -258,3 +258,14 @@ loadtest:
<<: *default_settings <<: *default_settings
monitor_mode: true monitor_mode: true
app_name: <%= ENV["NEW_RELIC_APP_NAME"] %> (Load Test) app_name: <%= ENV["NEW_RELIC_APP_NAME"] %> (Load Test)
edgestage:
<<: *default_settings
monitor_mode: true
app_name: <%= ENV["NEW_RELIC_APP_NAME"] %> (Edge Stage)
edgeprod:
<<: *default_settings
monitor_mode: true
app_name: <%= ENV["NEW_RELIC_APP_NAME"] %> (Edge Prod)
...@@ -58,6 +58,22 @@ helpers do ...@@ -58,6 +58,22 @@ helpers do
end end
def pin(obj)
raise ArgumentError, "User id is required" unless user
obj.pinned = true
obj.save
obj.reload.to_hash.to_json
end
def unpin(obj)
raise ArgumentError, "User id is required" unless user
obj.pinned = nil
obj.save
obj.reload.to_hash.to_json
end
def value_to_boolean(value) def value_to_boolean(value)
!!(value.to_s =~ /^true$/i) !!(value.to_s =~ /^true$/i)
end end
...@@ -128,7 +144,9 @@ helpers do ...@@ -128,7 +144,9 @@ helpers do
else else
page = (params["page"] || DEFAULT_PAGE).to_i page = (params["page"] || DEFAULT_PAGE).to_i
per_page = (params["per_page"] || DEFAULT_PER_PAGE).to_i per_page = (params["per_page"] || DEFAULT_PER_PAGE).to_i
comment_threads = comment_threads.order_by("#{sort_key} #{sort_order}") if sort_key && sort_order #KChugh turns out we don't need to go through all the extra work on the back end because the client is resorting anyway
#KChugh boy was I wrong, we need to sort for pagination
comment_threads = comment_threads.order_by("pinned DESC,#{sort_key} #{sort_order}") if sort_key && sort_order
num_pages = [1, (comment_threads.count / per_page.to_f).ceil].max num_pages = [1, (comment_threads.count / per_page.to_f).ceil].max
page = [num_pages, [1, page].max].min page = [num_pages, [1, page].max].min
paged_comment_threads = comment_threads.page(page).per(per_page) paged_comment_threads = comment_threads.page(page).per(per_page)
......
require 'rest_client'
roots = {}
roots['development'] = "http://localhost:8000"
roots['test'] = "http://localhost:8000"
roots['production'] = "http://edx.org"
roots['staging'] = "http://stage.edx.org"
ROOT = roots[ENV['SINATRA_ENV']]
namespace :kpis do
task :prolific => :environment do
#USAGE
#SINATRA_ENV=development rake kpis:prolific
#or
#SINATRA_ENV=development bundle exec rake kpis:prolific
courses = Content.all.distinct("course_id")
puts "\n\n*********************************************************************"
puts " Users who have created the most forum content on edX (#{Date.today}) "
puts "*********************************************************************\n\n"
courses.each do |c|
contributors = Content.prolific_metric({"course_id" => c}, 10)
#now output
puts c
puts "*********************"
contributors.each do |p|
url = ROOT + "/courses/#{c}/discussion/forum/users/#{p['_id']}"
count_string = "#{p['value'].to_i} contributions:".rjust(25)
puts "#{count_string} #{url} "
end
puts "\n"
end
end
task :starters => :environment do
#USAGE
#SINATRA_ENV=development rake kpis:starters
#or
#SINATRA_ENV=development bundle exec rake kpis:starters
courses = Content.all.distinct("course_id")
puts "\n\n*********************************************************************"
puts " Users who have started the most threads on edX (#{Date.today}) "
puts "*********************************************************************\n\n"
courses.each do |c|
contributors = Content.prolific_metric({"course_id" => c, "_type" => "CommentThread"}, 10)
#now output
puts c
puts "*********************"
contributors.each do |p|
url = ROOT + "/courses/#{c}/discussion/forum/users/#{p['_id']}"
count_string = "#{p['value'].to_i} contributions:".rjust(25)
puts "#{count_string} #{url} "
end
puts "\n"
end
end
task :ppu => :environment do
#USAGE
#SINATRA_ENV=development rake kpis:ppu
#or
#SINATRA_ENV=development bundle exec rake kpis:ppu
courses = Content.all.distinct("course_id")
puts "\n\n*********************************************************************"
puts "Average threads per contributing user per course on edX (#{Date.today}) "
puts "*********************************************************************\n\n"
courses.each do |c|
#first, get all the users who have contributed
contributors = Content.prolific_metric({"course_id" => c}, 10)
total_users = contributors.count
#now, get the threads
total_threads = Content.where("_type" => "CommentThread","course_id" => c).count
ratio = total_threads.to_f / total_users.to_f
#now output
puts c
puts "*********************"
puts "Total Threads: #{total_threads}"
puts "Total Users: #{total_users}"
puts "Average Thread/User: #{ratio}"
puts "\n"
end
end
task :epu => :environment do
#USAGE
#SINATRA_ENV=development rake kpis:epu
#or
#SINATRA_ENV=development bundle exec rake kpis:epu
courses = Content.all.distinct("course_id")
puts "\n\n*****************************************************************************************************************"
puts "Average contributions (votes, threads, or comments) per contributing user per course on edX (#{Date.today}) "
puts "*********************************************************************************************************************\n\n"
courses.each do |c|
#first, get all the users who have contributed
summary = Content.summary({"course_id" => c})
total_users = summary["contributor_count"]
total_activity = summary['thread_count']
total_activity += summary['comment_count']
total_activity += summary['vote_count']
ratio = total_activity.to_f / total_users.to_f
puts c
puts "*********************"
puts "Total Threads: #{summary['thread_count']}"
puts "Total Comments: #{summary['comment_count']}"
puts "Total Votes: #{summary['vote_count']}\n\n"
puts "Total Users: #{summary['contributor_count']}"
puts "Total Engagements: #{total_activity}\n\n"
puts "Average Engagement Per Engaging User: #{ratio}\n\n\n "
end
end
task :orphans => :environment do
#USAGE
#SINATRA_ENV=development rake kpis:orphans
#or
#SINATRA_ENV=development bundle exec rake kpis:orphans
courses = Content.all.distinct("course_id")
puts "\n\n****************************************************"
puts "thread reply rate per course on edX (#{Date.today}) "
puts "****************************************************\n\n"
courses.each do |c|
#first, get all the users who have contributed
threads = Content.where({"course_id" => c, "_type" => "CommentThread"})
orphans = Content.where({"course_id" => c, "_type" => "CommentThread", "comment_count" => 0})
ratio = orphans.count.to_f / threads.count.to_f
puts c
puts "*********************"
puts "Total Threads: #{threads.count}"
puts "Total Orphaned Threads: #{orphans.count}"
if threads.count > 0
puts "Orphan Ratio: #{(ratio*1000).round.to_f/10.0}%"
end
puts "\n\n\n"
end
end
end
...@@ -21,6 +21,8 @@ class CommentThread < Content ...@@ -21,6 +21,8 @@ class CommentThread < Content
field :closed, type: Boolean, default: false field :closed, type: Boolean, default: false
field :at_position_list, type: Array, default: [] field :at_position_list, type: Array, default: []
field :last_activity_at, type: Time field :last_activity_at, type: Time
field :group_id, type: Integer
field :pinned, type: Boolean
index({author_id: 1, course_id: 1}) index({author_id: 1, course_id: 1})
...@@ -39,9 +41,11 @@ class CommentThread < Content ...@@ -39,9 +41,11 @@ class CommentThread < Content
indexes :comment_count, type: :integer, included_in_all: false indexes :comment_count, type: :integer, included_in_all: false
indexes :votes_point, type: :integer, as: 'votes_point', included_in_all: false indexes :votes_point, type: :integer, as: 'votes_point', included_in_all: false
indexes :course_id, type: :string, index: :not_analyzed, incldued_in_all: false indexes :course_id, type: :string, index: :not_analyzed, included_in_all: false
indexes :commentable_id, type: :string, index: :not_analyzed, incldued_in_all: false indexes :commentable_id, type: :string, index: :not_analyzed, included_in_all: false
indexes :author_id, type: :string, as: 'author_id', index: :not_analyzed, incldued_in_all: false indexes :author_id, type: :string, as: 'author_id', index: :not_analyzed, included_in_all: false
indexes :group_id, type: :integer, as: 'group_id', index: :not_analyzed, included_in_all: false
#indexes :pinned, type: :boolean, as: 'pinned', index: :not_analyzed, included_in_all: false
end end
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
...@@ -107,14 +111,27 @@ class CommentThread < Content ...@@ -107,14 +111,27 @@ class CommentThread < Content
search.filter(:term, commentable_id: params["commentable_id"]) if params["commentable_id"] search.filter(:term, commentable_id: params["commentable_id"]) if params["commentable_id"]
search.filter(:terms, commentable_id: params["commentable_ids"]) if params["commentable_ids"] search.filter(:terms, commentable_id: params["commentable_ids"]) if params["commentable_ids"]
search.filter(:term, course_id: params["course_id"]) if params["course_id"] search.filter(:term, course_id: params["course_id"]) if params["course_id"]
if params["group_id"]
search.filter :or, [
{:not => {:exists => {:field => :group_id}}},
{:term => {:group_id => params["group_id"]}}
]
end
search.sort {|sort| sort.by sort_key, sort_order} if sort_key && sort_order #TODO should have search option 'auto sort or sth' search.sort {|sort| sort.by sort_key, sort_order} if sort_key && sort_order #TODO should have search option 'auto sort or sth'
search.size per_page search.size per_page
search.from per_page * (page - 1) search.from per_page * (page - 1)
results = search.results
if CommentService.config[:cache_enabled] if CommentService.config[:cache_enabled]
Sinatra::Application.cache.set(memcached_key, search.results, CommentService.config[:cache_timeout][:threads_search].to_i) Sinatra::Application.cache.set(memcached_key, results, CommentService.config[:cache_timeout][:threads_search].to_i)
end end
search.results results
end end
def activity_since(from_time=nil) def activity_since(from_time=nil)
...@@ -161,6 +178,8 @@ class CommentThread < Content ...@@ -161,6 +178,8 @@ class CommentThread < Content
"abuse_flaggers" => abuse_flaggers, "abuse_flaggers" => abuse_flaggers,
"tags" => tags_array, "tags" => tags_array,
"type" => "thread", "type" => "thread",
"group_id" => group_id,
"pinned" => pinned?,
"endorsed" => endorsed?) "endorsed" => endorsed?)
if params[:recursive] if params[:recursive]
......
...@@ -13,8 +13,6 @@ class Content ...@@ -13,8 +13,6 @@ class Content
end end
end end
def self.flagged def self.flagged
#return an array of flagged content #return an array of flagged content
holder = [] holder = []
...@@ -23,5 +21,66 @@ class Content ...@@ -23,5 +21,66 @@ class Content
end end
holder holder
end end
def self.prolific_metric what, count
#take a hash of criteria (what) and return a hash of hashes
#course => user => count
contributors = {}
map = "function(){emit(this.author_id,1)}"
reduce = "function(k, vals) { var sum = 0; for(var i in vals) sum += vals[i]; return sum; }"
contributors = []
self.where(what).map_reduce(map,reduce).out(replace: "results").each do |d|
contributors << d
end
#now sort and limit them
#first sort destructively
contributors.sort! {|a,b| -a["value"] <=> -b["value"]}
#then trim it
contributors = contributors[0..(count - 1)]
contributors
end
def self.summary what
#take a hash of criteria (what) and return a hash of hashes
#of total users, votes, comments, endorsements,
answer = {}
vote_count = 0
thread_count = 0
comment_count = 0
contributors = []
content = self.where(what)
content.each do |c|
contributors << c.author_id
contributors << c["votes"]["up"]
contributors << c["votes"]["down"]
vote_count += c["votes"]["count"]
if c._type == "CommentThread"
thread_count += 1
elsif c._type == "Comment"
comment_count += 1
end
end
#uniquify contributors
contributors = contributors.uniq
#assemble the answer and ship
answer["vote_count"] = vote_count
answer["thread_count"] = thread_count
answer["comment_count"] = comment_count
answer["contributor_count"] = contributors.count
answer
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