From a31a1e8c35edfdc3d7af72cd0e6d1416de3c6100 Mon Sep 17 00:00:00 2001 From: Mateus Rambo Strey <mars11@inf.ufpr.br> Date: Thu, 25 Feb 2016 11:06:17 -0300 Subject: [PATCH] working reputation reference calculation --- app/models/score.rb | 9 +++ app/models/score_user_category.rb | 27 +++++++++ app/models/user.rb | 11 +++- app/services/score_calculator_service.rb | 47 ++++++++++++++++ app/workers/score_calculator_worker.rb | 56 ++----------------- db/migrate/20160222144157_create_scores.rb | 2 +- .../20160222144216_create_user_categories.rb | 1 + .../20160225101700_change_users_add_score.rb | 6 ++ db/seeds/scores.rb | 4 +- 9 files changed, 108 insertions(+), 55 deletions(-) create mode 100644 app/services/score_calculator_service.rb create mode 100644 db/migrate/20160225101700_change_users_add_score.rb diff --git a/app/models/score.rb b/app/models/score.rb index cd2f1acf5..508061b5f 100644 --- a/app/models/score.rb +++ b/app/models/score.rb @@ -4,4 +4,13 @@ class Score < ActiveRecord::Base validates_presence_of :name, :code, :weight 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 diff --git a/app/models/score_user_category.rb b/app/models/score_user_category.rb index 9d701e717..1ff802069 100644 --- a/app/models/score_user_category.rb +++ b/app/models/score_user_category.rb @@ -4,4 +4,31 @@ class ScoreUserCategory < ActiveRecord::Base validates_presence_of :score, :user_category, :value 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 diff --git a/app/models/user.rb b/app/models/user.rb index b9b89e6e7..04022015a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -45,10 +45,19 @@ class User < ActiveRecord::Base end 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 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 def default_role diff --git a/app/services/score_calculator_service.rb b/app/services/score_calculator_service.rb new file mode 100644 index 000000000..9dc68a650 --- /dev/null +++ b/app/services/score_calculator_service.rb @@ -0,0 +1,47 @@ +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 diff --git a/app/workers/score_calculator_worker.rb b/app/workers/score_calculator_worker.rb index 5654058c0..82977994b 100644 --- a/app/workers/score_calculator_worker.rb +++ b/app/workers/score_calculator_worker.rb @@ -2,59 +2,13 @@ class ScoreCalculatorWorker include Sidekiq::Worker sidekiq_options queue: :score - def perform(rid) - object = LearningObject.find(rid) + def perform(id, object_class) + return false unless %w(User LearningObject Collection) - unless object.blank? - # Weights to score. Sum must be 1000 - weights = { - "thumbnail": 250, - "description": 150, - "likes": 250, - "views": 150, - "downloads":200 - } + object = object_class.constantize.find(id) - score = 0 + score = ScoreCalculatorService.new(object).calculate - # 250 points if it has thumbnail - 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 + object.update(score: score) end end diff --git a/db/migrate/20160222144157_create_scores.rb b/db/migrate/20160222144157_create_scores.rb index d92548521..736b07385 100644 --- a/db/migrate/20160222144157_create_scores.rb +++ b/db/migrate/20160222144157_create_scores.rb @@ -3,7 +3,7 @@ class CreateScores < ActiveRecord::Migration create_table :scores do |t| t.string :name t.string :code - t.integer :weight + t.float :weight t.boolean :active, default: true t.timestamps null: false diff --git a/db/migrate/20160222144216_create_user_categories.rb b/db/migrate/20160222144216_create_user_categories.rb index 0b1594c62..fa97c78f2 100644 --- a/db/migrate/20160222144216_create_user_categories.rb +++ b/db/migrate/20160222144216_create_user_categories.rb @@ -2,6 +2,7 @@ class CreateUserCategories < ActiveRecord::Migration def change create_table :user_categories do |t| t.string :name + t.float :reference t.timestamps null: false end diff --git a/db/migrate/20160225101700_change_users_add_score.rb b/db/migrate/20160225101700_change_users_add_score.rb new file mode 100644 index 000000000..ac9d75bb8 --- /dev/null +++ b/db/migrate/20160225101700_change_users_add_score.rb @@ -0,0 +1,6 @@ +class ChangeUsersAddScore < ActiveRecord::Migration + def change + add_reference :users, :user_category, index: true + add_column :users, :score, :float, default: 0 + end +end diff --git a/db/seeds/scores.rb b/db/seeds/scores.rb index 6668e3c17..9b5ac52ea 100644 --- a/db/seeds/scores.rb +++ b/db/seeds/scores.rb @@ -7,7 +7,7 @@ categories = [ { name: 'Amador' }, { name: 'Profissional' }, { name: 'Expert' } -] +].reverse # reputation reputations = [ @@ -29,7 +29,7 @@ values = [ [ 50, 3.8, 20, 550, 350, 85, 250, 15, 600], # Amador [ 100, 4.2, 40, 600, 450, 90, 1000, 25, 750], # Profissional [ 250, 4.9, 80, 680, 550, 95, 5000, 35, 800] # Expert -] +].reverse # iterate to make associations categories.each_with_index do |c, i| -- GitLab