[Forum] Revise forum post vote system

This commit is contained in:
Kira 2021-03-04 20:33:56 -08:00
parent 14b3224dd8
commit adabdd1028
9 changed files with 105 additions and 25 deletions

View File

@ -1,21 +1,26 @@
class ForumPostVotesController < ApplicationController
respond_to :js
before_action :load_forum_post
before_action :load_vote, only: [:destroy]
respond_to :json
before_action :member_only
before_action :load_forum_post
before_action :validate_forum_post
before_action :load_vote, only: [:destroy]
def create
@forum_post_vote = @forum_post.votes.create(forum_post_vote_params)
respond_with(@forum_post_vote)
respond_with(@forum_post_vote) do |fmt|
fmt.json { render json: @forum_post_vote, code: 201 }
end
end
def destroy
@forum_post_vote.destroy
respond_with(@forum_post_vote)
respond_with(@forum_post_vote) do |fmt|
fmt.json { render json: {}, code: 200 }
end
end
private
def load_vote
@forum_post_vote = @forum_post.votes.where(creator_id: CurrentUser.id).first
raise ActiveRecord::RecordNotFound.new if @forum_post_vote.nil?
@ -24,9 +29,13 @@ private
def load_forum_post
@forum_post = ForumPost.find(params[:forum_post_id])
end
def validate_forum_post
raise User::PrivilegeError.new unless @forum_post.visible?(CurrentUser.user)
raise User::PrivilegeError.new unless @forum_post.votable?
end
def forum_post_vote_params
params.fetch(:forum_post_vote, {}).permit(:score)
end
end

View File

@ -1,5 +1,4 @@
import Utility from "./utility";
import Comment from "./comments";
let ForumPost = {};
@ -9,9 +8,64 @@ ForumPost.initialize_all = function() {
$(".forum-post-reply-link").on('click', ForumPost.quote);
$(".forum-post-hide-link").on('click', ForumPost.hide);
$(".forum-post-unhide-link").on('click', ForumPost.unhide);
$(".forum-vote-up").on('click', ForumPost.vote_up);
$(".forum-vote-meh").on('click', ForumPost.vote_meh);
$(".forum-vote-down").on('click', ForumPost.vote_down);
$(document).on('click', ".forum-vote-remove", ForumPost.vote_remove);
}
}
ForumPost.vote = function(id, score) {
const create_post = function(new_vote) {
const score_map = {'1': 'fa-thumbs-up', '0': 'fa-meh', '-1': 'fa-thumbs-down' };
const score_map_2 = {'1': 'up', '0': 'meh', '-1': 'down'};
const link1 = $('<a>').attr('href', '#').attr('data-forum-id', new_vote.forum_post_id).addClass('forum-vote-remove').append($('<i>').addClass('far').addClass(score_map[new_vote.score.toString()]));
const link2 = $('<a>').attr('href', `/users/${new_vote.creator_id}`).text(new_vote.creator_name);
const container = $('<li>').addClass(`vote-score-${score_map_2[new_vote.score]}`).addClass('own-forum-vote');
container.append(link1).append(' ').append(link2);
$(`#forum-post-votes-for-${new_vote.forum_post_id}`).prepend(container);
};
$.ajax({
url: `/forum_posts/${id}/votes.json`,
type: 'POST',
dataType: 'json',
accept: 'text/javascript',
data: {'forum_post_vote[score]': score}
}).done(function(data) {
create_post(data);
$('.forum-post-vote-block').remove();
}).fail(function(data) {
Utility.error("Failed to vote on forum post.");
});
}
ForumPost.vote_up = function(evt) {
ForumPost.vote($(evt.target.parentNode).data('forum-id'), 1);
}
ForumPost.vote_meh = function(evt) {
ForumPost.vote($(evt.target.parentNode).data('forum-id'), 0);
}
ForumPost.vote_down = function(evt) {
ForumPost.vote($(evt.target.parentNode).data('forum-id'), -1);
}
ForumPost.vote_remove = function(evt) {
const id = $(evt.target.parentNode).data('forum-id');
$.ajax({
url: `/forum_posts/${id}/votes.json`,
type: 'DELETE',
dataType: 'json',
accept: 'text/javascript',
}).done(function(data) {
$(evt.target).parents(".own-forum-vote").remove();
Utility.notice("Vote removed.");
}).fail(function(data) {
Utility.error("Failed to unvote on forum post.");
})
}
ForumPost.quote = function (e) {
e.preventDefault();
const parent = $(e.target).parents('article.forum-post');

View File

@ -3,11 +3,32 @@ class ForumPostVote < ApplicationRecord
belongs_to :forum_post
validates :creator_id, uniqueness: {scope: :forum_post_id}
validates :score, inclusion: {in: [-1, 0, 1]}
validate :validate_creator_is_not_limited, on: :create
scope :up, -> {where(score: 1)}
scope :down, -> {where(score: -1)}
scope :by, ->(user_id) {where(creator_id: user_id)}
scope :excluding_user, ->(user_id) {where("creator_id <> ?", user_id)}
def creator_name
if association(:creator).loaded?
return creator&.name || "Anonymous"
end
User.id_to_name(creator_id)
end
def method_attributes
super + [:creator_name]
end
def validate_creator_is_not_limited
allowed = creator.can_forum_vote_with_reason
if allowed != true
errors.add(:creator, User.throttle_reason(allowed))
return false
end
true
end
def up?
score == 1
end

View File

@ -533,6 +533,8 @@ class User < ApplicationRecord
:general_bypass_throttle?, 3.days)
create_user_throttle(:suggest_tag, -> { Danbooru.config.tag_suggestion_limit - (TagAlias.for_creator(id).where("created_at > ?", 1.hour.ago).count + TagImplication.for_creator(id).where("created_at > ?", 1.hour.ago).count + BulkUpdateRequest.for_creator(id).where("created_at > ?", 1.hour.ago).count) },
:is_janitor?, 7.days)
create_user_throttle(:forum_vote, -> { Danbooru.config.forum_vote_limit - ForumPostVote.by(id).where("created_at < ?", 1.hour.ago).count },
:is_janitor?, 3.days)
def can_remove_from_pools?
is_member? && older_than(7.days)

View File

@ -2,10 +2,10 @@
# forum_post
%>
<li>
<%= link_to content_tag(:i, nil, class: "far fa-thumbs-up"), forum_post_votes_path(forum_post_id: forum_post.id, format: "js"), remote: true, method: :post, data: {params: "forum_post_vote[score]=1"}, title: "Vote up" %>
<li class="forum-post-vote-block">
<%= link_to content_tag(:i, nil, class: "far fa-thumbs-up"), "#", title: "Vote up", class: "forum-vote-up", 'data-forum-id': forum_post.id %>
<%= link_to content_tag(:i, nil, class: "far fa-meh"), forum_post_votes_path(forum_post_id: forum_post.id, format: "js"), remote: true, method: :post, data: {params: "forum_post_vote[score]=0"}, title: "Vote meh" %>
<%= link_to content_tag(:i, nil, class: "far fa-meh"), "#", title: "Vote meh", class: "forum-vote-meh", 'data-forum-id': forum_post.id %>
<%= link_to content_tag(:i, nil, class: "far fa-thumbs-down"), forum_post_votes_path(forum_post_id: forum_post.id, format: "js"), remote: true, method: :post, data: {params: "forum_post_vote[score]=-1"}, title: "Vote down" %>
<%= link_to content_tag(:i, nil, class: "far fa-thumbs-down"), "#", title: "Vote down", class: "forum-vote-down", 'data-forum-id': forum_post.id %>
</li>

View File

@ -3,9 +3,9 @@
# forum_post
%>
<li class="vote-score-<%= vote.vote_type %>">
<li class="vote-score-<%= vote.vote_type %> <%= 'own-forum-vote' if vote.creator_id == CurrentUser.id %>">
<% if forum_post.tag_change_request && forum_post.tag_change_request.is_pending? && vote.creator_id == CurrentUser.id %>
<%= link_to content_tag(:i, nil, class: "far #{vote.fa_class}"), forum_post_votes_path(forum_post_id: forum_post.id, format: "js"), remote: true, method: :delete %>
<%= link_to content_tag(:i, nil, class: "far #{vote.fa_class}"), "#", class: "forum-vote-remove", 'data-forum-id': forum_post.id %>
<%= link_to_user vote.creator %>
<% else %>
<%= content_tag(:i, nil, class: "far #{vote.fa_class}") %>

View File

@ -1,7 +0,0 @@
<% if @forum_post_vote.invalid? %>
$(window).trigger("danbooru:error", <%= raw @forum_post_vote.errors.full_messages.join("; ").to_json %>);
<% else %>
$(window).trigger("danbooru:notice", "Voted");
var code = <%= raw render(partial: "forum_post_votes/list", locals: {forum_post: @forum_post, votes: @forum_post.votes}).to_json %>;
$("#forum-post-votes-for-<%= @forum_post.id %>").html(code);
<% end %>

View File

@ -1,3 +0,0 @@
$(window).trigger("danbooru:notice", "Unvoted");
var code = <%= raw render(partial: "forum_post_votes/list", locals: {forum_post: @forum_post, votes: @forum_post.votes}).to_json %>;
$("#forum-post-votes-for-<%= @forum_post.id %>").html(code);

View File

@ -218,6 +218,10 @@ fart'
15
end
def forum_vote_limit
30
end
# Blips created in the last hour
def blip_limit
25