Skip to content

Commit

Permalink
Implemented permission view voters
Browse files Browse the repository at this point in the history
  • Loading branch information
Ole Jungclaussen committed Feb 8, 2017
1 parent 05e5e7c commit 7578cdf
Show file tree
Hide file tree
Showing 13 changed files with 235 additions and 11 deletions.
18 changes: 10 additions & 8 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

A plugin for redmine which allows users to up- or down-vote issues.

Current version: 1.0.2

Developed on Redmine 3.3.2

== Usage

* Install plugin
Expand All @@ -10,15 +14,13 @@ A plugin for redmine which allows users to up- or down-vote issues.

* Enable permissions for roles (minimum requirement is
always the user being logged in)
* Vote on issue
* View votes

Users with voting permission can now up- or down-vote on issues, change their
votes, or withdraw them again. They can see their own vote.

Users with viewing permission can see the total number of votes.


* "Vote on issue": Up- or down-vote on issues; change own votes or withdraw
them. See own votes.

* "View votes": See the total number of votes on an issue.

* "View voters": See who voted how on an issue.

There are Up- and down-votes columns available for the issue listing.

Expand Down
7 changes: 7 additions & 0 deletions app/controllers/vote_on_issues_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,11 @@ def cast_vote

# Auto loads /app/views/vote_on_issues/cast_vote.js.erb
end

def show_voters
@issue = Issue.find(params[:issue_id])
@UpVotes = VoteOnIssue.getListOfUpVotersOnIssue(params[:issue_id])
@DnVotes = VoteOnIssue.getListOfDnVotersOnIssue(params[:issue_id])
# Auto loads /app/views/vote_on_issues/show_voters.js.erb
end
end
17 changes: 17 additions & 0 deletions app/models/vote_on_issue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,22 @@ def self.getUpVoteCountOnIssue(issue_id)
def self.getDnVoteCountOnIssue(issue_id)
where("issue_id = ? AND vote_val < 0", issue_id).count
end

def self.getListOfUpVotersOnIssue(issue_id)
# this does load the users, but costly: One query for each user
# where("issue_id = ? AND vote_val > 0", issue_id)
# this does load the users, less costly: One query for all users
# includes(:user).where("issue_id = ? AND vote_val > 0", issue_id)
# where("issue_id = ? AND vote_val > 0", issue_id).includes(:user)
# joins users successfully, but still execs one query for each user
# where("issue_id = ? AND vote_val > 0", issue_id).joins(:user)
# This does what I want, but I'd love to find out how to do this in rails...
find_by_sql( ["SELECT `vote_on_issues`.`vote_val` AS vote_val, `users`.`login` AS user_login FROM `vote_on_issues` LEFT JOIN `users` ON (`users`.`id` = `vote_on_issues`.`user_id`) WHERE (`issue_id` = ? AND `vote_val` > 0) ORDER BY user_login ASC", issue_id] )
end

def self.getListOfDnVotersOnIssue(issue_id)
# see getListOfUpVotersOnIssue
find_by_sql( ["SELECT `vote_on_issues`.`vote_val` AS vote_val, `users`.`login` AS user_login FROM `vote_on_issues` LEFT JOIN `users` ON (`users`.`id` = `vote_on_issues`.`user_id`) WHERE (`issue_id` = ? AND `vote_val` < 0) ORDER BY user_login ASC", issue_id] )
end

end
21 changes: 21 additions & 0 deletions app/views/view_issues/_show_details_bottom.erb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,29 @@
<span id="vote_on_issues_nVotesDn"></span><%= image_tag 'arrow-d-r-red.png', :class => 'vote_on_issues-icon-votes', :plugin => 'vote_on_issues' %>
</div>

<% if authorize_for('issues', 'view_voters') %>
<div class="vote_on_issues-issue-votes-nowrap">
<%= link_to(l(:view_issues_label_voters), {:controller => 'vote_on_issues', :action => 'show_voters', :issue_id => @issue }, remote: true, :id => "vote_on_issues-link-voters", :class => 'vote_on_issues-link-voters', :title => l(:view_issues_show_voters) ) %>
</div>

<div id="vote_on_issues-issue-voters" style="display:none;">
<div>
<table><tbody><tr>
<td><%= l(:view_issues_issue_voters) %></td>
<td onClick="vote_on_issues.hideListOfVoters()"><%= image_tag('delete-white.png', :plugin => 'vote_on_issues') %></td>
</tr></tbody></table>
</div>
<div>
<table><tbody id="vote_on_issues-issue-voters-list">
</tbody></table>
</div>
</div>
<% end %>

<script>
vote_on_issues.showVotesOnIssue(<%= VoteOnIssue.getUpVoteCountOnIssue(@issue.id) %>, <%= VoteOnIssue.getDnVoteCountOnIssue(@issue.id) %>);
vote_on_issues.sImgUp = '<%= image_tag('arrow-u-r-green.png', :plugin => 'vote_on_issues') %>';
vote_on_issues.sImgDn = '<%= image_tag('arrow-d-r-red.png', :plugin => 'vote_on_issues') %>';
</script>
</div>
</div>
Expand Down
5 changes: 5 additions & 0 deletions app/views/vote_on_issues/cast_vote.js.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<% if User.current.allowed_to?(:view_votes, nil, :global => true) %>
vote_on_issues.showVotesOnIssue(<%= @nVotesUp %>, <%= @nVotesDn %>);
<% end %>

<% if User.current.allowed_to?(:view_voters, nil, :global => true) %>
vote_on_issues.hideListOfVoters();
<% end %>

vote_on_issues.showMyVote(<%= @iMyVote %>);
12 changes: 12 additions & 0 deletions app/views/vote_on_issues/show_voters.js.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

vote_on_issues.clearListOfVoters();

<% @UpVotes.each do |vote| %>
vote_on_issues.addToListOfVoters(<%= vote['vote_val'] %>, "<%= vote['user_login'] %>");
<% end %>

<% @DnVotes.each do |vote| %>
vote_on_issues.addToListOfVoters(<%= vote['vote_val'] %>, "<%= vote['user_login'] %>");
<% end %>

vote_on_issues.showListOfVoters();
Binary file added assets/images/delete-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions assets/javascripts/view_issues_vote.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,66 @@
**/
var vote_on_issues = {
version : '1.0.0'
,sImgUp : ''
,sImgDn : ''

// ALL VOTES
, showVotesOnIssue: function(nVotesUp, nVotesDn){
$('#vote_on_issues_nVotesUp').html(nVotesUp);
$('#vote_on_issues_nVotesDn').html(nVotesDn);
}

// LIST OF VOTERS
, isListOfVotersOpen : function() {
return('none' != $('#vote_on_issues-issue-voters').css('display'));
}
, clearListOfVoters : function() {
var ListTbody = $('#vote_on_issues-issue-voters-list');
ListTbody.html('');
}
, addToListOfVoters : function(vote_val, sVoter) {
$('#vote_on_issues-issue-voters-list').append(
'<tr><td>'
+(vote_val > 0 ? this.sImgUp : this.sImgDn)
+'</td><td><span data-vote-val="'+vote_val+'">'
+sVoter
+'</span></td></tr>'
);
}
, showListOfVoters : function() {
var ListBox = $('#vote_on_issues-issue-voters');
var Anchor = $('#vote_on_issues-link-voters');

ListBox.css({
top: Anchor.position().top,
left: Anchor.position().left
});

if('none' == ListBox.css('display')){
var that = this;
$(document).on('click.vote_on_issues-ListBox', function() {
$(document).off('click.vote_on_issues-ListBox');
that.hideListOfVoters();
});
ListBox.on('click.vote_on_issues-ListBox', function(e) {
e.stopPropagation(); // This is the preferred method.
return false; // This should not be used unless you do not want
// any click events registering inside the div
});
ListBox.show();
}
}
, hideListOfVoters : function() {
var ListBox = $('#vote_on_issues-issue-voters');
if('none' != ListBox.css('display')){
$(document).off('click.vote_on_issues-ListBox');
ListBox.off('click.vote_on_issues-ListBox');
ListBox.hide();
}
this.clearListOfVoters();
}

// MY VOTE
, showMyVote : function(iUserVote){

$('#vote_on_issues_MyVoteNil').hide();
Expand Down
96 changes: 96 additions & 0 deletions assets/stylesheets/view_issues_vote.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,103 @@
/**
**
** general
**
**/
div.vote_on_issues-issue-votes-nowrap {
white-space:nowrap;
float: left;
}

/**
**
** LIST OF VOTERS
**
**/
/* LINK/BUTTON */
.vote_on_issues-link-voters {
cursor:pointer;
}
/* BOX (BASIC DEVISION: TITLE, LIST) */
#vote_on_issues-issue-voters {
position: absolute;
top: 1em;
left: 1em;
width: 25em;
max-width: 50%;

border: 2px solid #CCC;
border-radius: 5px;

background-color: #FFF;

overflow: hidden;

box-shadow: 0.5em 0.5em 0.3em rgba(0,0,0,0.5);
}
#vote_on_issues-issue-voters > div:nth-child(1) {
background-color: #628DB6;
color:#FFF;
}
#vote_on_issues-issue-voters > div:nth-child(2) {
border-radius: 0 0 5px 5px;
padding:0.2em;

min-height: 10vh;
max-height: 40vh;

overflow: auto;
}
/* TITLE BAR */
#vote_on_issues-issue-voters > div:nth-child(1) > table {
width:100%;
border-collapse:collapse;
}
#vote_on_issues-issue-voters > div:nth-child(1) > table td:nth-child(1) {
padding:0.2em;
padding-left:0.3em;
text-align:left;
}
#vote_on_issues-issue-voters > div:nth-child(1) > table td:nth-child(2) {
text-align:right;
cursor:pointer;
}
#vote_on_issues-issue-voters > div:nth-child(1) > table img {
margin-right:0.3em;
width:0.7em;
height:0.7em;
}
/* LIST TABLE */
#vote_on_issues-issue-voters > div:nth-child(2) > table {
width:100%;
border-collapse:collapse;
}
#vote_on_issues-issue-voters-list tr {
border-bottom:1px solid #CCC;
}
#vote_on_issues-issue-voters-list tr:last-child {
border-bottom:none;
}
#vote_on_issues-issue-voters-list td {

}
#vote_on_issues-issue-voters-list td:nth-child(1) {
width:16px;
}
#vote_on_issues-issue-voters-list img {
width:0.8em;
height:0.8em;
}
#vote_on_issues-issue-voters-list span[data-vote-val="1"] {
color:#080;
}
#vote_on_issues-issue-voters-list span[data-vote-val="-1"] {
color:#800;
}
/**
**
** MY VOTE
**
**/
span.vote_on_issues-my-vote-opt {
clear:left;
}
Expand Down
2 changes: 2 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
1.0.2: Added permission 'view voters'
==
1.0.1: Added permission 'view votes'
==
1.0.0: Initial version
5 changes: 5 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ en:
permission_view_voter: "View voters"

view_issues_label_votes: "Votes"

view_issues_label_voters: "Voters"
view_issues_show_voters: "Show voters"
view_issues_issue_voters: "List of Voters"

view_issues_my_vote: "My vote"
view_issues_my_vote_opt: "Change"

Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Plugin's routes
# See: http://guides.rubyonrails.org/routing.html
get 'vote_on_issues/cast_vote', :to => 'vote_on_issues#cast_vote'
get 'vote_on_issues/show_voters', :to => 'vote_on_issues#show_voters'
get 'vote_on_issues', :to => 'vote_on_issues#index'
6 changes: 3 additions & 3 deletions init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@
Redmine::Plugin.register :vote_on_issues do
name 'Vote On Issues'
description 'This plugin allows to up- and down-vote issues.'
version '1.0.1'
version '1.0.2'
url 'https://github.com/ojde/redmine-vote_on_issues-plugin'
author 'Ole Jungclaussen'
author_url 'https://jungclaussen.com'

requires_redmine :version_or_higher => '3.2.0'
requires_redmine :version_or_higher => '3.3.2'

project_module :vote_on_issues do
permission :cast_votes, {:issues => :cast_vote }, :require => :loggedin
permission :view_votes, {:issues => :view_votes}, :require => :loggedin
# permission :view_voter, {:issues => :view_voter}, :require => :loggedin
permission :view_voters, {:issues => :view_voters}, :require => :loggedin
end

# permission for menu
Expand Down

0 comments on commit 7578cdf

Please sign in to comment.