Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions app/controllers/question_answer/votes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# frozen_string_literal: true

module QuestionAnswer
class VotesController < ApplicationController
before_action :ensure_logged_in
before_action :find_vote_post
before_action :find_vote_user, only: [:create, :destroy]
before_action :ensure_qa_enabled, only: [:create, :destroy]
before_action :ensure_can_act, only: [:create, :destroy]

def create
unless Topic.qa_can_vote(@post.topic, @user)
raise Discourse::InvalidAccess.new(
nil,
nil,
custom_message: 'vote.error.user_over_limit'
)
end

unless @post.qa_can_vote(@user.id)
raise Discourse::InvalidAccess.new(
nil,
nil,
custom_message: 'vote.error.one_vote_per_post'
)
end

if QuestionAnswer::Vote.vote(@post, @user, vote_args)
render json: success_json.merge(
qa_votes: Topic.qa_votes(@post.topic, @user),
qa_can_vote: Topic.qa_can_vote(@post.topic, @user)
)
else
render json: failed_json, status: 422
end
end

def destroy
if Topic.qa_votes(@post.topic, @user).length.zero?
raise(
Discourse::InvalidAccess.new,
I18n.t('vote.error.user_has_not_voted')
)
end

if QuestionAnswer::Vote.vote(@post, @user, vote_args)
render json: success_json.merge(
qa_votes: Topic.qa_votes(@post.topic, @user),
qa_can_vote: Topic.qa_can_vote(@post.topic, @user)
)
else
render json: failed_json, status: 422
end
end

def voters
voters = []

if @post.qa_voted.any?
@post.qa_voted.each do |user_id|
if (user = User.find_by(id: user_id))
voters.push(QuestionAnswer::Voter.new(user))
end
end
end

render_json_dump(
voters: serialize_data(voters, QuestionAnswer::VoterSerializer)
)
end

private

def vote_params
params.require(:vote).permit(:post_id, :user_id, :direction)
end

def vote_args
{
direction: vote_params[:direction],
action: action_name
}
end

def find_vote_post
if params[:vote].present?
post_id = vote_params[:post_id]
else
params.require(:post_id)
post_id = params[:post_id]
end

@post = Post.find_by(id: post_id)

raise Discourse::NotFound unless @post
end

def find_vote_user
@user = User.find_by(id: vote_params[:user_id])

raise Discourse::NotFound unless @user
end

def ensure_qa_enabled
Topic.qa_enabled(@post.topic)
end

def ensure_can_act
if Topic.qa_votes(@post.topic, @user).present?
if action_name == QuestionAnswer::Vote::CREATE
raise(
Discourse::InvalidAccess.new,
I18n.t('vote.error.alread_voted')
)
end

can_undo = QuestionAnswer::Vote.can_undo(@post, @user)

if action_name == QuestionAnswer::Vote::DESTROY && !can_undo
window = SiteSetting.qa_undo_vote_action_window
msg = I18n.t('vote.error.undo_vote_action_window', minutes: window)

raise Discourse::InvalidAccess.new, msg
end
elsif action_name == QuestionAnswer::Vote::DESTROY
raise(
Discourse::InvalidAccess.new,
I18n.t('vote.error.user_has_not_voted')
)
end
end
end
end
17 changes: 17 additions & 0 deletions app/lib/question_answer/category_custom_field_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module QuestionAnswer
module CategoryCustomFieldExtension
def self.included(base)
base.after_commit :update_post_order, if: :qa_enabled_changed
end

def qa_enabled_changed
name == 'qa_enabled'
end

def update_post_order
Jobs.enqueue(:update_post_order, category_id: category_id)
end
end
end
19 changes: 19 additions & 0 deletions app/lib/question_answer/category_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module QuestionAnswer
module CategoryExtension
def qa_cast(key)
ActiveModel::Type::Boolean.new.cast(custom_fields[key]) || false
end

%w[
qa_enabled
qa_one_to_many
qa_disable_like_on_answers
qa_disable_like_on_questions
qa_disable_like_on_comments
].each do |key|
define_method(key.to_sym) { qa_cast(key) }
end
end
end
21 changes: 21 additions & 0 deletions app/lib/question_answer/guardian_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module QuestionAnswer
module GuardianExtension
def can_create_post_on_topic?(topic)
post = self.try(:post_opts) || {}
category = topic.category

if category.present? &&
category.qa_enabled &&
category.qa_one_to_many &&
post.present? &&
!post[:reply_to_post_number]

return @user.id == topic.user_id
end

super(topic)
end
end
end
9 changes: 9 additions & 0 deletions app/lib/question_answer/post_action_type_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module QuestionAnswer
module PostActionTypeExtension
def public_types
@public_types ||= super.except(:vote)
end
end
end
10 changes: 10 additions & 0 deletions app/lib/question_answer/post_creator_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

module QuestionAnswer
module PostCreatorExtension
def valid?
guardian.post_opts = @opts
super
end
end
end
59 changes: 59 additions & 0 deletions app/lib/question_answer/post_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# frozen_string_literal: true

module QuestionAnswer
module PostExtension
def self.included(base)
base.ignored_columns = %w[vote_count]
base.after_create :qa_update_vote_order, if: :qa_enabled
end

def qa_vote_count
if vote_count = custom_fields['vote_count']
[*vote_count].first.to_i
else
0
end
end

def qa_voted
if custom_fields['voted'].present?
[*custom_fields['voted']].map(&:to_i)
else
[]
end
end

def qa_vote_history
if custom_fields['vote_history'].present?
[*custom_fields['vote_history']]
else
[]
end
end

def qa_enabled
::Topic.qa_enabled(topic)
end

def qa_update_vote_order
::Topic.qa_update_vote_order(topic_id)
end

def qa_last_voted(user_id)
user_votes = qa_vote_history.select do |v|
v['user_id'].to_i == user_id && v['action'] == 'create'
end

return unless user_votes.any?

user_votes
.max_by { |v| v['created_at'].to_datetime.to_i }['created_at']
.to_datetime
end

def qa_can_vote(user_id)
SiteSetting.qa_tl_allow_multiple_votes_per_post ||
!qa_voted.include?(user_id)
end
end
end
80 changes: 80 additions & 0 deletions app/lib/question_answer/post_serializer_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# frozen_string_literal: true

module QuestionAnswer
module PostSerializerExtension
def actions_summary
summaries = super.reject { |s| s[:id] == PostActionType.types[:vote] }

return summaries unless object.qa_enabled

user = scope.current_user
summary = {
id: PostActionType.types[:vote],
count: object.qa_vote_count
}

if user
voted = object.qa_voted.include?(user.id)

if voted
summary[:acted] = true
summary[:can_undo] = QuestionAnswer::Vote.can_undo(object, user)
else
summary[:can_act] = true
end
end

summary.delete(:count) if summary[:count].zero?

if summary[:can_act] || summary[:count]
summaries + [summary]
else
summaries
end
end

def qa_vote_count
object.qa_vote_count
end

def qa_voted
object.qa_voted
end

def qa_enabled
object.qa_enabled
end

def last_answerer
object.topic.last_answerer
end

def include_last_answerer?
object.qa_enabled
end

def last_answered_at
object.topic.last_answered_at
end

def include_last_answered_at?
object.qa_enabled
end

def answer_count
object.topic.answer_count
end

def include_answer_count?
object.qa_enabled
end

def last_answer_post_number
object.topic.last_answer_post_number
end

def include_last_answer_post_number?
object.qa_enabled
end
end
end
Loading