From 09292d6ff91b50d5214163bb2f228e5342ac5765 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 10 Jun 2015 06:09:20 +1000 Subject: [PATCH] - Add security - Add configuration option on categories to enable --- .../solved-settings.hbs | 8 +++ .../extend-for-solved-button.js.es6 | 10 ++++ config/locales/client.en.yml | 1 + config/locales/server.en.yml | 3 -- config/settings.yml | 4 -- plugin.rb | 50 ++++++++++++++++++- 6 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 assets/javascripts/discourse/connectors/category-custom-settings/solved-settings.hbs delete mode 100644 config/locales/server.en.yml delete mode 100644 config/settings.yml diff --git a/assets/javascripts/discourse/connectors/category-custom-settings/solved-settings.hbs b/assets/javascripts/discourse/connectors/category-custom-settings/solved-settings.hbs new file mode 100644 index 0000000..65513ca --- /dev/null +++ b/assets/javascripts/discourse/connectors/category-custom-settings/solved-settings.hbs @@ -0,0 +1,8 @@ +
+
+ +
+
diff --git a/assets/javascripts/discourse/initializers/extend-for-solved-button.js.es6 b/assets/javascripts/discourse/initializers/extend-for-solved-button.js.es6 index c4db815..c57afe2 100644 --- a/assets/javascripts/discourse/initializers/extend-for-solved-button.js.es6 +++ b/assets/javascripts/discourse/initializers/extend-for-solved-button.js.es6 @@ -8,6 +8,16 @@ export default { name: 'extend-for-solved-button', initialize: function() { + Discourse.Category.reopen({ + enable_accepted_answers: function(key, value){ + if (arguments.length > 1) { + this.set('custom_fields.enable_accepted_answers', value ? "true" : "false"); + } + var fields = this.get('custom_fields'); + return fields && (fields.enable_accepted_answers === "true"); + }.property('custom_fields') + }), + Topic.reopen({ // keeping this here cause there is complex localization diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index bf32c29..5396f49 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1,6 +1,7 @@ en: js: accepted_answer: + allow_accepted_answers: "Allow users to accept answers" accept_answer: "Accept answer" unaccept_answer: "Unaccept answer" accepted_html: " Solved by {{username}} in post #{{post_number}}" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml deleted file mode 100644 index 4ca7911..0000000 --- a/config/locales/server.en.yml +++ /dev/null @@ -1,3 +0,0 @@ -en: - site_settings: - categories_with_solved_button: "List of categories where solved button is allowed" diff --git a/config/settings.yml b/config/settings.yml deleted file mode 100644 index 5c9fc46..0000000 --- a/config/settings.yml +++ /dev/null @@ -1,4 +0,0 @@ -uncategorized: - categories_with_solved_button: - default: '' - client: true diff --git a/plugin.rb b/plugin.rb index 8296d35..cd57169 100644 --- a/plugin.rb +++ b/plugin.rb @@ -19,9 +19,10 @@ after_initialize do require_dependency "application_controller" class DiscourseSolvedButton::AnswerController < ::ApplicationController def accept - post = Post.find(params[:id].to_i) + guardian.ensure_can_accept_answer!(post.topic) + accepted_id = post.topic.custom_fields["accepted_answer_post_id"].to_i if accepted_id > 0 if p2 = Post.find_by(id: accepted_id) @@ -40,6 +41,9 @@ after_initialize do def unaccept post = Post.find(params[:id].to_i) + + guardian.ensure_can_accept_answer!(post.topic) + post.custom_fields["is_accepted_answer"] = nil post.topic.custom_fields["accepted_answer_post_id"] = nil post.topic.save! @@ -95,6 +99,44 @@ after_initialize do end + 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 + require_dependency 'post_serializer' class ::PostSerializer attributes :can_accept_answer, :can_unaccept_answer, :accepted_answer @@ -102,12 +144,16 @@ after_initialize do def can_accept_answer topic = (topic_view && topic_view.topic) || object.topic if topic + scope.can_accept_answer?(topic) && object.post_number > 1 && !accepted_answer end end def can_unaccept_answer - post_custom_fields["is_accepted_answer"] + topic = (topic_view && topic_view.topic) || object.topic + if topic + scope.can_accept_answer?(topic) && post_custom_fields["is_accepted_answer"] + end end def accepted_answer