mirror of
https://github.com/discourse/discourse-solved.git
synced 2025-07-05 21:32:11 +00:00
FIX: add mutex around un/mark as solved
To prevent any race conditions when two users toggle the state of a reply. (cf. https://meta.discourse.org/161104)
This commit is contained in:
parent
e16784fd07
commit
9ecac7a3e2
20
plugin.rb
20
plugin.rb
@ -77,6 +77,8 @@ SQL
|
|||||||
|
|
||||||
def self.accept_answer!(post, acting_user, topic: nil)
|
def self.accept_answer!(post, acting_user, topic: nil)
|
||||||
topic ||= post.topic
|
topic ||= post.topic
|
||||||
|
|
||||||
|
DistributedMutex.synchronize("discourse_solved_toggle_answer_#{topic.id}") do
|
||||||
accepted_id = topic.custom_fields["accepted_answer_post_id"].to_i
|
accepted_id = topic.custom_fields["accepted_answer_post_id"].to_i
|
||||||
|
|
||||||
if accepted_id > 0
|
if accepted_id > 0
|
||||||
@ -157,9 +159,12 @@ SQL
|
|||||||
|
|
||||||
DiscourseEvent.trigger(:accepted_solution, post)
|
DiscourseEvent.trigger(:accepted_solution, post)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.unaccept_answer!(post, topic: nil)
|
def self.unaccept_answer!(post, topic: nil)
|
||||||
topic ||= post.topic
|
topic ||= post.topic
|
||||||
|
|
||||||
|
DistributedMutex.synchronize("discourse_solved_toggle_answer_#{topic.id}") do
|
||||||
post.custom_fields["is_accepted_answer"] = nil
|
post.custom_fields["is_accepted_answer"] = nil
|
||||||
topic.custom_fields["accepted_answer_post_id"] = nil
|
topic.custom_fields["accepted_answer_post_id"] = nil
|
||||||
|
|
||||||
@ -198,12 +203,13 @@ SQL
|
|||||||
DiscourseEvent.trigger(:unaccepted_solution, post)
|
DiscourseEvent.trigger(:unaccepted_solution, post)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
require_dependency "application_controller"
|
require_dependency "application_controller"
|
||||||
|
|
||||||
class DiscourseSolved::AnswerController < ::ApplicationController
|
class DiscourseSolved::AnswerController < ::ApplicationController
|
||||||
|
|
||||||
def accept
|
def accept
|
||||||
|
|
||||||
limit_accepts
|
limit_accepts
|
||||||
|
|
||||||
post = Post.find(params[:id].to_i)
|
post = Post.find(params[:id].to_i)
|
||||||
@ -219,7 +225,6 @@ SQL
|
|||||||
end
|
end
|
||||||
|
|
||||||
def unaccept
|
def unaccept
|
||||||
|
|
||||||
limit_accepts
|
limit_accepts
|
||||||
|
|
||||||
post = Post.find(params[:id].to_i)
|
post = Post.find(params[:id].to_i)
|
||||||
@ -234,12 +239,11 @@ SQL
|
|||||||
end
|
end
|
||||||
|
|
||||||
def limit_accepts
|
def limit_accepts
|
||||||
unless current_user.staff?
|
return if current_user.staff?
|
||||||
RateLimiter.new(nil, "accept-hr-#{current_user.id}", 20, 1.hour).performed!
|
RateLimiter.new(nil, "accept-hr-#{current_user.id}", 20, 1.hour).performed!
|
||||||
RateLimiter.new(nil, "accept-min-#{current_user.id}", 4, 30.seconds).performed!
|
RateLimiter.new(nil, "accept-min-#{current_user.id}", 4, 30.seconds).performed!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
DiscourseSolved::Engine.routes.draw do
|
DiscourseSolved::Engine.routes.draw do
|
||||||
post "/accept" => "answer#accept"
|
post "/accept" => "answer#accept"
|
||||||
@ -477,7 +481,6 @@ SQL
|
|||||||
end
|
end
|
||||||
|
|
||||||
topic.user_id == current_user.id && !topic.closed
|
topic.user_id == current_user.id && !topic.closed
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -486,9 +489,7 @@ SQL
|
|||||||
attributes :can_accept_answer, :can_unaccept_answer, :accepted_answer
|
attributes :can_accept_answer, :can_unaccept_answer, :accepted_answer
|
||||||
|
|
||||||
def can_accept_answer
|
def can_accept_answer
|
||||||
topic = (topic_view && topic_view.topic) || object.topic
|
if topic = (topic_view && topic_view.topic) || object.topic
|
||||||
|
|
||||||
if topic
|
|
||||||
return scope.can_accept_answer?(topic, object) && object.post_number > 1 && !accepted_answer
|
return scope.can_accept_answer?(topic, object) && object.post_number > 1 && !accepted_answer
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -496,8 +497,7 @@ SQL
|
|||||||
end
|
end
|
||||||
|
|
||||||
def can_unaccept_answer
|
def can_unaccept_answer
|
||||||
topic = (topic_view && topic_view.topic) || object.topic
|
if topic = (topic_view && topic_view.topic) || object.topic
|
||||||
if topic
|
|
||||||
scope.can_accept_answer?(topic, object) && (post_custom_fields["is_accepted_answer"] == 'true')
|
scope.can_accept_answer?(topic, object) && (post_custom_fields["is_accepted_answer"] == 'true')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user