bring back story downvoting, remove low quality option
story hiding is still here, so hopefully this will result in less bogus story downvotes
This commit is contained in:
parent
48e5a0f130
commit
7f9c227ed0
|
@ -7,12 +7,18 @@
|
|||
var _Lobsters = Class.extend({
|
||||
curUser: null,
|
||||
|
||||
storyDownvoteReasons: { <%= Vote::STORY_REASONS.map{|k,v|
|
||||
"#{k.inspect}: #{v.inspect}" }.join(", ") %> },
|
||||
commentDownvoteReasons: { <%= Vote::COMMENT_REASONS.map{|k,v|
|
||||
"#{k.inspect}: #{v.inspect}" }.join(", ") %> },
|
||||
|
||||
upvoteStory: function(voterEl) {
|
||||
Lobsters.vote("story", voterEl, 1);
|
||||
},
|
||||
downvoteStory: function(voterEl) {
|
||||
Lobsters._showDownvoteWhyAt("story", voterEl, function(k) {
|
||||
Lobsters.vote("story", voterEl, -1, k); });
|
||||
},
|
||||
hideStory: function(hiderEl) {
|
||||
if (!Lobsters.curUser)
|
||||
return Lobsters.bounceToLogin();
|
||||
|
@ -37,10 +43,17 @@ var _Lobsters = Class.extend({
|
|||
Lobsters.vote("comment", voterEl, 1);
|
||||
},
|
||||
downvoteComment: function(voterEl) {
|
||||
Lobsters._showDownvoteWhyAt("comment", voterEl, function(k) {
|
||||
Lobsters.vote("comment", voterEl, -1, k); });
|
||||
},
|
||||
_showDownvoteWhyAt: function(thingType, voterEl, onChooseWhy) {
|
||||
if (!Lobsters.curUser)
|
||||
return Lobsters.bounceToLogin();
|
||||
|
||||
var li = $(voterEl).closest(".story, .comment");
|
||||
if (li.hasClass("downvoted")) {
|
||||
/* already upvoted, neutralize */
|
||||
Lobsters.vote("comment", voterEl, -1, null);
|
||||
Lobsters.vote(thingType, voterEl, -1, null);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -58,7 +71,13 @@ var _Lobsters = Class.extend({
|
|||
|
||||
var d = $("<div id=\"downvote_why\"></div>");
|
||||
|
||||
$.each(Lobsters.commentDownvoteReasons, function(k, v) {
|
||||
var reasons;
|
||||
if (thingType == "comment")
|
||||
reasons = Lobsters.commentDownvoteReasons;
|
||||
else
|
||||
reasons = Lobsters.storyDownvoteReasons;
|
||||
|
||||
$.each(reasons, function(k, v) {
|
||||
var a = $("<a href=\"#\"" + (k == "" ? " class=\"cancelreason\"" : "") +
|
||||
">" + v + "</a>");
|
||||
|
||||
|
@ -67,7 +86,7 @@ var _Lobsters = Class.extend({
|
|||
$("#downvote_why_shadow").remove();
|
||||
|
||||
if (k != "")
|
||||
Lobsters.vote("comment", voterEl, -1, k);
|
||||
onChooseWhy(k);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
@ -234,6 +253,10 @@ $(document).ready(function() {
|
|||
return false;
|
||||
});
|
||||
|
||||
$("li.story a.downvoter").click(function() {
|
||||
Lobsters.downvoteStory(this);
|
||||
return false;
|
||||
});
|
||||
$("li.story a.upvoter").click(function() {
|
||||
Lobsters.upvoteStory(this);
|
||||
return false;
|
||||
|
|
|
@ -368,6 +368,7 @@ ol.search_results li.story {
|
|||
|
||||
div.voters {
|
||||
float: left;
|
||||
margin-top: -4px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
|
@ -423,8 +424,8 @@ li.story {
|
|||
clear: both;
|
||||
}
|
||||
li.story div.story_liner {
|
||||
padding-top: 0.3em;
|
||||
padding-bottom: 0.3em;
|
||||
padding-top: 0.4em;
|
||||
padding-bottom: 0.4em;
|
||||
}
|
||||
.comment {
|
||||
clear: both;
|
||||
|
|
|
@ -58,8 +58,9 @@
|
|||
}
|
||||
|
||||
div.voters {
|
||||
width: 31px;
|
||||
margin-left: 0.25em;
|
||||
margin-top: 0px;
|
||||
width: 31px;
|
||||
}
|
||||
div.voters a.upvoter {
|
||||
margin-top: -5px;
|
||||
|
@ -133,7 +134,7 @@
|
|||
color: #333;
|
||||
display: block;
|
||||
font-size: 9pt;
|
||||
margin: -0.5em 0.5em 0 0.5em;
|
||||
margin: 0 0.5em;
|
||||
padding: 2px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class StoriesController < ApplicationController
|
||||
before_filter :require_logged_in_user_or_400,
|
||||
:only => [ :upvote, :unvote, :hide, :unhide, :preview ]
|
||||
:only => [ :upvote, :downvote, :unvote, :hide, :unhide, :preview ]
|
||||
|
||||
before_filter :require_logged_in_user, :only => [ :destroy, :create, :edit,
|
||||
:fetch_url_title, :new ]
|
||||
|
@ -201,6 +201,25 @@ class StoriesController < ApplicationController
|
|||
render :text => "ok"
|
||||
end
|
||||
|
||||
def downvote
|
||||
if !(story = find_story)
|
||||
return render :text => "can't find story", :status => 400
|
||||
end
|
||||
|
||||
if !Vote::STORY_REASONS[params[:reason]]
|
||||
return render :text => "invalid reason", :status => 400
|
||||
end
|
||||
|
||||
if !@user.can_downvote?(story)
|
||||
return render :text => "not permitted to downvote", :status => 400
|
||||
end
|
||||
|
||||
Vote.vote_thusly_on_story_or_comment_for_user_because(-1, story.id,
|
||||
nil, @user.id, params[:reason])
|
||||
|
||||
render :text => "ok"
|
||||
end
|
||||
|
||||
def hide
|
||||
if !(story = find_story)
|
||||
return render :text => "can't find story", :status => 400
|
||||
|
|
|
@ -10,6 +10,8 @@ class Story < ActiveRecord::Base
|
|||
validates_length_of :description, :maximum => (64 * 1024)
|
||||
validates_presence_of :user_id
|
||||
|
||||
DOWNVOTABLE_DAYS = 14
|
||||
|
||||
# after this many minutes old, a story cannot be edited
|
||||
MAX_EDIT_MINS = 30
|
||||
|
||||
|
@ -117,7 +119,8 @@ class Story < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def calculated_hotness
|
||||
order = Math.log([ score.abs, 1 ].max, 10)
|
||||
# don't immediately kill stories at 0 by bumping up score by one
|
||||
order = Math.log([ (score + 1).abs, 1 ].max, 10)
|
||||
if score > 0
|
||||
sign = 1
|
||||
elsif score < 0
|
||||
|
@ -230,6 +233,14 @@ class Story < ActiveRecord::Base
|
|||
:vote => 0).count
|
||||
end
|
||||
|
||||
def is_downvotable?
|
||||
if self.created_at
|
||||
Time.now - self.created_at <= DOWNVOTABLE_DAYS.days
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def is_editable_by_user?(user)
|
||||
if user && user.is_moderator?
|
||||
return true
|
||||
|
@ -401,4 +412,27 @@ class Story < ActiveRecord::Base
|
|||
def url_or_comments_url
|
||||
self.url.blank? ? self.comments_url : self.url
|
||||
end
|
||||
|
||||
def vote_summary_for(user)
|
||||
r_counts = {}
|
||||
r_whos = {}
|
||||
Vote.where(:story_id => self.id, :comment_id => nil).each do |v|
|
||||
r_counts[v.reason.to_s] ||= 0
|
||||
r_counts[v.reason.to_s] += v.vote
|
||||
if user && user.is_moderator?
|
||||
r_whos[v.reason.to_s] ||= []
|
||||
r_whos[v.reason.to_s].push v.user.username
|
||||
end
|
||||
end
|
||||
|
||||
r_counts.keys.sort.map{|k|
|
||||
if k == ""
|
||||
"+#{r_counts[k]}"
|
||||
else
|
||||
"#{r_counts[k]} " +
|
||||
(Vote::STORY_REASONS[k] || Vote::OLD_STORY_REASONS[k]) +
|
||||
(user && user.is_moderator?? " (#{r_whos[k].join(", ")})" : "")
|
||||
end
|
||||
}.join(", ")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -103,8 +103,12 @@ class User < ActiveRecord::Base
|
|||
if is_new?
|
||||
return false
|
||||
elsif obj.is_a?(Story)
|
||||
# user can unvote
|
||||
return obj.vote == -1
|
||||
if obj.is_downvotable?
|
||||
return true
|
||||
elsif obj.vote == -1
|
||||
# user can unvote
|
||||
return true
|
||||
end
|
||||
elsif obj.is_a?(Comment)
|
||||
if obj.is_downvotable?
|
||||
return true
|
||||
|
|
|
@ -11,6 +11,18 @@ class Vote < ActiveRecord::Base
|
|||
"" => "Cancel",
|
||||
}
|
||||
|
||||
STORY_REASONS = {
|
||||
"O" => "Off-topic",
|
||||
"A" => "Already Posted",
|
||||
"T" => "Poorly Tagged",
|
||||
"L" => "Poorly Titled",
|
||||
"S" => "Spam",
|
||||
"" => "Cancel",
|
||||
}
|
||||
OLD_STORY_REASONS = {
|
||||
"Q" => "Low Quality",
|
||||
}
|
||||
|
||||
def self.votes_by_user_for_stories_hash(user, stories)
|
||||
votes = {}
|
||||
|
||||
|
|
|
@ -10,6 +10,11 @@ class="story <%= story.vote == 1 ? "upvoted" : "" %> <%= story.vote == -1 ?
|
|||
<%= link_to "", login_url, :class => "upvoter" %>
|
||||
<% end %>
|
||||
<div class="score"><%= story.score %></div>
|
||||
<% if @user && @user.can_downvote?(story) %>
|
||||
<a class="downvoter"></a>
|
||||
<% else %>
|
||||
<span class="downvoter downvoter_stub"></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="details">
|
||||
<span class="link">
|
||||
|
@ -83,6 +88,12 @@ class="story <%= story.vote == 1 ? "upvoted" : "" %> <%= story.vote == -1 ?
|
|||
(story.comments_count == 1 ? "" : "s") %></a>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<% if defined?(single_story) && single_story %>
|
||||
<% if story.downvotes > 0 %>
|
||||
| <%= story.vote_summary_for(@user).downcase %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -42,6 +42,7 @@ Lobsters::Application.routes.draw do
|
|||
|
||||
resources :stories do
|
||||
post "upvote"
|
||||
post "downvote"
|
||||
post "unvote"
|
||||
post "undelete"
|
||||
post "hide"
|
||||
|
|
Loading…
Reference in a new issue