Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEV: Fix new Rubocop offenses #282

Merged
merged 1 commit into from Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 30 additions & 6 deletions Gemfile.lock
@@ -1,19 +1,38 @@
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)
racc (1.7.3)
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)
Expand All @@ -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
Expand Down
41 changes: 41 additions & 0 deletions app/controllers/answer_controller.rb
@@ -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
85 changes: 85 additions & 0 deletions app/lib/before_head_close.rb
@@ -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
13 changes: 13 additions & 0 deletions app/lib/category_extension.rb
@@ -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
11 changes: 11 additions & 0 deletions app/lib/post_serializer_extension.rb
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module DiscourseSolved::PostSerializerExtension
extend ActiveSupport::Concern

private

def topic
topic_view&.topic || object.topic
end
end
30 changes: 30 additions & 0 deletions app/lib/topic_posters_summary_extension.rb
@@ -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
54 changes: 54 additions & 0 deletions app/lib/topic_view_serializer_extension.rb
@@ -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
9 changes: 9 additions & 0 deletions app/lib/user_summary_extension.rb
@@ -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
22 changes: 22 additions & 0 deletions app/lib/web_hook_extension.rb
@@ -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