Commit 046756e4dfafa863b7c8fc305227bcaf42acb452
1 parent
70917f62
Exists in
master
and in
1 other branch
Create script for searching and fixing people points
Showing
1 changed file
with
156 additions
and
0 deletions
Show diff stats
... | ... | @@ -0,0 +1,156 @@ |
1 | +#!/usr/bin/env ruby | |
2 | +# encoding: UTF-8 | |
3 | + | |
4 | +# | |
5 | +# This script was created for ensuring all the actions observed | |
6 | +# by merit for pontuation was judged and pontuated accordingly | |
7 | +# It checks the merit_actions registers for each action(model | |
8 | +# create or destroy) and recreates it | |
9 | +# | |
10 | + | |
11 | +require 'csv' | |
12 | + | |
13 | +class ProcessObserver | |
14 | + def update(changed_data) | |
15 | + merit = changed_data[:merit_object] | |
16 | + if merit.kind_of?(Merit::Score::Point) | |
17 | + action = Merit::Action.find(changed_data[:merit_action_id]) | |
18 | + new_date = YAML.load(action.target_data).created_at | |
19 | + action.update_attribute(:created_at, new_date) | |
20 | + merit.update_attribute(:created_at, new_date) | |
21 | + end | |
22 | + end | |
23 | +end | |
24 | + | |
25 | +def create_action(obj, index, count) | |
26 | + target_model = obj.class.base_class.name.downcase | |
27 | + action = Merit::Action.find_by_target_id_and_target_model_and_action_method(obj.id, target_model, 'create') | |
28 | + if action.nil? | |
29 | + puts "#{index}/#{count} Create merit action for #{target_model} #{obj.id}" | |
30 | + begin | |
31 | + obj.new_merit_action(:create) | |
32 | + rescue Exception => e | |
33 | + puts "Could not be create: #{e.message}" | |
34 | + end | |
35 | + end | |
36 | +end | |
37 | + | |
38 | +def recreate_actions person, objects, category | |
39 | + puts "Recreating actions for #{person.identifier} on model #{objects.first.class.base_class.name}" | |
40 | + actions = Merit::Action.where(target_id: objects, target_model: objects.first.class.base_class.name.downcase, action_method: 'create') | |
41 | + Merit::Score::Point.where(action_id: actions).destroy_all | |
42 | + actions.destroy_all | |
43 | + # erase remaining points if any (can be wrong on destroy cases ?) | |
44 | + person.score_points.where(score_id: Merit::Score.where(category: category)).destroy_all | |
45 | + count = objects.count | |
46 | + objects.each_with_index{ |obj, index| create_action(obj, index, count) } | |
47 | +end | |
48 | + | |
49 | +def calc_points categorization, objects | |
50 | + rule = Merit::PointRules::AVAILABLE_RULES[categorization.point_type.name.to_sym] | |
51 | + return 0 if rule.nil? | |
52 | + | |
53 | + sum = objects.map{|o| rule[:value].respond_to?(:call) ? rule[:value].call(o) : rule[:value] }.sum | |
54 | + return sum * categorization.weight | |
55 | +end | |
56 | + | |
57 | +# avoid updating level on every action for increasing performance | |
58 | +Merit.observers.delete('RankObserver') | |
59 | + | |
60 | +Merit.observers << 'ProcessObserver' | |
61 | + | |
62 | +class Article < ActiveRecord::Base | |
63 | + def self.text_article_types | |
64 | + ['ProposalsDiscussionPlugin::Proposal'] | |
65 | + end | |
66 | +end | |
67 | + | |
68 | +puts "Creaning up points from actions which don't exist" | |
69 | +Merit::Score::Point.includes(:action).find_each(batch_size: 100) do |point| | |
70 | + point.destroy if point.action.nil? | |
71 | +end | |
72 | + | |
73 | +Environment.all.each do |environment| | |
74 | + puts "Process environment #{environment.name}" | |
75 | + | |
76 | + Merit::AppPointRules.clear | |
77 | + Merit::AppBadgeRules.clear | |
78 | + Merit::AppPointRules.merge!(Merit::PointRules.new(environment).defined_rules) | |
79 | + Merit::AppBadgeRules.merge!(Merit::BadgeRules.new(environment).defined_rules) | |
80 | + | |
81 | + group_control = YAML.load(File.read(File.join(Rails.root,'tmp','control_group.yml'))) if File.exist?(File.join(Rails.root,'tmp','control_group.yml')) | |
82 | + conditions = group_control.nil? ? {} : {:identifier => group_control.map{|k,v| v['profiles']}.flatten} | |
83 | + people_count = environment.people.where(conditions).count | |
84 | + person_index = 0 | |
85 | + remaining_wrong_points = [] | |
86 | + puts "Analising environment people" | |
87 | + environment.people.find_each(:conditions => conditions) do |person| | |
88 | + person_index += 1 | |
89 | + profile_ids = GamificationPlugin::PointsCategorization.uniq.pluck(:profile_id) | |
90 | + profile_ids.keep_if { |item| group_control.keys.include?(item) } unless group_control.nil? | |
91 | + profile_ids.each do |profile_id| | |
92 | + profile = Profile.where(id: profile_id).first | |
93 | + if profile.nil? | |
94 | + profile_name = 'generic' | |
95 | + # person actions | |
96 | + person_articles = Article.where(author_id: person.id) | |
97 | + comments = Comment.where(author_id: person.id) | |
98 | + votes = Vote.for_voter(person) | |
99 | + follows = ArticleFollower.where(person_id: person.id) | |
100 | + else | |
101 | + profile_name = profile.identifier | |
102 | + #person actions | |
103 | + person_articles = Article.where(author_id: person.id, profile_id: profile) | |
104 | + comments = Comment.where(author_id: person.id, source_id: profile.articles) | |
105 | + general_votes = Vote.for_voter(person) | |
106 | + votes = general_votes.where("(voteable_type = 'Article' and voteable_id in (?)) or (voteable_type = 'Comment' and voteable_id in (?))",profile.articles, Comment.where(source_type: "Article", source_id: profile.articles)) | |
107 | + follows = ArticleFollower.where(person_id: person.id, article_id: profile.articles) | |
108 | + end | |
109 | + # received actions | |
110 | + comments_received = Comment.where(:source_id => person_articles) | |
111 | + votes_received = Vote.where("(voteable_type = 'Article' and voteable_id in (?)) or (voteable_type = 'Comment' and voteable_id in (?))",person_articles, person.comments) | |
112 | + follows_received = ArticleFollower.where(:article_id => person_articles) | |
113 | + | |
114 | + puts "#{person_index}/#{people_count} - Analising points for #{person.identifier} on #{profile_name}" | |
115 | + puts "Proposed #{person_articles.count} times, Commented #{comments.count} times, Voted #{votes.count} times, Followed #{follows.count} times" | |
116 | + puts "Received #{votes_received.count} votes, #{comments_received.count} comments, #{follows_received.count} follows\n" | |
117 | + | |
118 | + scope_by_type = { | |
119 | + article_author: person_articles, comment_author: comments, vote_voter: votes, follower: follows, | |
120 | + comment_article_author: comments_received, vote_voteable_author: votes_received, followed_article_author: follows_received | |
121 | + } | |
122 | + | |
123 | + puts "Points:" | |
124 | + scope_by_type.each do |type, scope| | |
125 | + c = GamificationPlugin::PointsCategorization.for_type(type).where(profile_id: profile_id).joins(:point_type).first | |
126 | + points = calc_points c, scope | |
127 | + puts "On #{c.point_type.name} it should have #{points} and have #{person.points(category: c.id.to_s)} " | |
128 | + if points != person.points(category: c.id.to_s) | |
129 | + recreate_actions person, scope, c.id.to_s | |
130 | + points = calc_points c, scope | |
131 | + puts "after recreating points the person has: #{person.reload.points(category: c.id.to_s)} and should have #{points}" | |
132 | + remaining_wrong_points << [person.identifier, person.name, scope.first.class.base_class.name, profile_name, c.id, c.point_type.name, scope.count*c.weight, person.points(category: c.id.to_s)] if points != person.points(category: c.id.to_s) | |
133 | + end | |
134 | + end | |
135 | + puts | |
136 | + end | |
137 | + puts "Updating #{person.identifier} level\n" | |
138 | + person.update_attribute(:level, person.gamification_plugin_calculate_level) | |
139 | + end | |
140 | + | |
141 | + # write to the spreadsheet the person points that couldn't regulate | |
142 | + unless remaining_wrong_points.blank? | |
143 | + CSV.open( "gamification_points_out_expectation.csv", 'w' ) do |csv| | |
144 | + csv << ['identifier', 'name', 'action', 'profile', 'category id', 'category type', 'should have', 'have'] | |
145 | + remaining_wrong_points.each do |line| | |
146 | + csv << line | |
147 | + end | |
148 | + end | |
149 | + end | |
150 | + | |
151 | + if remaining_wrong_points.count | |
152 | + puts "Finished. There was #{remaining_wrong_points.count} people/pontuation types with errors after check and fix. Please check the created spreadsheet." | |
153 | + else | |
154 | + puts "Finished. There was no errors after checking. \o/ Pontuation seems to be ok!" | |
155 | + end | |
156 | +end | ... | ... |