mirror of
https://github.com/discourse/discourse-solved.git
synced 2026-11-01 01:48:36 -05:00
DEV: Fix new Rubocop offenses
This commit is contained in:
committed by
Loïc Guitaut
parent
b50b118a79
commit
4c6ddcf08d
+30
-6
@@ -1,11 +1,30 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (7.1.3.2)
|
||||
base64
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
connection_pool (>= 2.2.5)
|
||||
drb
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
mutex_m
|
||||
tzinfo (~> 2.0)
|
||||
ast (2.4.2)
|
||||
base64 (0.2.0)
|
||||
bigdecimal (3.1.6)
|
||||
concurrent-ruby (1.2.3)
|
||||
connection_pool (2.4.1)
|
||||
drb (2.2.1)
|
||||
i18n (1.14.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
json (2.7.1)
|
||||
language_server-protocol (3.17.0.3)
|
||||
minitest (5.22.2)
|
||||
mutex_m (0.2.0)
|
||||
parallel (1.24.0)
|
||||
parser (3.3.0.4)
|
||||
parser (3.3.0.5)
|
||||
ast (~> 2.4.1)
|
||||
racc
|
||||
prettier_print (1.2.1)
|
||||
@@ -13,7 +32,7 @@ GEM
|
||||
rainbow (3.1.1)
|
||||
regexp_parser (2.9.0)
|
||||
rexml (3.2.6)
|
||||
rubocop (1.60.0)
|
||||
rubocop (1.61.0)
|
||||
json (~> 2.3)
|
||||
language_server-protocol (>= 3.17.0)
|
||||
parallel (~> 1.10)
|
||||
@@ -24,22 +43,27 @@ GEM
|
||||
rubocop-ast (>= 1.30.0, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.30.0)
|
||||
parser (>= 3.2.1.0)
|
||||
rubocop-ast (1.31.1)
|
||||
parser (>= 3.3.0.4)
|
||||
rubocop-capybara (2.20.0)
|
||||
rubocop (~> 1.41)
|
||||
rubocop-discourse (3.6.0)
|
||||
rubocop-discourse (3.7.1)
|
||||
activesupport (>= 6.1)
|
||||
rubocop (>= 1.59.0)
|
||||
rubocop-capybara (>= 2.0.0)
|
||||
rubocop-factory_bot (>= 2.0.0)
|
||||
rubocop-rspec (>= 2.25.0)
|
||||
rubocop-factory_bot (2.25.1)
|
||||
rubocop (~> 1.41)
|
||||
rubocop-rspec (2.26.1)
|
||||
rubocop-rspec (2.27.1)
|
||||
rubocop (~> 1.40)
|
||||
rubocop-capybara (~> 2.17)
|
||||
rubocop-factory_bot (~> 2.22)
|
||||
ruby-progressbar (1.13.0)
|
||||
syntax_tree (6.2.0)
|
||||
prettier_print (>= 1.2.0)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
unicode-display_width (2.5.0)
|
||||
|
||||
PLATFORMS
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class DiscourseSolved::AnswerController < ::ApplicationController
|
||||
requires_plugin DiscourseSolved::PLUGIN_NAME
|
||||
|
||||
def accept
|
||||
limit_accepts
|
||||
|
||||
post = Post.find(params[:id].to_i)
|
||||
|
||||
topic = post.topic
|
||||
topic ||= Topic.with_deleted.find(post.topic_id) if guardian.is_staff?
|
||||
|
||||
guardian.ensure_can_accept_answer!(topic, post)
|
||||
|
||||
DiscourseSolved.accept_answer!(post, current_user, topic: topic)
|
||||
|
||||
render json: success_json
|
||||
end
|
||||
|
||||
def unaccept
|
||||
limit_accepts
|
||||
|
||||
post = Post.find(params[:id].to_i)
|
||||
|
||||
topic = post.topic
|
||||
topic ||= Topic.with_deleted.find(post.topic_id) if guardian.is_staff?
|
||||
|
||||
guardian.ensure_can_accept_answer!(topic, post)
|
||||
|
||||
DiscourseSolved.unaccept_answer!(post, topic: topic)
|
||||
|
||||
render json: success_json
|
||||
end
|
||||
|
||||
def limit_accepts
|
||||
return if 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
|
||||
@@ -0,0 +1,85 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class DiscourseSolved::BeforeHeadClose
|
||||
attr_reader :controller
|
||||
|
||||
def initialize(controller)
|
||||
@controller = controller
|
||||
end
|
||||
|
||||
def html
|
||||
return "" if !controller.instance_of? TopicsController
|
||||
|
||||
topic_view = controller.instance_variable_get(:@topic_view)
|
||||
topic = topic_view&.topic
|
||||
return "" if !topic
|
||||
# note, we have canonicals so we only do this for page 1 at the moment
|
||||
# it can get confusing to have this on every page and it should make page 1
|
||||
# a bit more prominent + cut down on pointless work
|
||||
|
||||
return "" if SiteSetting.solved_add_schema_markup == "never"
|
||||
|
||||
allowed =
|
||||
controller.guardian.allow_accepted_answers?(topic.category_id, topic.tags.pluck(:name))
|
||||
return "" if !allowed
|
||||
|
||||
first_post = topic_view.posts&.first
|
||||
return "" if first_post&.post_number != 1
|
||||
|
||||
question_json = {
|
||||
"@type" => "Question",
|
||||
"name" => topic.title,
|
||||
"text" => get_schema_text(first_post),
|
||||
"upvoteCount" => first_post.like_count,
|
||||
"answerCount" => 0,
|
||||
"datePublished" => topic.created_at,
|
||||
"author" => {
|
||||
"@type" => "Person",
|
||||
"name" => topic.user&.username,
|
||||
"url" => topic.user&.full_url,
|
||||
},
|
||||
}
|
||||
|
||||
if accepted_answer =
|
||||
Post.find_by(
|
||||
id: topic.custom_fields[::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD],
|
||||
)
|
||||
question_json["answerCount"] = 1
|
||||
question_json[:acceptedAnswer] = {
|
||||
"@type" => "Answer",
|
||||
"text" => get_schema_text(accepted_answer),
|
||||
"upvoteCount" => accepted_answer.like_count,
|
||||
"datePublished" => accepted_answer.created_at,
|
||||
"url" => accepted_answer.full_url,
|
||||
"author" => {
|
||||
"@type" => "Person",
|
||||
"name" => accepted_answer.user&.username,
|
||||
"url" => accepted_answer.user&.full_url,
|
||||
},
|
||||
}
|
||||
else
|
||||
return "" if SiteSetting.solved_add_schema_markup == "answered only"
|
||||
end
|
||||
|
||||
[
|
||||
'<script type="application/ld+json">',
|
||||
MultiJson
|
||||
.dump(
|
||||
"@context" => "http://schema.org",
|
||||
"@type" => "QAPage",
|
||||
"name" => topic&.title,
|
||||
"mainEntity" => question_json,
|
||||
)
|
||||
.gsub("</", "<\\/")
|
||||
.html_safe,
|
||||
"</script>",
|
||||
].join("")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_schema_text(post)
|
||||
post.excerpt(nil, keep_onebox_body: true).presence ||
|
||||
post.excerpt(nil, keep_onebox_body: true, keep_quotes: true)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DiscourseSolved::CategoryExtension
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
prepended { after_save :reset_accepted_cache, if: -> { SiteSetting.solved_enabled? } }
|
||||
|
||||
private
|
||||
|
||||
def reset_accepted_cache
|
||||
::DiscourseSolved::AcceptedAnswerCache.reset_accepted_answer_cache
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DiscourseSolved::PostSerializerExtension
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
private
|
||||
|
||||
def topic
|
||||
topic_view&.topic || object.topic
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DiscourseSolved::TopicPostersSummaryExtension
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def descriptions_by_id
|
||||
if !defined?(@descriptions_by_id)
|
||||
super(ids: old_user_ids)
|
||||
|
||||
if id = topic.accepted_answer_user_id
|
||||
@descriptions_by_id[id] ||= []
|
||||
@descriptions_by_id[id] << I18n.t(:accepted_answer)
|
||||
end
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def last_poster_is_topic_creator?
|
||||
super || topic.accepted_answer_user_id == topic.last_post_user_id
|
||||
end
|
||||
|
||||
def user_ids
|
||||
if id = topic.accepted_answer_user_id
|
||||
super.insert(1, id)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,54 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DiscourseSolved::TopicViewSerializerExtension
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
prepended { attributes :accepted_answer }
|
||||
|
||||
def include_accepted_answer?
|
||||
SiteSetting.solved_enabled? && accepted_answer_post_id
|
||||
end
|
||||
|
||||
def accepted_answer
|
||||
if info = accepted_answer_post_info
|
||||
{ post_number: info[0], username: info[1], excerpt: info[2], name: info[3] }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def accepted_answer_post_info
|
||||
post_info =
|
||||
if post = object.posts.find { |p| p.post_number == accepted_answer_post_id }
|
||||
[post.post_number, post.user.username, post.cooked, post.user.name]
|
||||
else
|
||||
Post
|
||||
.where(id: accepted_answer_post_id, topic_id: object.topic.id)
|
||||
.joins(:user)
|
||||
.pluck("post_number", "username", "cooked", "name")
|
||||
.first
|
||||
end
|
||||
|
||||
if post_info
|
||||
post_info[2] = if SiteSetting.solved_quote_length > 0
|
||||
PrettyText.excerpt(post_info[2], SiteSetting.solved_quote_length, keep_emoji_images: true)
|
||||
else
|
||||
nil
|
||||
end
|
||||
|
||||
post_info[3] = nil if !SiteSetting.enable_names || !SiteSetting.display_name_on_posts
|
||||
|
||||
post_info
|
||||
end
|
||||
end
|
||||
|
||||
def accepted_answer_post_id
|
||||
id = object.topic.custom_fields[::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD]
|
||||
# a bit messy but race conditions can give us an array here, avoid
|
||||
begin
|
||||
id && id.to_i
|
||||
rescue StandardError
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DiscourseSolved::UserSummaryExtension
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def solved_count
|
||||
UserAction.where(user: @user).where(action_type: UserAction::SOLVED).count
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DiscourseSolved::WebHookExtension
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
def enqueue_solved_hooks(event, post, payload = nil)
|
||||
if active_web_hooks(event).exists? && post.present?
|
||||
payload ||= WebHook.generate_payload(:post, post)
|
||||
|
||||
WebHook.enqueue_hooks(
|
||||
:solved,
|
||||
event,
|
||||
id: post.id,
|
||||
category_id: post.topic&.category_id,
|
||||
tag_ids: post.topic&.tags&.pluck(:id),
|
||||
payload: payload,
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -6,8 +6,8 @@ require "composer_messages_finder"
|
||||
|
||||
describe ComposerMessagesFinder do
|
||||
describe ".check_topic_is_solved" do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
fab!(:topic) { Fabricate(:topic) }
|
||||
fab!(:user)
|
||||
fab!(:topic)
|
||||
fab!(:post) { Fabricate(:post, topic: topic, user: Fabricate(:user)) }
|
||||
|
||||
before { SiteSetting.disable_solved_education_message = false }
|
||||
|
||||
@@ -41,7 +41,7 @@ describe PostRevisor do
|
||||
fab!(:tag1) { Fabricate(:tag) }
|
||||
fab!(:tag2) { Fabricate(:tag) }
|
||||
|
||||
fab!(:topic) { Fabricate(:topic) }
|
||||
fab!(:topic)
|
||||
let(:post) { Fabricate(:post, topic: topic) }
|
||||
|
||||
it "sets the refresh option after adding an allowed tag" do
|
||||
|
||||
@@ -340,7 +340,7 @@ RSpec.describe "Managing Posts solved status" do
|
||||
end
|
||||
|
||||
context "with group moderators" do
|
||||
fab!(:group_user) { Fabricate(:group_user) }
|
||||
fab!(:group_user)
|
||||
let(:user_gm) { group_user.user }
|
||||
let(:group) { group_user.group }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user