diff --git a/app/controllers/stories_controller.rb b/app/controllers/stories_controller.rb index ea55cc7..0e48d0c 100644 --- a/app/controllers/stories_controller.rb +++ b/app/controllers/stories_controller.rb @@ -237,8 +237,7 @@ class StoriesController < ApplicationController return render :text => "can't find story", :status => 400 end - Vote.vote_thusly_on_story_or_comment_for_user_because(0, story.id, - nil, @user.id, "H") + HiddenStory.hide_story_for_user(story.id, @user.id) render :text => "ok" end @@ -248,8 +247,7 @@ class StoriesController < ApplicationController return render :text => "can't find story", :status => 400 end - Vote.vote_thusly_on_story_or_comment_for_user_because(0, story.id, - nil, @user.id, nil) + HiddenStory.where(:user_id => @user.id, :story_id => story.id).delete_all render :text => "ok" end @@ -299,9 +297,11 @@ private if @user if v = Vote.where(:user_id => @user.id, :story_id => @story.id, :comment_id => nil).first - @story.vote = v.vote + @story.vote = { :vote => v.vote, :reason => v.reason } end + @story.is_hidden_by_cur_user = @story.is_hidden_by_user?(@user) + @votes = Vote.comment_votes_by_user_for_story_hash(@user.id, @story.id) @comments.each do |c| if @votes[c.id] diff --git a/app/models/hidden_story.rb b/app/models/hidden_story.rb new file mode 100644 index 0000000..03ea233 --- /dev/null +++ b/app/models/hidden_story.rb @@ -0,0 +1,11 @@ +class HiddenStory < ActiveRecord::Base + belongs_to :user + belongs_to :story + + validates_presence_of :user_id, :story_id + + def self.hide_story_for_user(story_id, user_id) + HiddenStory.where(:user_id => user_id, :story_id => + story_id).first_or_initialize.save! + end +end diff --git a/app/models/stories_paginator.rb b/app/models/stories_paginator.rb index 36838d7..3229d1f 100644 --- a/app/models/stories_paginator.rb +++ b/app/models/stories_paginator.rb @@ -26,10 +26,16 @@ private if @user votes = Vote.votes_by_user_for_stories_hash(@user.id, scope.map(&:id)) + hs = HiddenStory.where(:user_id => @user.id, :story_id => + scope.map(&:id)).map(&:story_id) + scope.each do |s| if votes[s.id] s.vote = votes[s.id] end + if hs.include?(s.id) + s.is_hidden_by_cur_user = true + end end end scope diff --git a/app/models/story.rb b/app/models/story.rb index 850a87d..b3da7d4 100644 --- a/app/models/story.rb +++ b/app/models/story.rb @@ -31,7 +31,7 @@ class Story < ActiveRecord::Base RECENT_DAYS = 30 attr_accessor :vote, :already_posted_story, :fetched_content, :previewing, - :seen_previous + :seen_previous, :is_hidden_by_cur_user attr_accessor :editor, :moderation_reason, :merge_story_short_id before_validation :assign_short_id_and_upvote, @@ -298,11 +298,11 @@ class Story < ActiveRecord::Base end def hider_count - @hider_count ||= Vote.where(:story_id => self.id, :comment_id => nil, - :vote => 0).count + @hider_count ||= HiddenStory.where(:story_id => self.id).count end def is_downvotable? + return true if self.created_at Time.now - self.created_at <= DOWNVOTABLE_DAYS.days else @@ -328,6 +328,10 @@ class Story < ActiveRecord::Base is_expired? end + def is_hidden_by_user?(user) + !!HiddenStory.where(:user_id => user.id, :story_id => self.id).first + end + def is_recent? self.created_at >= RECENT_DAYS.days.ago end diff --git a/app/models/story_repository.rb b/app/models/story_repository.rb index 3507289..97391de 100644 --- a/app/models/story_repository.rb +++ b/app/models/story_repository.rb @@ -11,7 +11,7 @@ class StoryRepository def hottest hottest = positive_ranked base_scope - hottest = filter_downvoted_and_tags hottest + hottest = filter_hidden_and_tags hottest hottest.order('hotness') end @@ -27,7 +27,7 @@ class StoryRepository end def newest - newest = filter_downvoted_and_tags base_scope + newest = filter_hidden_and_tags base_scope newest.order("stories.id DESC") end @@ -94,9 +94,9 @@ private Story.unmerged.where(is_expired: false) end - def filter_downvoted_and_tags(scope) + def filter_hidden_and_tags(scope) if @user - scope = filter_downvoted scope + scope = filter_hidden scope end if @params[:exclude_tags].try(:any?) scope = filter_tags scope, @params[:exclude_tags] @@ -104,20 +104,16 @@ private scope end - def filter_downvoted(scope) + def filter_hidden(scope) scope.where(Story.arel_table[:id].not_in(hidden_arel)) end def hidden_arel if @user - hidden_arel = Vote.arel_table.where( - Vote.arel_table[:user_id].eq(@user.id) - ).where( - Vote.arel_table[:vote].lteq(0) - ).where( - Vote.arel_table[:comment_id].eq(nil) + hidden_arel = HiddenStory.arel_table.where( + HiddenStory.arel_table[:user_id].eq(@user.id) ).project( - Vote.arel_table[:story_id] + HiddenStory.arel_table[:story_id] ) end end diff --git a/app/models/vote.rb b/app/models/vote.rb index 9775d8c..9ee1a60 100644 --- a/app/models/vote.rb +++ b/app/models/vote.rb @@ -28,7 +28,7 @@ class Vote < ActiveRecord::Base Vote.where(:user_id => user, :story_id => stories, :comment_id => nil).each do |v| - votes[v.story_id] = v.vote + votes[v.story_id] = { :vote => v.vote, :reason => v.reason } end votes @@ -84,7 +84,7 @@ class Vote < ActiveRecord::Base v = Vote.where(:user_id => user_id, :story_id => story_id, :comment_id => comment_id).first_or_initialize - if !v.new_record? && v.vote == vote && vote != 0 + if !v.new_record? && v.vote == vote return end @@ -93,7 +93,7 @@ class Vote < ActiveRecord::Base Vote.transaction do # unvote - if vote == 0 && reason == nil + if vote == 0 # neutralize previous vote upvote = (v.vote == 1 ? -1 : 0) downvote = (v.vote == -1 ? -1 : 0) diff --git a/app/views/stories/_listdetail.html.erb b/app/views/stories/_listdetail.html.erb index 4b6e0d0..0eb4f89 100644 --- a/app/views/stories/_listdetail.html.erb +++ b/app/views/stories/_listdetail.html.erb @@ -1,7 +1,8 @@
  • <%= story.vote == -1 ? -"downvoted" : "" %> <%= story.vote == 0 ? "hidden" : "" %> <%= story.is_expired? ? -"expired" : "" %>"> +class="story <%= story.vote && story.vote[:vote] == 1 ? "upvoted" : "" %> +<%= story.vote && story.vote[:vote] == -1 ? "downvoted" : "" %> +<%= story.is_hidden_by_cur_user ? "hidden" : "" %> +<%= story.is_expired? ? "expired" : "" %>">
    <% if @user %> @@ -100,10 +101,13 @@ class="story <%= story.vote == 1 ? "upvoted" : "" %> <%= story.vote == -1 ? <% end %> <% end %> <% if !story.is_gone? && @user %> - <% if @user && @user.can_downvote?(story) %> + <% if @user && story.vote && story.vote[:vote] == -1 %> + | unflag (<%= + Vote::STORY_REASONS[story.vote[:reason]].to_s.downcase %>) + <% elsif @user && @user.can_downvote?(story) %> | flag <% end %> - <% if story.vote == 0 %> + <% if story.is_hidden_by_cur_user %> | <%= link_to "unhide", story_unhide_path(story.short_id), :class => "hider" %> <% else %> diff --git a/db/migrate/20150211170052_move_hidden_votes_to_hidden_story.rb b/db/migrate/20150211170052_move_hidden_votes_to_hidden_story.rb new file mode 100644 index 0000000..47012f1 --- /dev/null +++ b/db/migrate/20150211170052_move_hidden_votes_to_hidden_story.rb @@ -0,0 +1,19 @@ +class MoveHiddenVotesToHiddenStory < ActiveRecord::Migration + def up + create_table :hidden_stories do |t| + t.integer :user_id + t.integer :story_id + end + + add_index "hidden_stories", ["user_id", "story_id"], :unique => true + + Vote.where(:vote => 0).each do |v| + hs = HiddenStory.new + hs.user_id = v.user_id + hs.story_id = v.story_id + hs.save! + end + + Vote.where(:vote => 0).delete_all + end +end diff --git a/db/schema.rb b/db/schema.rb index 9a970a1..544a8e0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150127180326) do +ActiveRecord::Schema.define(version: 20150211170052) do create_table "comments", force: true do |t| t.datetime "created_at", null: false @@ -46,6 +46,13 @@ ActiveRecord::Schema.define(version: 20150127180326) do t.string "link" end + create_table "hidden_stories", force: true do |t| + t.integer "user_id" + t.integer "story_id" + end + + add_index "hidden_stories", ["user_id", "story_id"], name: "index_hidden_stories_on_user_id_and_story_id", unique: true, using: :btree + create_table "invitation_requests", force: true do |t| t.string "code" t.boolean "is_verified", default: false