From 67fc2cc75c3df047d2d04e210058341dcdc73dc0 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Mon, 17 Feb 2014 10:13:08 -0600 Subject: [PATCH] set maximum time during which comments and stories can be downvoted always allow a user to "unvote" if they're previously downvoted, but after a certain number of days, don't accept new downvotes there isn't really any benefit in downvoting old stuff that is already off the front pages or on a dead comment thread, other than to maliciously strip karma for particular users --- app/controllers/comments_controller.rb | 10 ++++++++-- app/controllers/stories_controller.rb | 10 ++++++++-- app/models/comment.rb | 11 +++++++++++ app/models/story.rb | 12 +++++++++++- app/models/user.rb | 23 ++++++++++++++++++++--- app/views/comments/_comment.html.erb | 2 +- app/views/stories/_listdetail.html.erb | 2 +- 7 files changed, 60 insertions(+), 10 deletions(-) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 2d5ad68..f5cdcc7 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -150,7 +150,7 @@ class CommentsController < ApplicationController return render :text => "invalid reason", :status => 400 end - if !@user.can_downvote? + if !@user.can_downvote?(comment) return render :text => "not permitted to downvote", :status => 400 end @@ -260,6 +260,12 @@ private end def find_comment - Comment.where(:short_id => params[:id]).first + comment = Comment.where(:short_id => params[:id]).first + if @user && comment + comment.current_vote = Vote.where(:user_id => @user.id, + :story_id => comment.story_id, :comment_id => comment.id).first + end + + comment end end diff --git a/app/controllers/stories_controller.rb b/app/controllers/stories_controller.rb index fb3edc6..8f156d0 100644 --- a/app/controllers/stories_controller.rb +++ b/app/controllers/stories_controller.rb @@ -213,7 +213,7 @@ class StoriesController < ApplicationController return render :text => "invalid reason", :status => 400 end - if !@user.can_downvote? + if !@user.can_downvote?(story) return render :text => "not permitted to downvote", :status => 400 end @@ -239,7 +239,13 @@ private end def find_story - Story.where(:short_id => params[:story_id]).first + story = Story.where(:short_id => params[:story_id]).first + if @user && story + story.vote = Vote.where(:user_id => @user.id, + :story_id => story.id, :comment_id => nil).first.try(:vote) + end + + story end def find_user_story diff --git a/app/models/comment.rb b/app/models/comment.rb index 6ed0ec0..f0a01b5 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -20,6 +20,9 @@ class Comment < ActiveRecord::Base :deliver_mention_notifications, :log_to_countinual after_destroy :unassign_votes + DOWNVOTABLE_DAYS = 7 + + # after this many minutes old, a comment cannot be edited MAX_EDIT_MINS = 90 validate do @@ -278,6 +281,14 @@ class Comment < ActiveRecord::Base end 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.id == self.user_id if self.is_moderated? diff --git a/app/models/story.rb b/app/models/story.rb index 71da77a..b04fdfa 100644 --- a/app/models/story.rb +++ b/app/models/story.rb @@ -10,10 +10,12 @@ 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 - # days a story is considered recent + # days a story is considered recent, for resubmitting RECENT_DAYS = 30 attr_accessor :vote, :already_posted_story, :fetched_content, :previewing, @@ -220,6 +222,14 @@ class Story < ActiveRecord::Base "hotness = '#{self.calculated_hotness}' WHERE id = #{self.id.to_i}") 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 diff --git a/app/models/user.rb b/app/models/user.rb index 92bb2bb..4296915 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -98,9 +98,26 @@ class User < ActiveRecord::Base true end - def can_downvote? - # TODO: maybe change this to require a certain level of karma - !is_new? + def can_downvote?(obj) + if is_new? + return false + elsif obj.is_a?(Story) + 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 + elsif obj.current_vote.try(:vote).to_i == -1 + # user can unvote + return true + end + end + + false end def check_session_token diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb index 994f1b9..584fa5f 100644 --- a/app/views/comments/_comment.html.erb +++ b/app/views/comments/_comment.html.erb @@ -14,7 +14,7 @@ class="comment <%= comment.current_vote ? (comment.current_vote[:vote] == 1 ? <%= link_to "", login_url, :class => "upvoter" %> <% end %>
<%= comment.score %>
- <% if @user && @user.can_downvote? %> + <% if @user && @user.can_downvote?(comment) %> <% else %> diff --git a/app/views/stories/_listdetail.html.erb b/app/views/stories/_listdetail.html.erb index ffcaf05..aa54456 100644 --- a/app/views/stories/_listdetail.html.erb +++ b/app/views/stories/_listdetail.html.erb @@ -9,7 +9,7 @@ class="story <%= story.vote == 1 ? "upvoted" : (story.vote == -1 ? <%= link_to "", login_url, :class => "upvoter" %> <% end %>
<%= story.upvotes - story.downvotes %>
- <% if @user && @user.can_downvote? %> + <% if @user && @user.can_downvote?(story) %> <% else %>