Commit ae067ee322e6702fb5ef0fd4f0cc4d4d5106cbde

Authored by Riyad Preukschas
1 parent 6c6f415c

Fix vote counting

app/helpers/notes_helper.rb
1 module NotesHelper 1 module NotesHelper
2 - def loading_more_notes?  
3 - params[:loading_more].present?  
4 - end  
5 -  
6 - def loading_new_notes?  
7 - params[:loading_new].present?  
8 - end  
9 -  
10 # Helps to distinguish e.g. commit notes in mr notes list 2 # Helps to distinguish e.g. commit notes in mr notes list
11 def note_for_main_target?(note) 3 def note_for_main_target?(note)
12 !@mixed_targets || (@target.class.name == note.noteable_type && !note.for_diff_line?) 4 !@mixed_targets || (@target.class.name == note.noteable_type && !note.for_diff_line?)
@@ -23,4 +15,12 @@ module NotesHelper @@ -23,4 +15,12 @@ module NotesHelper
23 link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable_id, anchor: note.line_code) 15 link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable_id, anchor: note.line_code)
24 end 16 end
25 end 17 end
  18 +
  19 + def loading_more_notes?
  20 + params[:loading_more].present?
  21 + end
  22 +
  23 + def loading_new_notes?
  24 + params[:loading_new].present?
  25 + end
26 end 26 end
app/models/note.rb
@@ -85,7 +85,9 @@ class Note < ActiveRecord::Base @@ -85,7 +85,9 @@ class Note < ActiveRecord::Base
85 # Returns true if this is a downvote note, 85 # Returns true if this is a downvote note,
86 # otherwise false is returned 86 # otherwise false is returned
87 def downvote? 87 def downvote?
88 - note.start_with?('-1') || note.start_with?(':-1:') 88 + votable? && (note.start_with?('-1') ||
  89 + note.start_with?(':-1:')
  90 + )
89 end 91 end
90 92
91 def for_commit? 93 def for_commit?
@@ -100,6 +102,10 @@ class Note < ActiveRecord::Base @@ -100,6 +102,10 @@ class Note < ActiveRecord::Base
100 line_code.present? 102 line_code.present?
101 end 103 end
102 104
  105 + def for_issue?
  106 + noteable_type == "Issue"
  107 + end
  108 +
103 def for_merge_request? 109 def for_merge_request?
104 noteable_type == "MergeRequest" 110 noteable_type == "MergeRequest"
105 end 111 end
@@ -150,6 +156,12 @@ class Note < ActiveRecord::Base @@ -150,6 +156,12 @@ class Note < ActiveRecord::Base
150 # Returns true if this is an upvote note, 156 # Returns true if this is an upvote note,
151 # otherwise false is returned 157 # otherwise false is returned
152 def upvote? 158 def upvote?
153 - note.start_with?('+1') || note.start_with?(':+1:') 159 + votable? && (note.start_with?('+1') ||
  160 + note.start_with?(':+1:')
  161 + )
  162 + end
  163 +
  164 + def votable?
  165 + for_issue? || (for_merge_request? && !for_diff_line?)
154 end 166 end
155 end 167 end
app/roles/votes.rb
1 module Votes 1 module Votes
2 - # Return the number of +1 comments (upvotes)  
3 - def upvotes  
4 - notes.select(&:upvote?).size 2 +
  3 + # Return the number of -1 comments (downvotes)
  4 + def downvotes
  5 + notes.select(&:downvote?).size
5 end 6 end
6 7
7 - def upvotes_in_percent 8 + def downvotes_in_percent
8 if votes_count.zero? 9 if votes_count.zero?
9 0 10 0
10 else 11 else
11 - 100.0 / votes_count * upvotes 12 + 100.0 - upvotes_in_percent
12 end 13 end
13 end 14 end
14 15
15 - # Return the number of -1 comments (downvotes)  
16 - def downvotes  
17 - notes.select(&:downvote?).size 16 + # Return the number of +1 comments (upvotes)
  17 + def upvotes
  18 + notes.select(&:upvote?).size
18 end 19 end
19 20
20 - def downvotes_in_percent 21 + def upvotes_in_percent
21 if votes_count.zero? 22 if votes_count.zero?
22 0 23 0
23 else 24 else
24 - 100.0 - upvotes_in_percent 25 + 100.0 / votes_count * upvotes
25 end 26 end
26 end 27 end
27 28
app/views/notes/_note.html.haml
@@ -14,16 +14,14 @@ @@ -14,16 +14,14 @@
14 = time_ago_in_words(note.updated_at) 14 = time_ago_in_words(note.updated_at)
15 ago 15 ago
16 16
17 - -# only show vote if it's a note for the main target  
18 - - if note_for_main_target?(note)  
19 - - if note.upvote?  
20 - %span.vote.upvote.label.label-success  
21 - %i.icon-thumbs-up  
22 - \+1  
23 - - if note.downvote?  
24 - %span.vote.downvote.label.label-error  
25 - %i.icon-thumbs-down  
26 - \-1 17 + - if note.upvote?
  18 + %span.vote.upvote.label.label-success
  19 + %i.icon-thumbs-up
  20 + \+1
  21 + - if note.downvote?
  22 + %span.vote.downvote.label.label-error
  23 + %i.icon-thumbs-down
  24 + \-1
27 25
28 26
29 .note-body 27 .note-body
spec/factories.rb
@@ -91,6 +91,32 @@ FactoryGirl.define do @@ -91,6 +91,32 @@ FactoryGirl.define do
91 factory :note do 91 factory :note do
92 project 92 project
93 note "Note" 93 note "Note"
  94 + author
  95 +
  96 + factory :note_on_commit, traits: [:on_commit]
  97 + factory :note_on_commit_line, traits: [:on_commit, :on_line]
  98 + factory :note_on_issue, traits: [:on_issue], aliases: [:votable_note]
  99 + factory :note_on_merge_request, traits: [:on_merge_request]
  100 + factory :note_on_merge_request_line, traits: [:on_merge_request, :on_line]
  101 +
  102 + trait :on_commit do
  103 + noteable_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
  104 + noteable_type "Commit"
  105 + end
  106 +
  107 + trait :on_line do
  108 + line_code "0_184_184"
  109 + end
  110 +
  111 + trait :on_merge_request do
  112 + noteable_id 1
  113 + noteable_type "MergeRequest"
  114 + end
  115 +
  116 + trait :on_issue do
  117 + noteable_id 1
  118 + noteable_type "Issue"
  119 + end
94 end 120 end
95 121
96 factory :event do 122 factory :event do
spec/models/note_spec.rb
@@ -43,79 +43,105 @@ describe Note do @@ -43,79 +43,105 @@ describe Note do
43 let(:project) { create(:project) } 43 let(:project) { create(:project) }
44 44
45 it "recognizes a neutral note" do 45 it "recognizes a neutral note" do
46 - note = create(:note, note: "This is not a +1 note") 46 + note = create(:votable_note, note: "This is not a +1 note")
47 note.should_not be_upvote 47 note.should_not be_upvote
48 note.should_not be_downvote 48 note.should_not be_downvote
49 end 49 end
50 50
51 it "recognizes a neutral emoji note" do 51 it "recognizes a neutral emoji note" do
52 - note = build(:note, note: "I would :+1: this, but I don't want to") 52 + note = build(:votable_note, note: "I would :+1: this, but I don't want to")
53 note.should_not be_upvote 53 note.should_not be_upvote
54 note.should_not be_downvote 54 note.should_not be_downvote
55 end 55 end
56 56
57 it "recognizes a +1 note" do 57 it "recognizes a +1 note" do
58 - note = create(:note, note: "+1 for this") 58 + note = create(:votable_note, note: "+1 for this")
59 note.should be_upvote 59 note.should be_upvote
60 end 60 end
61 61
62 it "recognizes a +1 emoji as a vote" do 62 it "recognizes a +1 emoji as a vote" do
63 - note = build(:note, note: ":+1: for this") 63 + note = build(:votable_note, note: ":+1: for this")
64 note.should be_upvote 64 note.should be_upvote
65 end 65 end
66 66
67 it "recognizes a -1 note" do 67 it "recognizes a -1 note" do
68 - note = create(:note, note: "-1 for this") 68 + note = create(:votable_note, note: "-1 for this")
69 note.should be_downvote 69 note.should be_downvote
70 end 70 end
71 71
72 it "recognizes a -1 emoji as a vote" do 72 it "recognizes a -1 emoji as a vote" do
73 - note = build(:note, note: ":-1: for this") 73 + note = build(:votable_note, note: ":-1: for this")
74 note.should be_downvote 74 note.should be_downvote
75 end 75 end
76 end 76 end
77 77
78 - let(:project) { create(:project) }  
79 - let(:commit) { project.commit }  
80 -  
81 describe "Commit notes" do 78 describe "Commit notes" do
82 - before do  
83 - @note = create(:note,  
84 - noteable_id: commit.id,  
85 - noteable_type: "Commit")  
86 - end 79 + let!(:note) { create(:note_on_commit, note: "+1 from me") }
  80 + let!(:commit) { note.noteable }
87 81
88 it "should be accessible through #noteable" do 82 it "should be accessible through #noteable" do
89 - @note.noteable_id.should == commit.id  
90 - @note.noteable.should be_a(Commit)  
91 - @note.noteable.should == commit 83 + note.noteable_id.should == commit.id
  84 + note.noteable.should be_a(Commit)
  85 + note.noteable.should == commit
92 end 86 end
93 87
94 it "should save a valid note" do 88 it "should save a valid note" do
95 - @note.noteable_id.should == commit.id  
96 - @note.noteable == commit 89 + note.noteable_id.should == commit.id
  90 + note.noteable == commit
97 end 91 end
98 92
99 it "should be recognized by #for_commit?" do 93 it "should be recognized by #for_commit?" do
100 - @note.should be_for_commit 94 + note.should be_for_commit
101 end 95 end
102 - end  
103 96
104 - describe "Pre-line commit notes" do  
105 - before do  
106 - @note = create(:note,  
107 - noteable_id: commit.id,  
108 - noteable_type: "Commit",  
109 - line_code: "0_16_1") 97 + it "should not be votable" do
  98 + note.should_not be_votable
110 end 99 end
  100 + end
  101 +
  102 + describe "Commit diff line notes" do
  103 + let!(:note) { create(:note_on_commit_line, note: "+1 from me") }
  104 + let!(:commit) { note.noteable }
111 105
112 it "should save a valid note" do 106 it "should save a valid note" do
113 - @note.noteable_id.should == commit.id  
114 - @note.noteable.id.should == commit.id 107 + note.noteable_id.should == commit.id
  108 + note.noteable.id.should == commit.id
115 end 109 end
116 110
117 it "should be recognized by #for_diff_line?" do 111 it "should be recognized by #for_diff_line?" do
118 - @note.should be_for_diff_line 112 + note.should be_for_diff_line
  113 + end
  114 +
  115 + it "should be recognized by #for_commit_diff_line?" do
  116 + note.should be_for_commit_diff_line
  117 + end
  118 +
  119 + it "should not be votable" do
  120 + note.should_not be_votable
  121 + end
  122 + end
  123 +
  124 + describe "Issue notes" do
  125 + let!(:note) { create(:note_on_issue, note: "+1 from me") }
  126 +
  127 + it "should not be votable" do
  128 + note.should be_votable
  129 + end
  130 + end
  131 +
  132 + describe "Merge request notes" do
  133 + let!(:note) { create(:note_on_merge_request, note: "+1 from me") }
  134 +
  135 + it "should not be votable" do
  136 + note.should be_votable
  137 + end
  138 + end
  139 +
  140 + describe "Merge request diff line notes" do
  141 + let!(:note) { create(:note_on_merge_request_line, note: "+1 from me") }
  142 +
  143 + it "should not be votable" do
  144 + note.should_not be_votable
119 end 145 end
120 end 146 end
121 147
spec/roles/votes_spec.rb
1 require 'spec_helper' 1 require 'spec_helper'
2 2
3 describe Issue do 3 describe Issue do
4 - let(:issue) { create(:issue) } 4 + it { should include_module(Votes) }
  5 +end
  6 +
  7 +describe MergeRequest do
  8 + let(:merge_request) { FactoryGirl.create(:merge_request_with_diffs) }
  9 +
  10 + it { should include_module(Votes) }
5 11
6 describe "#upvotes" do 12 describe "#upvotes" do
7 it "with no notes has a 0/0 score" do 13 it "with no notes has a 0/0 score" do
8 - issue.upvotes.should == 0 14 + merge_request.upvotes.should == 0
9 end 15 end
10 16
11 it "should recognize non-+1 notes" do 17 it "should recognize non-+1 notes" do
12 - issue.notes << create(:note, note: "No +1 here")  
13 - issue.should have(1).note  
14 - issue.notes.first.upvote?.should be_false  
15 - issue.upvotes.should == 0 18 + merge_request.notes << create(:note, note: "No +1 here")
  19 + merge_request.should have(1).note
  20 + merge_request.notes.first.upvote?.should be_false
  21 + merge_request.upvotes.should == 0
16 end 22 end
17 23
18 it "should recognize a single +1 note" do 24 it "should recognize a single +1 note" do
19 - issue.notes << create(:note, note: "+1 This is awesome")  
20 - issue.upvotes.should == 1 25 + merge_request.notes << create(:note, note: "+1 This is awesome")
  26 + merge_request.upvotes.should == 1
21 end 27 end
22 28
23 it "should recognize multiple +1 notes" do 29 it "should recognize multiple +1 notes" do
24 - issue.notes << create(:note, note: "+1 This is awesome")  
25 - issue.notes << create(:note, note: "+1 I want this")  
26 - issue.upvotes.should == 2 30 + merge_request.notes << create(:note, note: "+1 This is awesome")
  31 + merge_request.notes << create(:note, note: "+1 I want this")
  32 + merge_request.upvotes.should == 2
27 end 33 end
28 end 34 end
29 35
30 describe "#downvotes" do 36 describe "#downvotes" do
31 it "with no notes has a 0/0 score" do 37 it "with no notes has a 0/0 score" do
32 - issue.downvotes.should == 0 38 + merge_request.downvotes.should == 0
33 end 39 end
34 40
35 it "should recognize non--1 notes" do 41 it "should recognize non--1 notes" do
36 - issue.notes << create(:note, note: "Almost got a -1")  
37 - issue.should have(1).note  
38 - issue.notes.first.downvote?.should be_false  
39 - issue.downvotes.should == 0 42 + merge_request.notes << create(:note, note: "Almost got a -1")
  43 + merge_request.should have(1).note
  44 + merge_request.notes.first.downvote?.should be_false
  45 + merge_request.downvotes.should == 0
40 end 46 end
41 47
42 it "should recognize a single -1 note" do 48 it "should recognize a single -1 note" do
43 - issue.notes << create(:note, note: "-1 This is bad")  
44 - issue.downvotes.should == 1 49 + merge_request.notes << create(:note, note: "-1 This is bad")
  50 + merge_request.downvotes.should == 1
45 end 51 end
46 52
47 it "should recognize multiple -1 notes" do 53 it "should recognize multiple -1 notes" do
48 - issue.notes << create(:note, note: "-1 This is bad")  
49 - issue.notes << create(:note, note: "-1 Away with this")  
50 - issue.downvotes.should == 2 54 + merge_request.notes << create(:note, note: "-1 This is bad")
  55 + merge_request.notes << create(:note, note: "-1 Away with this")
  56 + merge_request.downvotes.should == 2
51 end 57 end
52 end 58 end
53 59
54 describe "#votes_count" do 60 describe "#votes_count" do
55 it "with no notes has a 0/0 score" do 61 it "with no notes has a 0/0 score" do
56 - issue.votes_count.should == 0 62 + merge_request.votes_count.should == 0
57 end 63 end
58 64
59 it "should recognize non notes" do 65 it "should recognize non notes" do
60 - issue.notes << create(:note, note: "No +1 here")  
61 - issue.should have(1).note  
62 - issue.votes_count.should == 0 66 + merge_request.notes << create(:note, note: "No +1 here")
  67 + merge_request.should have(1).note
  68 + merge_request.votes_count.should == 0
63 end 69 end
64 70
65 it "should recognize a single +1 note" do 71 it "should recognize a single +1 note" do
66 - issue.notes << create(:note, note: "+1 This is awesome")  
67 - issue.votes_count.should == 1 72 + merge_request.notes << create(:note, note: "+1 This is awesome")
  73 + merge_request.votes_count.should == 1
68 end 74 end
69 75
70 it "should recognize a single -1 note" do 76 it "should recognize a single -1 note" do
71 - issue.notes << create(:note, note: "-1 This is bad")  
72 - issue.votes_count.should == 1 77 + merge_request.notes << create(:note, note: "-1 This is bad")
  78 + merge_request.votes_count.should == 1
73 end 79 end
74 80
75 it "should recognize multiple notes" do 81 it "should recognize multiple notes" do
76 - issue.notes << create(:note, note: "+1 This is awesome")  
77 - issue.notes << create(:note, note: "-1 This is bad")  
78 - issue.notes << create(:note, note: "+1 I want this")  
79 - issue.votes_count.should == 3 82 + merge_request.notes << create(:note, note: "+1 This is awesome")
  83 + merge_request.notes << create(:note, note: "-1 This is bad")
  84 + merge_request.notes << create(:note, note: "+1 I want this")
  85 + merge_request.votes_count.should == 3
80 end 86 end
81 end 87 end
82 88
83 describe "#upvotes_in_percent" do 89 describe "#upvotes_in_percent" do
84 it "with no notes has a 0% score" do 90 it "with no notes has a 0% score" do
85 - issue.upvotes_in_percent.should == 0 91 + merge_request.upvotes_in_percent.should == 0
86 end 92 end
87 93
88 it "should count a single 1 note as 100%" do 94 it "should count a single 1 note as 100%" do
89 - issue.notes << create(:note, note: "+1 This is awesome")  
90 - issue.upvotes_in_percent.should == 100 95 + merge_request.notes << create(:note, note: "+1 This is awesome")
  96 + merge_request.upvotes_in_percent.should == 100
91 end 97 end
92 98
93 it "should count multiple +1 notes as 100%" do 99 it "should count multiple +1 notes as 100%" do
94 - issue.notes << create(:note, note: "+1 This is awesome")  
95 - issue.notes << create(:note, note: "+1 I want this")  
96 - issue.upvotes_in_percent.should == 100 100 + merge_request.notes << create(:note, note: "+1 This is awesome")
  101 + merge_request.notes << create(:note, note: "+1 I want this")
  102 + merge_request.upvotes_in_percent.should == 100
97 end 103 end
98 104
99 it "should count fractions for multiple +1 and -1 notes correctly" do 105 it "should count fractions for multiple +1 and -1 notes correctly" do
100 - issue.notes << create(:note, note: "+1 This is awesome")  
101 - issue.notes << create(:note, note: "+1 I want this")  
102 - issue.notes << create(:note, note: "-1 This is bad")  
103 - issue.notes << create(:note, note: "+1 me too")  
104 - issue.upvotes_in_percent.should == 75 106 + merge_request.notes << create(:note, note: "+1 This is awesome")
  107 + merge_request.notes << create(:note, note: "+1 I want this")
  108 + merge_request.notes << create(:note, note: "-1 This is bad")
  109 + merge_request.notes << create(:note, note: "+1 me too")
  110 + merge_request.upvotes_in_percent.should == 75
105 end 111 end
106 end 112 end
107 113
108 describe "#downvotes_in_percent" do 114 describe "#downvotes_in_percent" do
109 it "with no notes has a 0% score" do 115 it "with no notes has a 0% score" do
110 - issue.downvotes_in_percent.should == 0 116 + merge_request.downvotes_in_percent.should == 0
111 end 117 end
112 118
113 it "should count a single -1 note as 100%" do 119 it "should count a single -1 note as 100%" do
114 - issue.notes << create(:note, note: "-1 This is bad")  
115 - issue.downvotes_in_percent.should == 100 120 + merge_request.notes << create(:note, note: "-1 This is bad")
  121 + merge_request.downvotes_in_percent.should == 100
116 end 122 end
117 123
118 it "should count multiple -1 notes as 100%" do 124 it "should count multiple -1 notes as 100%" do
119 - issue.notes << create(:note, note: "-1 This is bad")  
120 - issue.notes << create(:note, note: "-1 Away with this")  
121 - issue.downvotes_in_percent.should == 100 125 + merge_request.notes << create(:note, note: "-1 This is bad")
  126 + merge_request.notes << create(:note, note: "-1 Away with this")
  127 + merge_request.downvotes_in_percent.should == 100
122 end 128 end
123 129
124 it "should count fractions for multiple +1 and -1 notes correctly" do 130 it "should count fractions for multiple +1 and -1 notes correctly" do
125 - issue.notes << create(:note, note: "+1 This is awesome")  
126 - issue.notes << create(:note, note: "+1 I want this")  
127 - issue.notes << create(:note, note: "-1 This is bad")  
128 - issue.notes << create(:note, note: "+1 me too")  
129 - issue.downvotes_in_percent.should == 25 131 + merge_request.notes << create(:note, note: "+1 This is awesome")
  132 + merge_request.notes << create(:note, note: "+1 I want this")
  133 + merge_request.notes << create(:note, note: "-1 This is bad")
  134 + merge_request.notes << create(:note, note: "+1 me too")
  135 + merge_request.downvotes_in_percent.should == 25
130 end 136 end
131 end 137 end
132 end 138 end