Merge pull request #1409 from riyad/update-votes
Update votes for issues and merge requests
This commit is contained in:
commit
40eec08c99
17 changed files with 256 additions and 66 deletions
|
@ -415,13 +415,48 @@ p.time {
|
|||
}
|
||||
}
|
||||
|
||||
.upvotes {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #468847;
|
||||
text-align: right;
|
||||
padding: 4px;
|
||||
margin: 2px;
|
||||
.votes {
|
||||
font-size: 13px;
|
||||
line-height: 15px;
|
||||
.progress {
|
||||
height: 4px;
|
||||
margin: 0;
|
||||
.bar {
|
||||
float: left;
|
||||
height: 100%;
|
||||
}
|
||||
.bar-success {
|
||||
background-color: #468847;
|
||||
@include bg-gradient(#62C462, #51A351);
|
||||
}
|
||||
.bar-danger {
|
||||
background-color: #B94A48;
|
||||
@include bg-gradient(#EE5F5B, #BD362F);
|
||||
}
|
||||
}
|
||||
.upvotes {
|
||||
display: inline-block;
|
||||
color: #468847;
|
||||
}
|
||||
.downvotes {
|
||||
display: inline-block;
|
||||
color: #B94A48;
|
||||
}
|
||||
}
|
||||
.votes-block {
|
||||
margin: 14px 6px 6px 0;
|
||||
.downvotes {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.votes-inline {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
.progress {
|
||||
display: inline-block;
|
||||
padding: 0 0 2px;
|
||||
width: 45px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix for readme code (stopped it from being yellow) */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Issue < ActiveRecord::Base
|
||||
include IssueCommonality
|
||||
include Upvote
|
||||
include Votes
|
||||
|
||||
acts_as_taggable_on :labels
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ require File.join(Rails.root, "app/models/commit")
|
|||
|
||||
class MergeRequest < ActiveRecord::Base
|
||||
include IssueCommonality
|
||||
include Upvote
|
||||
include Votes
|
||||
|
||||
BROKEN_DIFF = "--broken-diff"
|
||||
|
||||
|
|
|
@ -105,6 +105,12 @@ class Note < ActiveRecord::Base
|
|||
def upvote?
|
||||
note.start_with?('+1') || note.start_with?(':+1:')
|
||||
end
|
||||
|
||||
# Returns true if this is a downvote note,
|
||||
# otherwise false is returned
|
||||
def downvote?
|
||||
note.start_with?('-1') || note.start_with?(':-1:')
|
||||
end
|
||||
end
|
||||
# == Schema Information
|
||||
#
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
module Upvote
|
||||
# Return the number of +1 comments (upvotes)
|
||||
def upvotes
|
||||
notes.select(&:upvote?).size
|
||||
end
|
||||
end
|
32
app/roles/votes.rb
Normal file
32
app/roles/votes.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Votes
|
||||
# Return the number of +1 comments (upvotes)
|
||||
def upvotes
|
||||
notes.select(&:upvote?).size
|
||||
end
|
||||
|
||||
def upvotes_in_percent
|
||||
if votes_count.zero?
|
||||
0
|
||||
else
|
||||
100.0 / votes_count * upvotes
|
||||
end
|
||||
end
|
||||
|
||||
# Return the number of -1 comments (downvotes)
|
||||
def downvotes
|
||||
notes.select(&:downvote?).size
|
||||
end
|
||||
|
||||
def downvotes_in_percent
|
||||
if votes_count.zero?
|
||||
0
|
||||
else
|
||||
100.0 - upvotes_in_percent
|
||||
end
|
||||
end
|
||||
|
||||
# Return the total number of votes
|
||||
def votes_count
|
||||
upvotes + downvotes
|
||||
end
|
||||
end
|
|
@ -34,5 +34,5 @@
|
|||
- else
|
||||
|
||||
|
||||
- if issue.upvotes > 0
|
||||
%span.badge.badge-success= "+#{issue.upvotes}"
|
||||
- if issue.votes_count > 0
|
||||
= render 'votes/votes_inline', votable: issue
|
||||
|
|
|
@ -8,22 +8,22 @@
|
|||
%span.right
|
||||
- if can?(current_user, :admin_project, @project) || @issue.author == current_user
|
||||
- if @issue.closed
|
||||
= link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn small"
|
||||
= link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn grouped success"
|
||||
- else
|
||||
= link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn small", title: "Close Issue"
|
||||
= link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn grouped danger", title: "Close Issue"
|
||||
- if can?(current_user, :admin_project, @project) || @issue.author == current_user
|
||||
= link_to edit_project_issue_path(@project, @issue), class: "btn small" do
|
||||
= link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do
|
||||
%i.icon-edit
|
||||
Edit
|
||||
|
||||
%br
|
||||
- if @issue.upvotes > 0
|
||||
.upvotes#upvotes= "+#{pluralize @issue.upvotes, 'upvote'}"
|
||||
.right
|
||||
.span3#votes= render 'votes/votes_block', votable: @issue
|
||||
|
||||
.back_link
|
||||
= link_to project_issues_path(@project) do
|
||||
← To issues list
|
||||
|
||||
|
||||
.main_box
|
||||
.top_box_content
|
||||
%h4
|
||||
|
|
|
@ -23,5 +23,6 @@
|
|||
authored by #{merge_request.author_name}
|
||||
= time_ago_in_words(merge_request.created_at)
|
||||
ago
|
||||
- if merge_request.upvotes > 0
|
||||
%span.badge.badge-success= "+#{merge_request.upvotes}"
|
||||
|
||||
- if merge_request.votes_count > 0
|
||||
= render 'votes/votes_inline', votable: merge_request
|
||||
|
|
|
@ -23,10 +23,8 @@
|
|||
%i.icon-edit
|
||||
Edit
|
||||
|
||||
%br
|
||||
- if @merge_request.upvotes > 0
|
||||
.upvotes#upvotes= "+#{pluralize @merge_request.upvotes, 'upvote'}"
|
||||
|
||||
.right
|
||||
.span3#votes= render 'votes/votes_block', votable: @merge_request
|
||||
|
||||
.back_link
|
||||
= link_to project_merge_requests_path(@project) do
|
||||
|
|
6
app/views/votes/_votes_block.html.haml
Normal file
6
app/views/votes/_votes_block.html.haml
Normal file
|
@ -0,0 +1,6 @@
|
|||
.votes.votes-block
|
||||
.progress
|
||||
.bar.bar-success{style: "width: #{votable.upvotes_in_percent}%;"}
|
||||
.bar.bar-danger{style: "width: #{votable.downvotes_in_percent}%;"}
|
||||
.upvotes= "#{votable.upvotes} up"
|
||||
.downvotes= "#{votable.downvotes} down"
|
6
app/views/votes/_votes_inline.html.haml
Normal file
6
app/views/votes/_votes_inline.html.haml
Normal file
|
@ -0,0 +1,6 @@
|
|||
.votes.votes-inline
|
||||
.upvotes= votable.upvotes
|
||||
.progress
|
||||
.bar.bar-success{style: "width: #{votable.upvotes_in_percent}%;"}
|
||||
.bar.bar-danger{style: "width: #{votable.downvotes_in_percent}%;"}
|
||||
.downvotes= votable.downvotes
|
|
@ -12,7 +12,7 @@ describe Issue do
|
|||
|
||||
describe 'modules' do
|
||||
it { should include_module(IssueCommonality) }
|
||||
it { should include_module(Upvote) }
|
||||
it { should include_module(Votes) }
|
||||
end
|
||||
|
||||
subject { Factory.create(:issue) }
|
||||
|
|
|
@ -8,6 +8,6 @@ describe MergeRequest do
|
|||
|
||||
describe 'modules' do
|
||||
it { should include_module(IssueCommonality) }
|
||||
it { should include_module(Upvote) }
|
||||
it { should include_module(Votes) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,6 +24,13 @@ describe Note do
|
|||
it "recognizes a neutral note" do
|
||||
note = Factory(:note, note: "This is not a +1 note")
|
||||
note.should_not be_upvote
|
||||
note.should_not be_downvote
|
||||
end
|
||||
|
||||
it "recognizes a neutral emoji note" do
|
||||
note = build(:note, note: "I would :+1: this, but I don't want to")
|
||||
note.should_not be_upvote
|
||||
note.should_not be_downvote
|
||||
end
|
||||
|
||||
it "recognizes a +1 note" do
|
||||
|
@ -31,19 +38,19 @@ describe Note do
|
|||
note.should be_upvote
|
||||
end
|
||||
|
||||
it "recognizes a -1 note as no vote" do
|
||||
note = Factory(:note, note: "-1 for this")
|
||||
note.should_not be_upvote
|
||||
end
|
||||
|
||||
it "recognizes a +1 emoji as a vote" do
|
||||
note = build(:note, note: ":+1: for this")
|
||||
note.should be_upvote
|
||||
end
|
||||
|
||||
it "recognizes a neutral emoji note" do
|
||||
note = build(:note, note: "I would :+1: this, but I don't want to")
|
||||
note.should_not be_upvote
|
||||
it "recognizes a -1 note" do
|
||||
note = Factory(:note, note: "-1 for this")
|
||||
note.should be_downvote
|
||||
end
|
||||
|
||||
it "recognizes a -1 emoji as a vote" do
|
||||
note = build(:note, note: ":-1: for this")
|
||||
note.should be_downvote
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Issue, "Upvote" do
|
||||
let(:issue) { create(:issue) }
|
||||
|
||||
it "with no notes has a 0/0 score" do
|
||||
issue.upvotes.should == 0
|
||||
end
|
||||
|
||||
it "should recognize non-+1 notes" do
|
||||
issue.notes << create(:note, note: "No +1 here")
|
||||
issue.should have(1).note
|
||||
issue.notes.first.upvote?.should be_false
|
||||
issue.upvotes.should == 0
|
||||
end
|
||||
|
||||
it "should recognize a single +1 note" do
|
||||
issue.notes << create(:note, note: "+1 This is awesome")
|
||||
issue.upvotes.should == 1
|
||||
end
|
||||
|
||||
it "should recognize multiple +1 notes" do
|
||||
issue.notes << create(:note, note: "+1 This is awesome")
|
||||
issue.notes << create(:note, note: "+1 I want this")
|
||||
issue.upvotes.should == 2
|
||||
end
|
||||
end
|
132
spec/roles/votes_spec.rb
Normal file
132
spec/roles/votes_spec.rb
Normal file
|
@ -0,0 +1,132 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Issue do
|
||||
let(:issue) { create(:issue) }
|
||||
|
||||
describe "#upvotes" do
|
||||
it "with no notes has a 0/0 score" do
|
||||
issue.upvotes.should == 0
|
||||
end
|
||||
|
||||
it "should recognize non-+1 notes" do
|
||||
issue.notes << create(:note, note: "No +1 here")
|
||||
issue.should have(1).note
|
||||
issue.notes.first.upvote?.should be_false
|
||||
issue.upvotes.should == 0
|
||||
end
|
||||
|
||||
it "should recognize a single +1 note" do
|
||||
issue.notes << create(:note, note: "+1 This is awesome")
|
||||
issue.upvotes.should == 1
|
||||
end
|
||||
|
||||
it "should recognize multiple +1 notes" do
|
||||
issue.notes << create(:note, note: "+1 This is awesome")
|
||||
issue.notes << create(:note, note: "+1 I want this")
|
||||
issue.upvotes.should == 2
|
||||
end
|
||||
end
|
||||
|
||||
describe "#downvotes" do
|
||||
it "with no notes has a 0/0 score" do
|
||||
issue.downvotes.should == 0
|
||||
end
|
||||
|
||||
it "should recognize non--1 notes" do
|
||||
issue.notes << create(:note, note: "Almost got a -1")
|
||||
issue.should have(1).note
|
||||
issue.notes.first.downvote?.should be_false
|
||||
issue.downvotes.should == 0
|
||||
end
|
||||
|
||||
it "should recognize a single -1 note" do
|
||||
issue.notes << create(:note, note: "-1 This is bad")
|
||||
issue.downvotes.should == 1
|
||||
end
|
||||
|
||||
it "should recognize multiple -1 notes" do
|
||||
issue.notes << create(:note, note: "-1 This is bad")
|
||||
issue.notes << create(:note, note: "-1 Away with this")
|
||||
issue.downvotes.should == 2
|
||||
end
|
||||
end
|
||||
|
||||
describe "#votes_count" do
|
||||
it "with no notes has a 0/0 score" do
|
||||
issue.votes_count.should == 0
|
||||
end
|
||||
|
||||
it "should recognize non notes" do
|
||||
issue.notes << create(:note, note: "No +1 here")
|
||||
issue.should have(1).note
|
||||
issue.votes_count.should == 0
|
||||
end
|
||||
|
||||
it "should recognize a single +1 note" do
|
||||
issue.notes << create(:note, note: "+1 This is awesome")
|
||||
issue.votes_count.should == 1
|
||||
end
|
||||
|
||||
it "should recognize a single -1 note" do
|
||||
issue.notes << create(:note, note: "-1 This is bad")
|
||||
issue.votes_count.should == 1
|
||||
end
|
||||
|
||||
it "should recognize multiple notes" do
|
||||
issue.notes << create(:note, note: "+1 This is awesome")
|
||||
issue.notes << create(:note, note: "-1 This is bad")
|
||||
issue.notes << create(:note, note: "+1 I want this")
|
||||
issue.votes_count.should == 3
|
||||
end
|
||||
end
|
||||
|
||||
describe "#upvotes_in_percent" do
|
||||
it "with no notes has a 0% score" do
|
||||
issue.upvotes_in_percent.should == 0
|
||||
end
|
||||
|
||||
it "should count a single 1 note as 100%" do
|
||||
issue.notes << create(:note, note: "+1 This is awesome")
|
||||
issue.upvotes_in_percent.should == 100
|
||||
end
|
||||
|
||||
it "should count multiple +1 notes as 100%" do
|
||||
issue.notes << create(:note, note: "+1 This is awesome")
|
||||
issue.notes << create(:note, note: "+1 I want this")
|
||||
issue.upvotes_in_percent.should == 100
|
||||
end
|
||||
|
||||
it "should count fractions for multiple +1 and -1 notes correctly" do
|
||||
issue.notes << create(:note, note: "+1 This is awesome")
|
||||
issue.notes << create(:note, note: "+1 I want this")
|
||||
issue.notes << create(:note, note: "-1 This is bad")
|
||||
issue.notes << create(:note, note: "+1 me too")
|
||||
issue.upvotes_in_percent.should == 75
|
||||
end
|
||||
end
|
||||
|
||||
describe "#downvotes_in_percent" do
|
||||
it "with no notes has a 0% score" do
|
||||
issue.downvotes_in_percent.should == 0
|
||||
end
|
||||
|
||||
it "should count a single -1 note as 100%" do
|
||||
issue.notes << create(:note, note: "-1 This is bad")
|
||||
issue.downvotes_in_percent.should == 100
|
||||
end
|
||||
|
||||
it "should count multiple -1 notes as 100%" do
|
||||
issue.notes << create(:note, note: "-1 This is bad")
|
||||
issue.notes << create(:note, note: "-1 Away with this")
|
||||
issue.downvotes_in_percent.should == 100
|
||||
end
|
||||
|
||||
it "should count fractions for multiple +1 and -1 notes correctly" do
|
||||
issue.notes << create(:note, note: "+1 This is awesome")
|
||||
issue.notes << create(:note, note: "+1 I want this")
|
||||
issue.notes << create(:note, note: "-1 This is bad")
|
||||
issue.notes << create(:note, note: "+1 me too")
|
||||
issue.downvotes_in_percent.should == 25
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue