DEV: Remove code deprecated by the new Reviewable API (#8023)

* Remove flag hooks and endpoints

* Remove #reject_bulk for users

* Remove code for quued_posts_controller
This commit is contained in:
Roman Rizzi 2019-08-26 10:33:26 -03:00 committed by GitHub
parent 8841563f8a
commit 3259ea60a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 0 additions and 770 deletions

View File

@ -1,19 +0,0 @@
# frozen_string_literal: true
require_dependency 'flag_query'
class Admin::FlaggedTopicsController < Admin::AdminController
def index
result = FlagQuery.flagged_topics
render_json_dump(
{
flagged_topics: serialize_data(result[:flagged_topics], FlaggedTopicSummarySerializer),
users: serialize_data(result[:users], BasicUserSerializer),
},
rest_serializer: true
)
end
end

View File

@ -1,146 +0,0 @@
# frozen_string_literal: true
require 'flag_query'
class Admin::FlagsController < Admin::AdminController
def self.flags_per_page
10
end
def index
Discourse.deprecate("FlagsController#index has been deprecated, please use the Reviewable API instead", since: "2.3.0beta5", drop_from: "2.4")
offset = params[:offset].to_i
per_page = Admin::FlagsController.flags_per_page
posts, topics, users, post_actions, total_rows = FlagQuery.flagged_posts_report(
current_user,
filter: params[:filter],
user_id: params[:user_id],
offset: offset,
topic_id: params[:topic_id],
per_page: per_page
)
meta = {
types: {
disposed_by: 'user'
}
}
next_segment = offset + per_page
if (total_rows || 0) > next_segment
meta[:total_rows_flagged_posts] = total_rows
meta[:load_more_flagged_posts] = admin_flags_filtered_path(
filter: params[:filter],
offset: next_segment,
topic_id: params[:topic_id]
)
end
render_json_dump(
{
flagged_posts: posts,
topics: serialize_data(topics, FlaggedTopicSerializer),
users: serialize_data(users, FlaggedUserSerializer),
post_actions: post_actions
},
rest_serializer: true,
meta: meta
)
end
def agree
Discourse.deprecate("FlagsController#agree has been deprecated, please use the Reviewable API instead", since: "2.3.0beta5", drop_from: "2.4")
params.permit(:id, :action_on_post)
post = Post.find(params[:id])
DiscourseEvent.trigger(
:before_staff_flag_action,
type: 'agree',
post: post,
action_on_post: params[:action_on_post],
user: current_user
)
reviewable = post.reviewable_flag
return render_json_error(I18n.t("flags.errors.already_handled"), status: 409) if reviewable.blank?
keep_post = ['silenced', 'suspended', 'keep'].include?(params[:action_on_post])
delete_post = params[:action_on_post] == "delete"
restore_post = params[:action_on_post] == "restore"
if delete_post
# PostDestroy automatically agrees with flags
destroy_post(post)
elsif restore_post
reviewable.perform(current_user, :agree_and_restore)
else
reviewable.perform(
current_user,
:agree_and_keep,
post_was_deleted: delete_post,
hide_post: !keep_post
)
end
render body: nil
end
def disagree
Discourse.deprecate("FlagsController#disagree has been deprecated, please use the Reviewable API instead", since: "2.3.0beta5", drop_from: "2.4")
params.permit(:id)
post = Post.find(params[:id])
if reviewable = post.reviewable_flag
DiscourseEvent.trigger(
:before_staff_flag_action,
type: 'disagree',
post: post,
user: current_user
)
if post.hidden?
reviewable.perform(current_user, :disagree_and_restore)
else
reviewable.perform(current_user, :disagree)
end
end
render body: nil
end
def defer
Discourse.deprecate("FlagsController#defer has been deprecated, please use the Reviewable API instead", since: "2.3.0beta5", drop_from: "2.4")
params.permit(:id, :delete_post)
post = Post.find(params[:id])
if reviewable = post.reviewable_flag
DiscourseEvent.trigger(
:before_staff_flag_action,
type: 'defer',
post: post,
user: current_user
)
reviewable.perform(current_user, :ignore, post_was_deleted: params[:delete_post])
destroy_post(post) if params[:delete_post]
end
render body: nil
end
private
def destroy_post(post)
if post.is_first_post?
topic = Topic.find_by(id: post.topic_id)
guardian.ensure_can_delete!(topic) if topic.present?
end
PostDestroyer.new(current_user, post).destroy
end
end

View File

@ -370,23 +370,6 @@ class Admin::UsersController < Admin::AdminController
)
end
# Kept for backwards compatibility, but is replaced by the Reviewable Queue
def reject_bulk
Discourse.deprecate("AdminUsersController#reject_bulk is deprecated. Please use the Reviewable API instead.", since: "2.3.0beta5", drop_from: "2.4")
success_count = 0
d = UserDestroyer.new(current_user)
User.where(id: params[:users]).each do |u|
success_count += 1 if guardian.can_delete_user?(u) && d.destroy(u, params.slice(:context)) rescue UserDestroyer::PostsExistError
end
render json: {
success: success_count,
failed: (params[:users].try(:size) || 0) - success_count
}
end
def disable_second_factor
guardian.ensure_can_disable_second_factor!(@user)
user_second_factor = @user.user_second_factors

View File

@ -1,72 +0,0 @@
# frozen_string_literal: true
require_dependency 'queued_post_serializer'
class QueuedPostsController < ApplicationController
before_action :ensure_staff
def index
Discourse.deprecate("QueuedPostController#index is deprecated. Please use the Reviewable API instead.", since: "2.3.0beta5", drop_from: "2.4")
status = params[:state] || 'pending'
status = 'pending' if status == 'new'
reviewables = Reviewable.list_for(current_user, status: status.to_sym, type: ReviewableQueuedPost.name)
render_serialized(reviewables,
QueuedPostSerializer,
root: :queued_posts,
rest_serializer: true,
refresh_queued_posts: "/queued_posts?status=new")
end
def update
Discourse.deprecate("QueuedPostController#update is deprecated. Please use the Reviewable API instead.", since: "2.3.0beta5", drop_from: "2.4")
reviewable = Reviewable.find_by(id: params[:id])
raise Discourse::NotFound if reviewable.blank?
update_params = params[:queued_post]
reviewable.payload['raw'] = update_params[:raw] if update_params[:raw].present?
if reviewable.topic_id.blank? && update_params[:state].blank?
reviewable.payload['title'] = update_params[:title] if update_params[:title].present?
reviewable.payload['tags'] = update_params[:tags]
reviewable.category_id = update_params[:category_id].to_i if update_params[:category_id].present?
end
reviewable.save(validate: false)
state = update_params[:state]
begin
if state == 'approved'
reviewable.perform(current_user, :approve_post)
elsif state == 'rejected'
reviewable.perform(current_user, :reject_post)
if update_params[:delete_user] == 'true' && guardian.can_delete_user?(reviewable.created_by)
UserDestroyer.new(current_user).destroy(reviewable.created_by, user_deletion_opts)
end
end
rescue StandardError => e
return render_json_error e.message
end
render_serialized(reviewable, QueuedPostSerializer, root: :queued_posts)
end
private
def user_deletion_opts
base = {
context: I18n.t('queue.delete_reason', performed_by: current_user.username),
delete_posts: true,
delete_as_spammer: true
}
if Rails.env.production? && ENV["Staging"].nil?
base.merge!(block_email: true, block_ip: true)
end
base
end
end

View File

@ -439,25 +439,6 @@ class User < ActiveRecord::Base
!skip_email_validation && !staged?
end
# Approve this user
def approve(approved_by, send_mail = true)
Discourse.deprecate("User#approve is deprecated. Please use the Reviewable API instead.", output_in_test: true, since: "2.3.0beta5", drop_from: "2.4")
# Backwards compatibility - in case plugins or something is using the old API which accepted
# either a Number or object. Probably should remove at some point
approved_by = User.find_by(id: approved_by) if approved_by.is_a?(Numeric)
if reviewable_user = ReviewableUser.find_by(target: self)
result = reviewable_user.perform(approved_by, :approve_user, send_email: send_mail)
if result.success?
Reviewable.set_approved_fields!(self, approved_by)
return true
end
end
false
end
def self.email_hash(email)
Digest::MD5.hexdigest(email.strip.downcase)
end

View File

@ -59,10 +59,6 @@ class WebHook < ActiveRecord::Base
def self.enqueue_object_hooks(type, object, event, serializer = nil)
if active_web_hooks(type).exists?
if type == :flag
Discourse.deprecate("The flags webhook is deprecated. Please use reviewable instead.")
end
payload = WebHook.generate_payload(type, object, serializer)
WebHook.enqueue_hooks(type, event,

View File

@ -74,37 +74,12 @@ end
end
end
%i(
flag_created
flag_agreed
flag_disagreed
flag_deferred
).each do |event|
DiscourseEvent.on(event) do |flag|
WebHook.enqueue_object_hooks(:flag, flag, event)
end
end
DiscourseEvent.on(:reviewable_created) do |reviewable|
WebHook.enqueue_object_hooks(:reviewable, reviewable, :reviewable_created, reviewable.serializer)
# TODO: Backwards compatibility for Queued Post webhooks. Remve in favor of Reviewable API
if reviewable.is_a?(ReviewableQueuedPost)
WebHook.enqueue_object_hooks(:queued_post, reviewable, :queued_post_created, reviewable.serializer)
end
end
DiscourseEvent.on(:reviewable_transitioned_to) do |status, reviewable|
WebHook.enqueue_object_hooks(:reviewable, reviewable, :reviewable_transitioned_to, reviewable.serializer)
# TODO: Backwards compatibility for Queued Post webhooks. Remove in favor of Reviewable API
if reviewable.is_a?(ReviewableQueuedPost)
if reviewable.approved?
WebHook.enqueue_object_hooks(:queued_post, reviewable, :approved_post, QueuedPostSerializer)
elsif reviewable.rejected?
WebHook.enqueue_object_hooks(:queued_post, reviewable, :rejected_post, QueuedPostSerializer)
end
end
end
DiscourseEvent.on(:notification_created) do |notification|

View File

@ -107,7 +107,6 @@ Discourse::Application.routes.draw do
delete "delete-others-with-same-ip" => "users#delete_other_accounts_with_same_ip"
get "total-others-with-same-ip" => "users#total_other_accounts_with_same_ip"
put "approve-bulk" => "users#approve_bulk"
delete "reject-bulk" => "users#reject_bulk"
end
delete "penalty_history", constraints: AdminConstraint.new
put "suspend"
@ -199,14 +198,6 @@ Discourse::Application.routes.draw do
get "customize/embedding" => "embedding#show", constraints: AdminConstraint.new
put "customize/embedding" => "embedding#update", constraints: AdminConstraint.new
get "flags" => "flags#index"
get "flags/:filter" => "flags#index", as: 'flags_filtered'
get "flags/topics/:topic_id" => "flags#index"
post "flags/agree/:id" => "flags#agree"
post "flags/disagree/:id" => "flags#disagree"
post "flags/defer/:id" => "flags#defer"
resources :flagged_topics, constraints: StaffConstraint.new
resources :themes, constraints: AdminConstraint.new
post "themes/import" => "themes#import"
@ -771,9 +762,6 @@ Discourse::Application.routes.draw do
get "/posts/:id/raw-email" => "posts#raw_email"
get "raw/:topic_id(/:post_number)" => "posts#markdown_num"
resources :queued_posts, constraints: StaffConstraint.new
get 'queued-posts' => 'queued_posts#index'
resources :invites
post "invites/upload_csv" => "invites#upload_csv"
post "invites/rescind-all" => "invites#rescind_all_invites"

View File

@ -444,70 +444,6 @@ describe WebHook do
expect(payload["id"]).to eq(tag.id)
end
# NOTE: Backwards compatibility, people should use reviewable instead
it 'should enqueue the right hooks for flag events' do
post = Fabricate(:post)
admin = Fabricate(:admin)
moderator = Fabricate(:moderator)
Fabricate(:flag_web_hook)
result = PostActionCreator.spam(admin, post)
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
expect(job_args["event_name"]).to eq("flag_created")
payload = JSON.parse(job_args["payload"])
expect(payload["id"]).to eq(result.post_action.id)
result.reviewable.perform(moderator, :agree_and_keep)
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
expect(job_args["event_name"]).to eq("flag_agreed")
payload = JSON.parse(job_args["payload"])
expect(payload["id"]).to eq(result.post_action.id)
result = PostActionCreator.spam(Fabricate(:user), post)
result.reviewable.perform(moderator, :disagree)
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
expect(job_args["event_name"]).to eq("flag_disagreed")
payload = JSON.parse(job_args["payload"])
expect(payload["id"]).to eq(result.post_action.id)
post = Fabricate(:post)
result = PostActionCreator.spam(admin, post)
result.reviewable.perform(moderator, :ignore)
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
expect(job_args["event_name"]).to eq("flag_deferred")
payload = JSON.parse(job_args["payload"])
expect(payload["id"]).to eq(result.post_action.id)
end
# NOTE: Backwards compatibility, people should use reviewable instead
it 'should enqueue the right hooks for queued post events' do
Fabricate(:queued_post_web_hook)
reviewable = Fabricate(:reviewable_queued_post)
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
expect(job_args["event_name"]).to eq("queued_post_created")
payload = JSON.parse(job_args["payload"])
expect(payload["id"]).to eq(reviewable.id)
reviewable.perform(Discourse.system_user, :approve_post)
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
expect(job_args["event_name"]).to eq("approved_post")
payload = JSON.parse(job_args["payload"])
expect(payload["id"]).to eq(reviewable.id)
reviewable.perform(Discourse.system_user, :reject_post)
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
expect(job_args["event_name"]).to eq("rejected_post")
payload = JSON.parse(job_args["payload"])
expect(payload["id"]).to eq(reviewable.id)
end
it 'should enqueue the right hooks for notifications' do
Fabricate(:notification_web_hook)
notification = Fabricate(:notification)

View File

@ -1,42 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Admin::FlaggedTopicsController do
fab!(:post) { Fabricate(:post) }
fab!(:user) { Fabricate(:user) }
before do
PostActionCreator.spam(user, post)
end
fab!(:flag) { Fabricate(:flag) }
shared_examples "successfully retrieve list of flagged topics" do
it "returns a list of flagged topics" do
get "/admin/flagged_topics.json"
expect(response.status).to eq(200)
data = ::JSON.parse(response.body)
expect(data['flagged_topics']).to be_present
expect(data['users']).to be_present
end
end
context "as admin" do
before do
sign_in(Fabricate(:admin))
end
include_examples "successfully retrieve list of flagged topics"
end
context "as moderator" do
before do
sign_in(Fabricate(:moderator))
end
include_examples "successfully retrieve list of flagged topics"
end
end

View File

@ -1,138 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Admin::FlagsController do
fab!(:user) { Fabricate(:user) }
fab!(:admin) { Fabricate(:admin) }
fab!(:post_1) { Fabricate(:post) }
fab!(:category) { Fabricate(:category) }
fab!(:first_post) { Fabricate(:post, post_number: 1) }
before do
sign_in(admin)
end
context '#index' do
it 'should return the right response when nothing is flagged' do
get '/admin/flags.json'
expect(response.status).to eq(200)
data = ::JSON.parse(response.body)
expect(data["users"]).to eq([])
expect(data["flagged_posts"]).to eq([])
end
it 'should return the right response' do
PostActionCreator.create(user, post_1, :spam)
get '/admin/flags.json'
expect(response.status).to eq(200)
data = ::JSON.parse(response.body)
expect(data["users"].length).to eq(2)
expect(data["flagged_posts"].length).to eq(1)
end
end
context '#agree' do
it 'should raise a reasonable error if a flag was deferred and then someone else agreed' do
Jobs.run_immediately!
reviewable = PostActionCreator.spam(user, post_1).reviewable
post "/admin/flags/defer/#{post_1.id}.json"
expect(response.status).to eq(200)
expect(reviewable.reload).to be_ignored
post "/admin/flags/agree/#{post_1.id}.json", params: { action_on_post: 'keep' }
# 409 means conflict which is what is happening here
expect(response.status).to eq(409)
error = JSON.parse(response.body)["errors"].first
expect(error).to eq(I18n.t("flags.errors.already_handled"))
end
it 'should be able to agree and keep content' do
Jobs.run_immediately!
result = PostActionCreator.spam(user, post_1)
reviewable = result.reviewable
post "/admin/flags/agree/#{post_1.id}.json", params: { action_on_post: 'keep' }
expect(response.status).to eq(200)
expect(reviewable.reload).to be_approved
approve_history = reviewable.reviewable_histories.where(
created_by: admin,
reviewable_history_type: ReviewableHistory.types[:transitioned],
status: Reviewable.statuses[:approved]
)
expect(approve_history).to be_present
expect(user.user_stat.reload.flags_agreed).to eq(1)
post_1.reload
expect(post_1.deleted_at).to eq(nil)
end
it 'should be able to hide spam' do
SiteSetting.allow_user_locale = true
Jobs.run_immediately!
post_action = PostActionCreator.new(user, post_1, PostActionType.types[:spam], message: 'bad').perform.post_action
admin.update!(locale: 'ja')
post "/admin/flags/agree/#{post_1.id}.json", params: { action_on_post: 'delete' }
expect(response.status).to eq(200)
post_action.reload
expect(post_action.agreed_by_id).to eq(admin.id)
expect(user.user_stat.reload.flags_agreed).to eq(1)
agree_post = Topic.joins(:topic_allowed_users).where('topic_allowed_users.user_id = ?', user.id).order(:id).last.posts.last
expect(agree_post.raw).to eq(I18n.with_locale(:en) { I18n.t('flags_dispositions.agreed_and_deleted') })
post_1.reload
expect(post_1.deleted_at).to be_present
end
it 'should not delete category topic' do
Jobs.run_immediately!
category.update_column(:topic_id, first_post.topic_id)
PostActionCreator.new(user, first_post, PostActionType.types[:spam], message: 'bad').perform
post "/admin/flags/agree/#{first_post.id}.json", params: { action_on_post: 'delete' }
expect(response.status).to eq(403)
first_post.reload
expect(first_post.deleted_at).to eq(nil)
end
end
context '#disagree' do
it "unhides the post and unsilences the user if disagreed" do
Reviewable.set_priorities(high: 1.0)
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:low]
SiteSetting.num_users_to_silence_new_user = 1
new_user = Fabricate(:newuser)
new_post = create_post(user: new_user)
PostActionCreator.spam(Fabricate(:leader), new_post)
post "/admin/flags/disagree/#{new_post.id}.json"
expect(response.status).to eq(200)
new_post.reload
new_user.reload
expect(new_post).to_not be_hidden
expect(new_post.spam_count).to eq(0)
expect(new_user).to_not be_silenced
end
end
end

View File

@ -715,74 +715,6 @@ RSpec.describe Admin::UsersController do
end
end
describe '#reject_bulk' do
fab!(:reject_me) { Fabricate(:user) }
fab!(:reject_me_too) { Fabricate(:user) }
it 'does nothing without users' do
delete "/admin/users/reject-bulk.json"
expect(response.status).to eq(200)
expect(User.where(id: reject_me.id).count).to eq(1)
expect(User.where(id: reject_me_too.id).count).to eq(1)
end
it "won't delete users if not allowed" do
sign_in(user)
delete "/admin/users/reject-bulk.json", params: {
users: [reject_me.id]
}
expect(response.status).to eq(404)
expect(User.where(id: reject_me.id).count).to eq(1)
end
it "reports successes" do
delete "/admin/users/reject-bulk.json", params: {
users: [reject_me.id, reject_me_too.id]
}
expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
expect(json['success'].to_i).to eq(2)
expect(json['failed'].to_i).to eq(0)
expect(User.where(id: reject_me.id).count).to eq(0)
expect(User.where(id: reject_me_too.id).count).to eq(0)
end
context 'failures' do
it 'can handle some successes and some failures' do
stat = reject_me_too.user_stat
stat.first_post_created_at = (SiteSetting.delete_user_max_post_age.to_i + 1).days.ago
stat.post_count = 10
stat.save!
delete "/admin/users/reject-bulk.json", params: {
users: [reject_me.id, reject_me_too.id]
}
expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
expect(json['success'].to_i).to eq(1)
expect(json['failed'].to_i).to eq(1)
expect(User.where(id: reject_me.id).count).to eq(0)
expect(User.where(id: reject_me_too.id).count).to eq(1)
end
it 'reports failure due to a user still having posts' do
Fabricate(:post, user: reject_me)
delete "/admin/users/reject-bulk.json", params: {
users: [reject_me.id]
}
expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
expect(json['success'].to_i).to eq(0)
expect(json['failed'].to_i).to eq(1)
expect(User.where(id: reject_me.id).count).to eq(1)
end
end
end
describe '#ip_info' do
it "retrieves IP info" do
ip = "81.2.69.142"

View File

@ -1,144 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
require_dependency 'queued_posts_controller'
# NOTE: This controller only exists for backwards compatibility
describe QueuedPostsController do
context 'without authentication' do
it 'fails' do
get "/queued-posts.json"
expect(response).to be_forbidden
end
end
context 'as a regular user' do
before { sign_in(Fabricate(:user)) }
it 'fails' do
get "/queued-posts.json"
expect(response).to be_forbidden
end
end
context 'as an admin' do
before { sign_in(Fabricate(:moderator)) }
it 'returns the queued posts' do
get "/queued-posts.json"
expect(response.status).to eq(200)
end
end
describe '#update' do
before { sign_in(Fabricate(:moderator)) }
fab!(:qp) { Fabricate(:reviewable_queued_post) }
context 'not found' do
it 'returns json error' do
qp.destroy!
put "/queued_posts/#{qp.id}.json", params: {
queued_post: { state: 'approved' }
}
expect(response.status).to eq(404)
end
end
context 'approved' do
it 'updates the post to approved' do
put "/queued_posts/#{qp.id}.json", params: {
queued_post: { state: 'approved' }
}
expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
qp_json = json['queued_posts']
expect(qp_json['state']).to eq(2)
end
end
context 'rejected' do
it 'updates the post to rejected' do
put "/queued_posts/#{qp.id}.json", params: {
queued_post: { state: 'rejected' }
}
expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
qp_json = json['queued_posts']
expect(qp_json['state']).to eq(3)
end
end
context 'editing content' do
let(:changes) do
{
raw: 'new raw',
title: 'new title',
category_id: 10,
tags: ['new_tag']
}
end
context 'when it is a topic' do
fab!(:queued_topic) { Fabricate(:reviewable_queued_post_topic,) }
it 'updates the topic attributes' do
put "/queued_posts/#{queued_topic.id}.json", params: {
queued_post: changes
}
expect(response.status).to eq(200)
queued_topic.reload
expect(queued_topic.payload['raw']).to eq(changes[:raw])
expect(queued_topic.payload['title']).to eq(changes[:title])
expect(queued_topic.category_id).to eq(changes[:category_id])
expect(queued_topic.payload['tags']).to eq(changes[:tags])
end
it 'removes tags if not present' do
queued_topic.payload[:tags] = ['another-tag']
queued_topic.save!
put "/queued_posts/#{queued_topic.id}.json", params: {
queued_post: changes.except(:tags)
}
expect(response.status).to eq(200)
queued_topic.reload
expect(queued_topic.payload['raw']).to eq(changes[:raw])
expect(queued_topic.payload['title']).to eq(changes[:title])
expect(queued_topic.category_id).to eq(changes[:category_id])
expect(queued_topic.payload['tags']).to be_nil
end
end
context 'when it is a reply' do
fab!(:queued_reply) { Fabricate(:reviewable_queued_post) }
it 'updates the reply attributes' do
put "/queued_posts/#{queued_reply.id}.json", params: {
queued_post: changes
}
original_category = queued_reply.category_id
expect(response.status).to eq(200)
queued_reply.reload
expect(queued_reply.payload['raw']).to eq(changes[:raw])
expect(queued_reply.payload['title']).to be_nil
expect(queued_reply.category_id).to eq(original_category)
expect(queued_reply.payload['tags']).to be_nil
end
end
end
end
end