2015-06-15 00:24:49 -04:00
|
|
|
# name: discourse-solved
|
2015-05-19 01:45:19 -04:00
|
|
|
# about: Add a solved button to answers on Discourse
|
|
|
|
# version: 0.1
|
|
|
|
# authors: Sam Saffron
|
|
|
|
|
2015-06-15 00:24:49 -04:00
|
|
|
PLUGIN_NAME = "discourse_solved".freeze
|
2015-05-19 01:45:19 -04:00
|
|
|
|
|
|
|
register_asset 'stylesheets/solutions.scss'
|
|
|
|
|
|
|
|
after_initialize do
|
|
|
|
|
2015-06-15 00:24:49 -04:00
|
|
|
module ::DiscourseSolved
|
2015-05-19 01:45:19 -04:00
|
|
|
class Engine < ::Rails::Engine
|
|
|
|
engine_name PLUGIN_NAME
|
2015-06-15 00:24:49 -04:00
|
|
|
isolate_namespace DiscourseSolved
|
2015-05-19 01:45:19 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
require_dependency "application_controller"
|
2015-06-15 00:24:49 -04:00
|
|
|
class DiscourseSolved::AnswerController < ::ApplicationController
|
2015-05-19 01:45:19 -04:00
|
|
|
def accept
|
|
|
|
post = Post.find(params[:id].to_i)
|
|
|
|
|
2015-06-09 16:09:20 -04:00
|
|
|
guardian.ensure_can_accept_answer!(post.topic)
|
|
|
|
|
2015-05-19 02:26:22 -04:00
|
|
|
accepted_id = post.topic.custom_fields["accepted_answer_post_id"].to_i
|
|
|
|
if accepted_id > 0
|
2015-05-19 01:45:19 -04:00
|
|
|
if p2 = Post.find_by(id: accepted_id)
|
|
|
|
p2.custom_fields["is_accepted_answer"] = nil
|
|
|
|
p2.save!
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
post.custom_fields["is_accepted_answer"] = "true"
|
|
|
|
post.topic.custom_fields["accepted_answer_post_id"] = post.id
|
|
|
|
post.topic.save!
|
|
|
|
post.save!
|
|
|
|
|
2015-06-15 00:24:49 -04:00
|
|
|
unless current_user.id == post.user_id
|
|
|
|
|
|
|
|
Notification.create!(notification_type: Notification.types[:custom],
|
|
|
|
user_id: post.user_id,
|
|
|
|
topic_id: post.topic_id,
|
|
|
|
post_number: post.post_number,
|
|
|
|
data: {
|
|
|
|
message: 'solved.accepted_notification',
|
|
|
|
display_username: current_user.username,
|
|
|
|
topic_title: post.topic.title
|
|
|
|
}.to_json
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2015-05-19 01:45:19 -04:00
|
|
|
render json: success_json
|
|
|
|
end
|
|
|
|
|
|
|
|
def unaccept
|
|
|
|
post = Post.find(params[:id].to_i)
|
2015-06-09 16:09:20 -04:00
|
|
|
|
|
|
|
guardian.ensure_can_accept_answer!(post.topic)
|
|
|
|
|
2015-05-19 01:45:19 -04:00
|
|
|
post.custom_fields["is_accepted_answer"] = nil
|
|
|
|
post.topic.custom_fields["accepted_answer_post_id"] = nil
|
|
|
|
post.topic.save!
|
|
|
|
post.save!
|
|
|
|
|
|
|
|
render json: success_json
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-06-15 00:24:49 -04:00
|
|
|
DiscourseSolved::Engine.routes.draw do
|
2015-05-19 01:45:19 -04:00
|
|
|
post "/accept" => "answer#accept"
|
|
|
|
post "/unaccept" => "answer#unaccept"
|
|
|
|
end
|
|
|
|
|
|
|
|
Discourse::Application.routes.append do
|
2015-06-15 00:24:49 -04:00
|
|
|
mount ::DiscourseSolved::Engine, at: "solution"
|
2015-05-19 01:45:19 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
TopicView.add_post_custom_fields_whitelister do |user|
|
|
|
|
["is_accepted_answer"]
|
|
|
|
end
|
|
|
|
|
|
|
|
require_dependency 'topic_view_serializer'
|
|
|
|
class ::TopicViewSerializer
|
|
|
|
attributes :accepted_answer
|
|
|
|
|
|
|
|
def include_accepted_answer?
|
|
|
|
accepted_answer_post_id
|
|
|
|
end
|
|
|
|
|
|
|
|
def accepted_answer
|
|
|
|
if info = accepted_answer_post_info
|
|
|
|
{
|
|
|
|
post_number: info[0],
|
|
|
|
username: info[1],
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def accepted_answer_post_info
|
|
|
|
# TODO: we may already have it in the stream ... so bypass query here
|
|
|
|
|
|
|
|
Post.where(id: accepted_answer_post_id, topic_id: object.topic.id)
|
|
|
|
.joins(:user)
|
|
|
|
.pluck('post_number, username')
|
|
|
|
.first
|
|
|
|
end
|
|
|
|
|
|
|
|
def accepted_answer_post_id
|
|
|
|
id = object.topic.custom_fields["accepted_answer_post_id"]
|
|
|
|
id && id.to_i
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2015-06-09 16:09:20 -04:00
|
|
|
class ::Category
|
|
|
|
after_save :reset_accepted_cache
|
|
|
|
|
|
|
|
protected
|
|
|
|
def reset_accepted_cache
|
|
|
|
::Guardian.reset_accepted_answer_cache
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class ::Guardian
|
|
|
|
|
|
|
|
@@allowed_accepted_cache = DistributedCache.new("allowed_accepted")
|
|
|
|
|
|
|
|
def self.reset_accepted_answer_cache
|
|
|
|
@@allowed_accepted_cache["allowed"] =
|
|
|
|
begin
|
|
|
|
Set.new(
|
|
|
|
CategoryCustomField
|
|
|
|
.where(name: "enable_accepted_answers", value: "true")
|
|
|
|
.pluck(:category_id)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def allow_accepted_answers_on_category?(category_id)
|
|
|
|
self.class.reset_accepted_answer_cache unless @@allowed_accepted_cache["allowed"]
|
|
|
|
@@allowed_accepted_cache["allowed"].include?(category_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_accept_answer?(topic)
|
|
|
|
allow_accepted_answers_on_category?(topic.category_id) && (
|
|
|
|
is_staff? || (
|
|
|
|
authenticated? && !topic.closed? && topic.user_id == current_user.id
|
|
|
|
)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-05-19 01:45:19 -04:00
|
|
|
require_dependency 'post_serializer'
|
|
|
|
class ::PostSerializer
|
|
|
|
attributes :can_accept_answer, :can_unaccept_answer, :accepted_answer
|
|
|
|
|
|
|
|
def can_accept_answer
|
|
|
|
topic = (topic_view && topic_view.topic) || object.topic
|
|
|
|
if topic
|
2015-06-09 16:09:20 -04:00
|
|
|
scope.can_accept_answer?(topic) &&
|
2015-05-19 01:45:19 -04:00
|
|
|
object.post_number > 1 && !accepted_answer
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_unaccept_answer
|
2015-06-09 16:09:20 -04:00
|
|
|
topic = (topic_view && topic_view.topic) || object.topic
|
|
|
|
if topic
|
|
|
|
scope.can_accept_answer?(topic) && post_custom_fields["is_accepted_answer"]
|
|
|
|
end
|
2015-05-19 01:45:19 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def accepted_answer
|
|
|
|
post_custom_fields["is_accepted_answer"]
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|