mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-23 05:03:04 +08:00
What is the problem? - `PostActionsController#create` passes `params[:is_warning]` to `PostActionCreator` without casting it — JSON requests preserve the boolean type, so `is_warning` arrives as Ruby `true` instead of string `"true"` - `PostActionCreator#perform` calls `#post_can_act?`, which delegates to `PostGuardian#post_can_act?` with `is_warning: @is_warning` - The guardian compares `opts[:is_warning] == "true"` — since Ruby's `true == "true"` is `false`, the non-staff check does not trigger and `#post_can_act?` returns `true` - With the authorization check passed, `#perform` continues to `#create_message_creator`, which forwards `is_warning: @is_warning` to `PostCreator` and ultimately `TopicCreator#create_warning` — where boolean `true` is truthy, creating a `UserWarning` record What is the solution? - Cast `params[:is_warning]` with `ActiveModel::Type::Boolean.new.cast` in `PostActionsController#create` before passing it to `PostActionCreator`, matching the pattern already used in `PostsController` - Simplify the guardian check in `PostGuardian#post_can_act?` from a string comparison to a direct truthiness check, since the controller now guarantees a proper boolean - Add request specs covering both form-encoded and JSON boolean variants of the `is_warning` param for both `true` and `false` values
90 lines
2.3 KiB
Ruby
Vendored
90 lines
2.3 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
class PostActionsController < ApplicationController
|
|
requires_login
|
|
|
|
before_action :fetch_post_from_params
|
|
before_action :fetch_post_action_type_id_from_params
|
|
|
|
def create
|
|
raise Discourse::NotFound if @post.blank?
|
|
|
|
creator =
|
|
PostActionCreator.new(
|
|
current_user,
|
|
@post,
|
|
@post_action_type_id,
|
|
is_warning: ActiveModel::Type::Boolean.new.cast(params[:is_warning]),
|
|
message: params[:message],
|
|
take_action: params[:take_action] == "true",
|
|
flag_topic: params[:flag_topic] == "true",
|
|
queue_for_review: params[:queue_for_review] == "true",
|
|
)
|
|
result = creator.perform
|
|
|
|
if result.failed?
|
|
render_json_error(result)
|
|
else
|
|
# We need to reload or otherwise we are showing the old values on the front end
|
|
@post.reload
|
|
|
|
if @post_action_type_id == PostActionType.types[:like]
|
|
limiter = result.post_action.post_action_rate_limiter
|
|
response.headers["Discourse-Actions-Remaining"] = limiter.remaining.to_s
|
|
response.headers["Discourse-Actions-Max"] = limiter.max.to_s
|
|
end
|
|
render_post_json(@post, add_raw: false)
|
|
end
|
|
end
|
|
|
|
def destroy
|
|
result =
|
|
PostActionDestroyer.new(
|
|
current_user,
|
|
Post.find_by(id: params[:id].to_i),
|
|
@post_action_type_id,
|
|
).perform
|
|
|
|
if result.failed?
|
|
render_json_error(result)
|
|
else
|
|
if !guardian.can_see_post?(result.post)
|
|
head :no_content
|
|
else
|
|
render_post_json(result.post, add_raw: false)
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def fetch_post_from_params
|
|
params.require(:id)
|
|
|
|
flag_topic = params[:flag_topic]
|
|
flag_topic = flag_topic && (flag_topic == true || flag_topic == "true")
|
|
|
|
post_id =
|
|
if flag_topic
|
|
begin
|
|
Topic.find(params[:id]).posts.first.id
|
|
rescue StandardError
|
|
raise Discourse::NotFound
|
|
end
|
|
else
|
|
params[:id]
|
|
end
|
|
|
|
finder = Post.where(id: post_id)
|
|
|
|
# Include deleted posts if the user is a staff
|
|
finder = finder.with_deleted if guardian.is_staff?
|
|
|
|
@post = finder.first
|
|
end
|
|
|
|
def fetch_post_action_type_id_from_params
|
|
params.require(:post_action_type_id)
|
|
@post_action_type_id = params[:post_action_type_id].to_i
|
|
end
|
|
end
|