| 
									
										
										
										
											2015-06-15 14:24:49 +10:00
										 |  |  | # name: discourse-solved | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  | # about: Add a solved button to answers on Discourse | 
					
						
							|  |  |  | # version: 0.1 | 
					
						
							|  |  |  | # authors: Sam Saffron | 
					
						
							| 
									
										
										
										
											2017-04-26 00:40:03 -04:00
										 |  |  | # url: https://github.com/discourse/discourse-solved | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 12:20:01 -05:00
										 |  |  | enabled_site_setting :solved_enabled | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 14:24:49 +10:00
										 |  |  | PLUGIN_NAME = "discourse_solved".freeze | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | register_asset 'stylesheets/solutions.scss' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | after_initialize do | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-06 17:28:15 +11:00
										 |  |  |   # we got to do a one time upgrade | 
					
						
							|  |  |  |   if defined?(UserAction::SOLVED) | 
					
						
							|  |  |  |     unless $redis.get('solved_already_upgraded') | 
					
						
							|  |  |  |       unless UserAction.where(action_type: UserAction::SOLVED).exists? | 
					
						
							|  |  |  |         Rails.logger.info("Upgrading storage for solved") | 
					
						
							| 
									
										
										
										
											2017-08-02 15:09:07 +09:00
										 |  |  |         sql = <<SQL
 | 
					
						
							| 
									
										
										
										
											2016-12-06 17:28:15 +11:00
										 |  |  |         INSERT INTO user_actions(action_type, | 
					
						
							|  |  |  |                                  user_id, | 
					
						
							|  |  |  |                                  target_topic_id, | 
					
						
							|  |  |  |                                  target_post_id, | 
					
						
							|  |  |  |                                  acting_user_id, | 
					
						
							|  |  |  |                                  created_at, | 
					
						
							|  |  |  |                                  updated_at) | 
					
						
							|  |  |  |         SELECT :solved, | 
					
						
							|  |  |  |                p.user_id, | 
					
						
							|  |  |  |                p.topic_id, | 
					
						
							|  |  |  |                p.id, | 
					
						
							|  |  |  |                t.user_id, | 
					
						
							|  |  |  |                pc.created_at, | 
					
						
							|  |  |  |                pc.updated_at | 
					
						
							|  |  |  |         FROM | 
					
						
							|  |  |  |           post_custom_fields pc | 
					
						
							|  |  |  |         JOIN | 
					
						
							|  |  |  |           posts p ON p.id = pc.post_id | 
					
						
							|  |  |  |         JOIN | 
					
						
							|  |  |  |           topics t ON t.id = p.topic_id | 
					
						
							|  |  |  |         WHERE | 
					
						
							|  |  |  |           pc.name = 'is_accepted_answer' AND | 
					
						
							|  |  |  |           pc.value = 'true' AND | 
					
						
							|  |  |  |           p.user_id IS NOT NULL | 
					
						
							|  |  |  | SQL | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         UserAction.exec_sql(sql, solved: UserAction::SOLVED) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       $redis.set("solved_already_upgraded", "true") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 14:24:49 +10:00
										 |  |  |   module ::DiscourseSolved | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |     class Engine < ::Rails::Engine | 
					
						
							|  |  |  |       engine_name PLUGIN_NAME | 
					
						
							| 
									
										
										
										
											2015-06-15 14:24:49 +10:00
										 |  |  |       isolate_namespace DiscourseSolved | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   require_dependency "application_controller" | 
					
						
							| 
									
										
										
										
											2015-06-15 14:24:49 +10:00
										 |  |  |   class DiscourseSolved::AnswerController < ::ApplicationController | 
					
						
							| 
									
										
										
										
											2016-12-06 17:28:15 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |     def accept | 
					
						
							| 
									
										
										
										
											2015-08-05 16:21:16 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |       limit_accepts | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |       post = Post.find(params[:id].to_i) | 
					
						
							| 
									
										
										
										
											2017-05-22 17:09:40 +08:00
										 |  |  |       topic = post.topic | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-22 17:09:40 +08:00
										 |  |  |       guardian.ensure_can_accept_answer!(topic) | 
					
						
							| 
									
										
										
										
											2015-06-10 06:09:20 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-22 17:09:40 +08:00
										 |  |  |       accepted_id = topic.custom_fields["accepted_answer_post_id"].to_i | 
					
						
							| 
									
										
										
										
											2015-05-19 16:26:22 +10:00
										 |  |  |       if accepted_id > 0
 | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |         if p2 = Post.find_by(id: accepted_id) | 
					
						
							|  |  |  |           p2.custom_fields["is_accepted_answer"] = nil | 
					
						
							|  |  |  |           p2.save! | 
					
						
							| 
									
										
										
										
											2016-12-06 17:28:15 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |           if defined?(UserAction::SOLVED) | 
					
						
							|  |  |  |             UserAction.where(action_type: UserAction::SOLVED, target_post_id: p2.id).destroy_all | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       post.custom_fields["is_accepted_answer"] = "true" | 
					
						
							| 
									
										
										
										
											2017-05-22 17:09:40 +08:00
										 |  |  |       topic.custom_fields["accepted_answer_post_id"] = post.id | 
					
						
							|  |  |  |       topic.save! | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |       post.save! | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-06 17:28:15 +11:00
										 |  |  |       if defined?(UserAction::SOLVED) | 
					
						
							| 
									
										
										
										
											2017-08-02 15:09:07 +09:00
										 |  |  |         UserAction.log_action!( | 
					
						
							|  |  |  |           action_type: UserAction::SOLVED, | 
					
						
							|  |  |  |           user_id: post.user_id, | 
					
						
							|  |  |  |           acting_user_id: guardian.user.id, | 
					
						
							|  |  |  |           target_post_id: post.id, | 
					
						
							|  |  |  |           target_topic_id: post.topic_id | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2016-12-06 17:28:15 +11:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 14:24:49 +10:00
										 |  |  |       unless current_user.id == post.user_id | 
					
						
							| 
									
										
										
										
											2017-08-02 15:09:07 +09:00
										 |  |  |         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: topic.title | 
					
						
							|  |  |  |           }.to_json | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2015-06-15 14:24:49 +10:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-02 15:09:07 +09:00
										 |  |  |       if (auto_close_hours = SiteSetting.solved_topics_auto_close_hours) > (0) && !topic.closed | 
					
						
							| 
									
										
										
										
											2017-05-22 17:09:40 +08:00
										 |  |  |         topic.set_or_create_timer( | 
					
						
							|  |  |  |           TopicTimer.types[:close], | 
					
						
							|  |  |  |           auto_close_hours, | 
					
						
							|  |  |  |           based_on_last_post: true | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2017-01-20 09:13:58 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-22 17:09:40 +08:00
										 |  |  |         MessageBus.publish("/topic/#{topic.id}", reload_topic: true) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       DiscourseEvent.trigger(:accepted_solution, post) | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |       render json: success_json | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def unaccept | 
					
						
							| 
									
										
										
										
											2015-08-05 16:21:16 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |       limit_accepts | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |       post = Post.find(params[:id].to_i) | 
					
						
							| 
									
										
										
										
											2015-06-10 06:09:20 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |       guardian.ensure_can_accept_answer!(post.topic) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |       post.custom_fields["is_accepted_answer"] = nil | 
					
						
							|  |  |  |       post.topic.custom_fields["accepted_answer_post_id"] = nil | 
					
						
							|  |  |  |       post.topic.save! | 
					
						
							|  |  |  |       post.save! | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-06 17:28:15 +11:00
										 |  |  |       # TODO remove_action! does not allow for this type of interface | 
					
						
							|  |  |  |       if defined? UserAction::SOLVED | 
					
						
							|  |  |  |         UserAction.where( | 
					
						
							|  |  |  |           action_type: UserAction::SOLVED, | 
					
						
							|  |  |  |           target_post_id: post.id | 
					
						
							|  |  |  |         ).destroy_all | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 10:06:18 +10:00
										 |  |  |       # yank notification | 
					
						
							|  |  |  |       notification = Notification.find_by( | 
					
						
							|  |  |  |          notification_type: Notification.types[:custom], | 
					
						
							|  |  |  |          user_id: post.user_id, | 
					
						
							|  |  |  |          topic_id: post.topic_id, | 
					
						
							|  |  |  |          post_number: post.post_number | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       notification.destroy if notification | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-20 09:13:58 -05:00
										 |  |  |       DiscourseEvent.trigger(:unaccepted_solution, post) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |       render json: success_json | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-08-05 16:21:16 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def limit_accepts | 
					
						
							|  |  |  |       unless current_user.staff? | 
					
						
							|  |  |  |         RateLimiter.new(nil, "accept-hr-#{current_user.id}", 20, 1.hour).performed! | 
					
						
							|  |  |  |         RateLimiter.new(nil, "accept-min-#{current_user.id}", 4, 30.seconds).performed! | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 14:24:49 +10:00
										 |  |  |   DiscourseSolved::Engine.routes.draw do | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |     post "/accept" => "answer#accept" | 
					
						
							|  |  |  |     post "/unaccept" => "answer#unaccept" | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Discourse::Application.routes.append do | 
					
						
							| 
									
										
										
										
											2015-06-15 14:24:49 +10:00
										 |  |  |     mount ::DiscourseSolved::Engine, at: "solution" | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   TopicView.add_post_custom_fields_whitelister do |user| | 
					
						
							|  |  |  |     ["is_accepted_answer"] | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 02:41:24 +02:00
										 |  |  |   if Report.respond_to?(:add_report) | 
					
						
							|  |  |  |     AdminDashboardData::GLOBAL_REPORTS << "accepted_solutions" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Report.add_report("accepted_solutions") do |report| | 
					
						
							|  |  |  |       report.data = [] | 
					
						
							|  |  |  |       accepted_solutions = TopicCustomField.where(name: "accepted_answer_post_id") | 
					
						
							|  |  |  |       accepted_solutions = accepted_solutions.joins(:topic).where("topics.category_id = ?", report.category_id) if report.category_id | 
					
						
							|  |  |  |       accepted_solutions.where("topic_custom_fields.created_at >= ?", report.start_date) | 
					
						
							| 
									
										
										
										
											2017-08-02 15:09:07 +09:00
										 |  |  |         .where("topic_custom_fields.created_at <= ?", report.end_date) | 
					
						
							|  |  |  |         .group("DATE(topic_custom_fields.created_at)") | 
					
						
							|  |  |  |         .order("DATE(topic_custom_fields.created_at)") | 
					
						
							|  |  |  |         .count | 
					
						
							|  |  |  |         .each do |date, count| | 
					
						
							| 
									
										
										
										
											2015-06-25 02:41:24 +02:00
										 |  |  |         report.data << { x: date, y: count } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       report.total = accepted_solutions.count | 
					
						
							|  |  |  |       report.prev30Days = accepted_solutions.where("topic_custom_fields.created_at >= ?", report.start_date - 30.days) | 
					
						
							| 
									
										
										
										
											2017-08-02 15:09:07 +09:00
										 |  |  |         .where("topic_custom_fields.created_at <= ?", report.start_date) | 
					
						
							|  |  |  |         .count | 
					
						
							| 
									
										
										
										
											2015-06-25 02:41:24 +02:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-06 17:28:15 +11:00
										 |  |  |   if defined?(UserAction::SOLVED) | 
					
						
							|  |  |  |     require_dependency 'user_summary' | 
					
						
							|  |  |  |     class ::UserSummary | 
					
						
							|  |  |  |       def solved_count | 
					
						
							|  |  |  |         UserAction | 
					
						
							|  |  |  |           .where(user: @user) | 
					
						
							|  |  |  |           .where(action_type: UserAction::SOLVED) | 
					
						
							|  |  |  |           .count | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     require_dependency 'user_summary_serializer' | 
					
						
							|  |  |  |     class ::UserSummarySerializer | 
					
						
							|  |  |  |       attributes :solved_count | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def solved_count | 
					
						
							|  |  |  |         object.solved_count | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |   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], | 
					
						
							| 
									
										
										
										
											2017-03-08 15:21:41 +00:00
										 |  |  |           excerpt: info[2] | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |         } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def accepted_answer_post_info | 
					
						
							|  |  |  |       # TODO: we may already have it in the stream ... so bypass query here | 
					
						
							| 
									
										
										
										
											2017-03-08 15:42:41 +00:00
										 |  |  |       postInfo = Post.where(id: accepted_answer_post_id, topic_id: object.topic.id) | 
					
						
							| 
									
										
										
										
											2017-08-02 15:09:07 +09:00
										 |  |  |         .joins(:user) | 
					
						
							|  |  |  |         .pluck('post_number', 'username', 'cooked') | 
					
						
							|  |  |  |         .first | 
					
						
							| 
									
										
										
										
											2017-05-22 17:09:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-08 15:47:18 +00:00
										 |  |  |       if postInfo | 
					
						
							| 
									
										
										
										
											2017-08-06 17:22:30 -04:00
										 |  |  |         postInfo[2] = if SiteSetting.solved_quote_length > 0
 | 
					
						
							| 
									
										
										
										
											2017-09-04 14:07:21 +02:00
										 |  |  |           PrettyText.excerpt(postInfo[2], SiteSetting.solved_quote_length, keep_emoji_images: true) | 
					
						
							| 
									
										
										
										
											2017-08-11 15:36:38 -04:00
										 |  |  |         else | 
					
						
							|  |  |  |           nil | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2017-03-08 15:47:18 +00:00
										 |  |  |         return postInfo | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def accepted_answer_post_id | 
					
						
							|  |  |  |       id = object.topic.custom_fields["accepted_answer_post_id"] | 
					
						
							| 
									
										
										
										
											2015-08-05 16:21:16 +10:00
										 |  |  |       # a bit messy but race conditions can give us an array here, avoid | 
					
						
							|  |  |  |       id && id.to_i rescue nil | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-10 06:09:20 +10: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) | 
					
						
							| 
									
										
										
										
											2015-06-19 16:08:43 +10:00
										 |  |  |       return true if SiteSetting.allow_solved_on_all_topics | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-10 06:09:20 +10:00
										 |  |  |       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? || ( | 
					
						
							| 
									
										
										
										
											2016-03-31 12:06:03 +11:00
										 |  |  |           authenticated? && ((!topic.closed? && topic.user_id == current_user.id) || | 
					
						
							|  |  |  |                             (current_user.trust_level >= SiteSetting.accept_all_solutions_trust_level)) | 
					
						
							| 
									
										
										
										
											2015-06-10 06:09:20 +10:00
										 |  |  |         ) | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10: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 | 
					
						
							| 
									
										
										
										
											2015-06-19 16:08:43 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |       if topic | 
					
						
							| 
									
										
										
										
											2016-02-17 15:58:32 -05:00
										 |  |  |         return scope.can_accept_answer?(topic) && object.post_number > 1 && !accepted_answer | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-02-17 15:58:32 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |       false | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_unaccept_answer | 
					
						
							| 
									
										
										
										
											2015-06-10 06:09:20 +10:00
										 |  |  |       topic = (topic_view && topic_view.topic) || object.topic | 
					
						
							|  |  |  |       if topic | 
					
						
							| 
									
										
										
										
											2016-02-17 15:58:32 -05:00
										 |  |  |         return scope.can_accept_answer?(topic) && (post_custom_fields["is_accepted_answer"] == 'true') | 
					
						
							| 
									
										
										
										
											2015-06-10 06:09:20 +10:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def accepted_answer | 
					
						
							| 
									
										
										
										
											2016-02-17 15:58:32 -05:00
										 |  |  |       post_custom_fields["is_accepted_answer"] == 'true' | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-06-15 16:26:40 +10:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-06-23 12:31:10 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   require_dependency 'search' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   #TODO Remove when plugin is 1.0 | 
					
						
							|  |  |  |   if Search.respond_to? :advanced_filter | 
					
						
							|  |  |  |     Search.advanced_filter(/in:solved/) do |posts| | 
					
						
							|  |  |  |       posts.where("topics.id IN (
 | 
					
						
							|  |  |  |         SELECT tc.topic_id | 
					
						
							|  |  |  |         FROM topic_custom_fields tc | 
					
						
							|  |  |  |         WHERE tc.name = 'accepted_answer_post_id' AND | 
					
						
							|  |  |  |                         tc.value IS NOT NULL | 
					
						
							|  |  |  |         )")
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-06-23 12:56:22 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Search.advanced_filter(/in:unsolved/) do |posts| | 
					
						
							|  |  |  |       posts.where("topics.id NOT IN (
 | 
					
						
							|  |  |  |         SELECT tc.topic_id | 
					
						
							|  |  |  |         FROM topic_custom_fields tc | 
					
						
							|  |  |  |         WHERE tc.name = 'accepted_answer_post_id' AND | 
					
						
							|  |  |  |                         tc.value IS NOT NULL | 
					
						
							|  |  |  |         )")
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-06-23 12:31:10 +10:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-06-15 16:26:40 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-27 19:51:50 +00:00
										 |  |  |   if Discourse.has_needed_version?(Discourse::VERSION::STRING, '1.8.0.beta6') | 
					
						
							|  |  |  |     require_dependency 'topic_query' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TopicQuery.add_custom_filter(:solved) do |results, topic_query| | 
					
						
							| 
									
										
										
										
											2017-02-28 15:22:07 +00:00
										 |  |  |       if topic_query.options[:solved] == 'yes' | 
					
						
							| 
									
										
										
										
											2017-02-27 19:51:50 +00:00
										 |  |  |         results = results.where("topics.id IN (
 | 
					
						
							|  |  |  |           SELECT tc.topic_id | 
					
						
							|  |  |  |           FROM topic_custom_fields tc | 
					
						
							|  |  |  |           WHERE tc.name = 'accepted_answer_post_id' AND | 
					
						
							|  |  |  |                           tc.value IS NOT NULL | 
					
						
							|  |  |  |           )")
 | 
					
						
							| 
									
										
										
										
											2017-02-28 15:22:07 +00:00
										 |  |  |       elsif topic_query.options[:solved] == 'no' | 
					
						
							| 
									
										
										
										
											2017-02-27 19:51:50 +00:00
										 |  |  |         results = results.where("topics.id NOT IN (
 | 
					
						
							|  |  |  |           SELECT tc.topic_id | 
					
						
							|  |  |  |           FROM topic_custom_fields tc | 
					
						
							|  |  |  |           WHERE tc.name = 'accepted_answer_post_id' AND | 
					
						
							|  |  |  |                           tc.value IS NOT NULL | 
					
						
							|  |  |  |           )")
 | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       results | 
					
						
							| 
									
										
										
										
											2017-02-27 18:19:21 +00:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 16:26:40 +10:00
										 |  |  |   require_dependency 'topic_list_item_serializer' | 
					
						
							| 
									
										
										
										
											2017-04-19 01:03:50 -03:00
										 |  |  |   require_dependency 'listable_topic_serializer' | 
					
						
							| 
									
										
										
										
											2015-06-15 16:26:40 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   class ::TopicListItemSerializer | 
					
						
							| 
									
										
										
										
											2017-02-27 21:19:58 +00:00
										 |  |  |     attributes :has_accepted_answer, :can_have_answer | 
					
						
							| 
									
										
										
										
											2015-06-15 16:26:40 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def has_accepted_answer | 
					
						
							| 
									
										
										
										
											2016-05-03 00:40:01 +05:30
										 |  |  |       object.custom_fields["accepted_answer_post_id"] ? true : false | 
					
						
							| 
									
										
										
										
											2015-06-15 16:26:40 +10:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2017-02-27 15:00:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-27 21:19:58 +00:00
										 |  |  |     def can_have_answer | 
					
						
							|  |  |  |       return true if SiteSetting.allow_solved_on_all_topics | 
					
						
							| 
									
										
										
										
											2017-03-06 01:34:29 +00:00
										 |  |  |       return false if object.closed || object.archived | 
					
						
							| 
									
										
										
										
											2017-02-27 21:19:58 +00:00
										 |  |  |       return scope.allow_accepted_answers_on_category?(object.category_id) | 
					
						
							| 
									
										
										
										
											2017-02-27 15:00:04 +00:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2017-02-27 21:26:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def include_can_have_answer? | 
					
						
							|  |  |  |       SiteSetting.empty_box_on_unsolved | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-06-15 16:26:40 +10:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-19 00:55:15 -03:00
										 |  |  |   class ::ListableTopicSerializer | 
					
						
							|  |  |  |     attributes :has_accepted_answer, :can_have_answer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def has_accepted_answer | 
					
						
							|  |  |  |       object.custom_fields["accepted_answer_post_id"] ? true : false | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_have_answer | 
					
						
							|  |  |  |       return true if SiteSetting.allow_solved_on_all_topics | 
					
						
							|  |  |  |       return false if object.closed || object.archived | 
					
						
							|  |  |  |       return scope.allow_accepted_answers_on_category?(object.category_id) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def include_can_have_answer? | 
					
						
							|  |  |  |       SiteSetting.empty_box_on_unsolved | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-05 16:21:16 +10:00
										 |  |  |   TopicList.preloaded_custom_fields << "accepted_answer_post_id" if TopicList.respond_to? :preloaded_custom_fields | 
					
						
							| 
									
										
										
										
											2015-06-15 16:26:40 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-01 17:25:54 +09:00
										 |  |  |   if CategoryList.respond_to?(:preloaded_topic_custom_fields) | 
					
						
							|  |  |  |     CategoryList.preloaded_topic_custom_fields << "accepted_answer_post_id" | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 15:45:19 +10:00
										 |  |  | end |