Skip to content
Snippets Groups Projects
Commit a31a1e8c authored by Mateus Rambo Strey's avatar Mateus Rambo Strey
Browse files

working reputation reference calculation

parent deab3b0f
No related branches found
No related tags found
No related merge requests found
...@@ -4,4 +4,13 @@ class Score < ActiveRecord::Base ...@@ -4,4 +4,13 @@ class Score < ActiveRecord::Base
validates_presence_of :name, :code, :weight validates_presence_of :name, :code, :weight
validates_uniqueness_of :code validates_uniqueness_of :code
def max_value
score_user_categories.maximum(:value)
end
def category_value(category)
score = score_user_categories.where(score: self, user_category: category).first
(score.nil?) ? nil : score.value
end
end end
...@@ -4,4 +4,31 @@ class ScoreUserCategory < ActiveRecord::Base ...@@ -4,4 +4,31 @@ class ScoreUserCategory < ActiveRecord::Base
validates_presence_of :score, :user_category, :value validates_presence_of :score, :user_category, :value
validates_uniqueness_of :user_category, scope: :score validates_uniqueness_of :user_category, scope: :score
after_commit :calculate_reference
private
def calculate_reference
return 0 if Score.count < 9 || !reputation_hash.values.all? { |x| !x.nil? }
reference = ScoreCalculatorService.new(self).reputation(reputation_hash)
user_category.update(reference: reference) if reference.is_a? Float
end
def reputation_hash
{
'reputation_submitted': Score.where(code: 'reputation_submitted').first.category_value(user_category),
'reputation_reviews_average_score': Score.where(code: 'reputation_reviews_average_score').first.category_value(user_category),
'reputation_added_in_best_collections': Score.where(code: 'reputation_added_in_best_collections').first.category_value(user_category),
'reputation_best_score': Score.where(code: 'reputation_best_score').first.category_value(user_category),
'reputation_average_score': Score.where(code: 'reputation_average_score').first.category_value(user_category),
'reputation_reviews_rate': Score.where(code: 'reputation_reviews_rate').first.category_value(user_category),
# 'reputation_confirmed_complaints': Score.where(code: 'reputation_confirmed_complaints').first.category_value(user_category),
'reputation_followers': Score.where(code: 'reputation_followers').first.category_value(user_category),
'reputation_submitted_recently': Score.where(code: 'reputation_submitted_recently').first.category_value(user_category),
'reputation_collection_score': Score.where(code: 'reputation_collection_score').first.category_value(user_category)
}
end
end end
...@@ -45,10 +45,19 @@ class User < ActiveRecord::Base ...@@ -45,10 +45,19 @@ class User < ActiveRecord::Base
end end
def review_approval_average def review_approval_average
array = reviews.map { |review| review.rates_percentage } array = reviews.map(&:rates_percentage)
array.inject(0.0) { |sum, el| sum + el } / array.size array.inject(0.0) { |sum, el| sum + el } / array.size
end end
def learning_objects_in_best_collections
average = Collection.average(:score)
collections.where(:score > average).count
end
def learning_objects_submitted_recently
learning_objects.where(:created_at > (Time.now - 2.months)).count
end
private private
def default_role def default_role
......
class ScoreCalculatorService
def initialize(object)
@object = object
@class = @object.class.name
end
def calculate
case @class
when 'User' then reputation
end
end
def reputation(values = nil)
values = reputation_hash if values.nil?
sum = 0
Score.all.find_each do |score|
sum += (values[score.code.to_sym].to_f / score.max_value.to_f) * score.weight.to_f unless score.max_value.to_f == 0
end
sum.to_f / sum_weights.to_f
end
private
def reputation_hash
{
'reputation_submitted': @object.learning_objects.count,
'reputation_reviews_average_score': @object.learning_objects.review_ratings_average,
'reputation_added_in_best_collections': @object.learning_objects_in_best_collections,
'reputation_best_score': @object.learning_objects.maximum(:score),
'reputation_average_score': @object.learning_objects.average(:score),
'reputation_reviews_rate': @object.review_approval_average,
# 'reputation_confirmed_complaints': ,
'reputation_followers': @object.followers.count,
'reputation_submitted_recently': @object.learning_objects_submitted_recently,
'reputation_collection_score': @object.where(privacy: 'public').average(:score)
}
end
def sum_weights
Score.pluck(:weight).inject(0){|sum,r| sum + r }.to_f
end
end
...@@ -2,59 +2,13 @@ class ScoreCalculatorWorker ...@@ -2,59 +2,13 @@ class ScoreCalculatorWorker
include Sidekiq::Worker include Sidekiq::Worker
sidekiq_options queue: :score sidekiq_options queue: :score
def perform(rid) def perform(id, object_class)
object = LearningObject.find(rid) return false unless %w(User LearningObject Collection)
unless object.blank? object = object_class.constantize.find(id)
# Weights to score. Sum must be 1000
weights = {
"thumbnail": 250,
"description": 150,
"likes": 250,
"views": 150,
"downloads":200
}
score = 0 score = ScoreCalculatorService.new(object).calculate
# 250 points if it has thumbnail object.update(score: score)
score += weights[:thumbnail] unless object.thumbnail.blank?
# 150 points if it has description
score += weights[:description] unless object.description.blank?
# range to 250 points, for normalized likes ( maxLikes/actualLike => [0..1] )
score += divide_by_max(
LearningObject.count('Likes', object),
LearningObject.max('Likes'),
weights[:likes]
)
# range to 200 points, for normalized views ( maxLikes/actualLike => [0..1] )
score += divide_by_max(
LearningObject.count('Views', object),
LearningObject.max('Views'),
weights[:views]
)
# downloads
score += divide_by_max(
LearningObject.count('Downloads', object),
LearningObject.max('Downloads'),
weights[:downloads]
)
LearningObject.update_property(object, 'score', score)
end
end
private
def divide_by_max(i, max, weight)
if (i > 0 && max > 0) && (i <= max)
(i / max) * weight
else
0
end
end end
end end
...@@ -3,7 +3,7 @@ class CreateScores < ActiveRecord::Migration ...@@ -3,7 +3,7 @@ class CreateScores < ActiveRecord::Migration
create_table :scores do |t| create_table :scores do |t|
t.string :name t.string :name
t.string :code t.string :code
t.integer :weight t.float :weight
t.boolean :active, default: true t.boolean :active, default: true
t.timestamps null: false t.timestamps null: false
......
...@@ -2,6 +2,7 @@ class CreateUserCategories < ActiveRecord::Migration ...@@ -2,6 +2,7 @@ class CreateUserCategories < ActiveRecord::Migration
def change def change
create_table :user_categories do |t| create_table :user_categories do |t|
t.string :name t.string :name
t.float :reference
t.timestamps null: false t.timestamps null: false
end end
......
class ChangeUsersAddScore < ActiveRecord::Migration
def change
add_reference :users, :user_category, index: true
add_column :users, :score, :float, default: 0
end
end
...@@ -7,7 +7,7 @@ categories = [ ...@@ -7,7 +7,7 @@ categories = [
{ name: 'Amador' }, { name: 'Amador' },
{ name: 'Profissional' }, { name: 'Profissional' },
{ name: 'Expert' } { name: 'Expert' }
] ].reverse
# reputation # reputation
reputations = [ reputations = [
...@@ -29,7 +29,7 @@ values = [ ...@@ -29,7 +29,7 @@ values = [
[ 50, 3.8, 20, 550, 350, 85, 250, 15, 600], # Amador [ 50, 3.8, 20, 550, 350, 85, 250, 15, 600], # Amador
[ 100, 4.2, 40, 600, 450, 90, 1000, 25, 750], # Profissional [ 100, 4.2, 40, 600, 450, 90, 1000, 25, 750], # Profissional
[ 250, 4.9, 80, 680, 550, 95, 5000, 35, 800] # Expert [ 250, 4.9, 80, 680, 550, 95, 5000, 35, 800] # Expert
] ].reverse
# iterate to make associations # iterate to make associations
categories.each_with_index do |c, i| categories.each_with_index do |c, i|
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment