mirror of
https://github.com/discourse/discourse.git
synced 2025-05-24 13:11:18 +08:00
DEV: Add a new type_source
field to the Reviewable
model. (#31325)
This change adds a new `type_source` field to the `Reviewable` model, indicating whether the Reviewable type was registered by `core`, a plugin, or an `unknown` source. When a plugin that registered a Reviewable type is disabled, this allows us to tell the user which plugin they need to re-enable to handle any orphan reviewable items.
This commit is contained in:
@ -6,6 +6,7 @@ import { underscore } from "@ember/string";
|
|||||||
import { isPresent } from "@ember/utils";
|
import { isPresent } from "@ember/utils";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
import { REVIEWABLE_UNKNOWN_TYPE_SOURCE } from "discourse/lib/constants";
|
||||||
import discourseComputed from "discourse/lib/decorators";
|
import discourseComputed from "discourse/lib/decorators";
|
||||||
import { i18n } from "discourse-i18n";
|
import { i18n } from "discourse-i18n";
|
||||||
|
|
||||||
@ -44,6 +45,7 @@ export default class ReviewIndexController extends Controller {
|
|||||||
sort_order = null;
|
sort_order = null;
|
||||||
additional_filters = null;
|
additional_filters = null;
|
||||||
filterScoreType = null;
|
filterScoreType = null;
|
||||||
|
unknownTypeSource = REVIEWABLE_UNKNOWN_TYPE_SOURCE;
|
||||||
|
|
||||||
@discourseComputed("reviewableTypes")
|
@discourseComputed("reviewableTypes")
|
||||||
allTypes() {
|
allTypes() {
|
||||||
|
@ -117,3 +117,5 @@ export const REPORT_MODES = {
|
|||||||
inline_table: "inline_table",
|
inline_table: "inline_table",
|
||||||
storage_stats: "storage_stats",
|
storage_stats: "storage_stats",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const REVIEWABLE_UNKNOWN_TYPE_SOURCE = "unknown";
|
||||||
|
@ -39,7 +39,7 @@ export default class ReviewIndex extends DiscourseRoute {
|
|||||||
filterCategoryId: meta.category_id,
|
filterCategoryId: meta.category_id,
|
||||||
filterPriority: meta.priority,
|
filterPriority: meta.priority,
|
||||||
reviewableTypes: meta.reviewable_types,
|
reviewableTypes: meta.reviewable_types,
|
||||||
unknownReviewableTypes: meta.unknown_reviewable_types,
|
unknownReviewableTypes: meta.unknown_reviewable_types_and_sources,
|
||||||
scoreTypes: meta.score_types,
|
scoreTypes: meta.score_types,
|
||||||
filterUsername: meta.username,
|
filterUsername: meta.username,
|
||||||
filterReviewedBy: meta.reviewed_by,
|
filterReviewedBy: meta.reviewed_by,
|
||||||
|
@ -6,8 +6,19 @@
|
|||||||
}}</span>
|
}}</span>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{{#each this.unknownReviewableTypes as |type|}}
|
{{#each this.unknownReviewableTypes as |reviewable|}}
|
||||||
<li>{{type}}</li>
|
{{#if (eq reviewable.source this.unknownTypeSource)}}
|
||||||
|
<li>{{i18n
|
||||||
|
"review.unknown.reviewable_unknown_source"
|
||||||
|
reviewableType=reviewable.type
|
||||||
|
}}</li>
|
||||||
|
{{else}}
|
||||||
|
<li>{{i18n
|
||||||
|
"review.unknown.reviewable_known_source"
|
||||||
|
reviewableType=reviewable.type
|
||||||
|
pluginName=reviewable.source
|
||||||
|
}}</li>
|
||||||
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
<span class="text">{{htmlSafe
|
<span class="text">{{htmlSafe
|
||||||
|
@ -42,6 +42,7 @@ export const NOTIFICATION_TYPES = {
|
|||||||
new_features: 37,
|
new_features: 37,
|
||||||
admin_problems: 38,
|
admin_problems: 38,
|
||||||
linked_consolidated: 39,
|
linked_consolidated: 39,
|
||||||
|
chat_watched_thread: 40,
|
||||||
following: 800,
|
following: 800,
|
||||||
following_created_topic: 801,
|
following_created_topic: 801,
|
||||||
following_replied: 802,
|
following_replied: 802,
|
||||||
|
@ -74,7 +74,7 @@ class ReviewablesController < ApplicationController
|
|||||||
total_rows_reviewables: total_rows,
|
total_rows_reviewables: total_rows,
|
||||||
types: meta_types,
|
types: meta_types,
|
||||||
reviewable_types: Reviewable.types,
|
reviewable_types: Reviewable.types,
|
||||||
unknown_reviewable_types: Reviewable.unknown_types,
|
unknown_reviewable_types_and_sources: Reviewable.unknown_types_and_sources,
|
||||||
score_types:
|
score_types:
|
||||||
ReviewableScore
|
ReviewableScore
|
||||||
.types
|
.types
|
||||||
|
@ -7,6 +7,8 @@ class Reviewable < ActiveRecord::Base
|
|||||||
ReviewableUser: BasicReviewableUserSerializer,
|
ReviewableUser: BasicReviewableUserSerializer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UNKNOWN_TYPE_SOURCE = "unknown"
|
||||||
|
|
||||||
self.ignored_columns = [:reviewable_by_group_id]
|
self.ignored_columns = [:reviewable_by_group_id]
|
||||||
|
|
||||||
class UpdateConflict < StandardError
|
class UpdateConflict < StandardError
|
||||||
@ -42,6 +44,8 @@ class Reviewable < ActiveRecord::Base
|
|||||||
|
|
||||||
validates :reject_reason, length: { maximum: 2000 }
|
validates :reject_reason, length: { maximum: 2000 }
|
||||||
|
|
||||||
|
before_save :set_type_source
|
||||||
|
|
||||||
after_create { log_history(:created, created_by) }
|
after_create { log_history(:created, created_by) }
|
||||||
|
|
||||||
after_commit(on: :create) { DiscourseEvent.trigger(:reviewable_created, self) }
|
after_commit(on: :create) { DiscourseEvent.trigger(:reviewable_created, self) }
|
||||||
@ -77,6 +81,16 @@ class Reviewable < ActiveRecord::Base
|
|||||||
self.types.map(&:sti_name)
|
self.types.map(&:sti_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.source_for(type)
|
||||||
|
type = type.sti_name if type.is_a?(Class)
|
||||||
|
return UNKNOWN_TYPE_SOURCE if Reviewable.sti_names.exclude?(type)
|
||||||
|
|
||||||
|
DiscoursePluginRegistry
|
||||||
|
.reviewable_types_lookup
|
||||||
|
.find { |r| r[:klass].sti_name == type }
|
||||||
|
&.dig(:plugin) || "core"
|
||||||
|
end
|
||||||
|
|
||||||
def self.custom_filters
|
def self.custom_filters
|
||||||
@reviewable_filters ||= []
|
@reviewable_filters ||= []
|
||||||
end
|
end
|
||||||
@ -89,6 +103,10 @@ class Reviewable < ActiveRecord::Base
|
|||||||
@reviewable_filters = []
|
@reviewable_filters = []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_type_source
|
||||||
|
self.type_source = Reviewable.source_for(type)
|
||||||
|
end
|
||||||
|
|
||||||
def created_new!
|
def created_new!
|
||||||
self.created_new = true
|
self.created_new = true
|
||||||
self.topic = target.topic if topic.blank? && target.is_a?(Post)
|
self.topic = target.topic if topic.blank? && target.is_a?(Post)
|
||||||
@ -766,8 +784,14 @@ class Reviewable < ActiveRecord::Base
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.unknown_types
|
def self.unknown_types_and_sources
|
||||||
Reviewable.pending.distinct.pluck(:type) - Reviewable.sti_names
|
@known_sources ||= Reviewable.sti_names.map { |n| [n, Reviewable.source_for(n)] }
|
||||||
|
|
||||||
|
known_unknowns = Reviewable.pending.distinct.pluck(:type, :type_source) - @known_sources
|
||||||
|
|
||||||
|
known_unknowns
|
||||||
|
.map { |type, source| { type: type, source: source } }
|
||||||
|
.sort_by { |e| [e[:source] == UNKNOWN_TYPE_SOURCE ? 1 : 0, e[:source], e[:type]] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.destroy_unknown_types!
|
def self.destroy_unknown_types!
|
||||||
@ -804,6 +828,7 @@ end
|
|||||||
#
|
#
|
||||||
# id :bigint not null, primary key
|
# id :bigint not null, primary key
|
||||||
# type :string not null
|
# type :string not null
|
||||||
|
# type_source :string default("unknown"), not null
|
||||||
# status :integer default("pending"), not null
|
# status :integer default("pending"), not null
|
||||||
# created_by_id :integer not null
|
# created_by_id :integer not null
|
||||||
# reviewable_by_moderator :boolean default(FALSE), not null
|
# reviewable_by_moderator :boolean default(FALSE), not null
|
||||||
|
@ -399,6 +399,7 @@ end
|
|||||||
#
|
#
|
||||||
# id :bigint not null, primary key
|
# id :bigint not null, primary key
|
||||||
# type :string not null
|
# type :string not null
|
||||||
|
# type_source :string default("unknown"), not null
|
||||||
# status :integer default("pending"), not null
|
# status :integer default("pending"), not null
|
||||||
# created_by_id :integer not null
|
# created_by_id :integer not null
|
||||||
# reviewable_by_moderator :boolean default(FALSE), not null
|
# reviewable_by_moderator :boolean default(FALSE), not null
|
||||||
|
@ -142,6 +142,7 @@ end
|
|||||||
#
|
#
|
||||||
# id :bigint not null, primary key
|
# id :bigint not null, primary key
|
||||||
# type :string not null
|
# type :string not null
|
||||||
|
# type_source :string default("unknown"), not null
|
||||||
# status :integer default("pending"), not null
|
# status :integer default("pending"), not null
|
||||||
# created_by_id :integer not null
|
# created_by_id :integer not null
|
||||||
# reviewable_by_moderator :boolean default(FALSE), not null
|
# reviewable_by_moderator :boolean default(FALSE), not null
|
||||||
|
@ -240,6 +240,7 @@ end
|
|||||||
#
|
#
|
||||||
# id :bigint not null, primary key
|
# id :bigint not null, primary key
|
||||||
# type :string not null
|
# type :string not null
|
||||||
|
# type_source :string default("unknown"), not null
|
||||||
# status :integer default("pending"), not null
|
# status :integer default("pending"), not null
|
||||||
# created_by_id :integer not null
|
# created_by_id :integer not null
|
||||||
# reviewable_by_moderator :boolean default(FALSE), not null
|
# reviewable_by_moderator :boolean default(FALSE), not null
|
||||||
|
@ -102,6 +102,7 @@ end
|
|||||||
#
|
#
|
||||||
# id :bigint not null, primary key
|
# id :bigint not null, primary key
|
||||||
# type :string not null
|
# type :string not null
|
||||||
|
# type_source :string default("unknown"), not null
|
||||||
# status :integer default("pending"), not null
|
# status :integer default("pending"), not null
|
||||||
# created_by_id :integer not null
|
# created_by_id :integer not null
|
||||||
# reviewable_by_moderator :boolean default(FALSE), not null
|
# reviewable_by_moderator :boolean default(FALSE), not null
|
||||||
|
@ -6,6 +6,7 @@ class ReviewableSerializer < ApplicationSerializer
|
|||||||
attributes(
|
attributes(
|
||||||
:id,
|
:id,
|
||||||
:type,
|
:type,
|
||||||
|
:type_source,
|
||||||
:topic_id,
|
:topic_id,
|
||||||
:topic_url,
|
:topic_url,
|
||||||
:target_url,
|
:target_url,
|
||||||
|
@ -589,6 +589,8 @@ en:
|
|||||||
one: "You have pending reviewables from disabled plugin:"
|
one: "You have pending reviewables from disabled plugin:"
|
||||||
other: "You have pending reviewables from disabled plugins:"
|
other: "You have pending reviewables from disabled plugins:"
|
||||||
instruction: "They cannot be properly displayed until you enable the relevant plugin. Please enable the plugin and refresh the page. Alternatively, you can ignore them. <a href='%{url}' target='_blank'>Learn more...</a>"
|
instruction: "They cannot be properly displayed until you enable the relevant plugin. Please enable the plugin and refresh the page. Alternatively, you can ignore them. <a href='%{url}' target='_blank'>Learn more...</a>"
|
||||||
|
reviewable_unknown_source: "%{reviewableType} (unknown plugin)"
|
||||||
|
reviewable_known_source: "%{reviewableType} (from the '%{pluginName}' plugin)"
|
||||||
ignore_all: "Ignore all"
|
ignore_all: "Ignore all"
|
||||||
enable_plugins: "Enable plugins"
|
enable_plugins: "Enable plugins"
|
||||||
delete_confirm: "Are you sure you want to delete all reviews created by disabled plugins?"
|
delete_confirm: "Are you sure you want to delete all reviews created by disabled plugins?"
|
||||||
|
27
db/migrate/20250212045125_add_type_source_to_reviewable.rb
Normal file
27
db/migrate/20250212045125_add_type_source_to_reviewable.rb
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
class AddTypeSourceToReviewable < ActiveRecord::Migration[7.2]
|
||||||
|
def change
|
||||||
|
add_column :reviewables, :type_source, :string, null: false, default: "unknown"
|
||||||
|
|
||||||
|
# Migrate known reviewables to have a type_source
|
||||||
|
known_reviewables = {
|
||||||
|
"chat" => %w[ReviewableChatMessage],
|
||||||
|
"core" => %w[ReviewableFlaggedPost ReviewableQueuedPost ReviewableUser ReviewablePost],
|
||||||
|
"discourse-ai" => %w[ReviewableAiChatMessage ReviewableAiPost],
|
||||||
|
"discourse-akismet" => %w[
|
||||||
|
ReviewableAkismetPost
|
||||||
|
ReviewableAkismetPostVotingComment
|
||||||
|
ReviewableAkismetUser
|
||||||
|
],
|
||||||
|
"discourse-antivirus" => %w[ReviewableUpload],
|
||||||
|
"discourse-category-experts" => %w[ReviewableCategoryExpertSuggestion],
|
||||||
|
"discourse-post-voting" => %w[ReviewablePostVotingComment],
|
||||||
|
}
|
||||||
|
|
||||||
|
known_reviewables.each do |plugin, types|
|
||||||
|
types.each do |type|
|
||||||
|
Reviewable.where(type: type, type_source: "unknown").update_all(type_source: plugin)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -50,6 +50,8 @@ class DiscoursePluginRegistry
|
|||||||
define_singleton_method("register_#{register_name.to_s.singularize}") do |value, plugin|
|
define_singleton_method("register_#{register_name.to_s.singularize}") do |value, plugin|
|
||||||
public_send(:"_raw_#{register_name}") << { plugin: plugin, value: value }
|
public_send(:"_raw_#{register_name}") << { plugin: plugin, value: value }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
yield(self) if block_given?
|
||||||
end
|
end
|
||||||
|
|
||||||
define_register :javascripts, Set
|
define_register :javascripts, Set
|
||||||
@ -129,6 +131,14 @@ class DiscoursePluginRegistry
|
|||||||
|
|
||||||
define_filtered_register :custom_filter_mappings
|
define_filtered_register :custom_filter_mappings
|
||||||
|
|
||||||
|
define_filtered_register :reviewable_types do |singleton|
|
||||||
|
singleton.define_singleton_method("reviewable_types_lookup") do
|
||||||
|
public_send(:"_raw_reviewable_types")
|
||||||
|
.filter_map { |h| { plugin: h[:plugin].name, klass: h[:value] } if h[:plugin].enabled? }
|
||||||
|
.uniq
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.register_auth_provider(auth_provider)
|
def self.register_auth_provider(auth_provider)
|
||||||
self.auth_providers << auth_provider
|
self.auth_providers << auth_provider
|
||||||
end
|
end
|
||||||
|
@ -169,6 +169,8 @@ task "javascript:update_constants" => :environment do
|
|||||||
export const USER_FIELD_FLAGS = #{UserField::FLAG_ATTRIBUTES};
|
export const USER_FIELD_FLAGS = #{UserField::FLAG_ATTRIBUTES};
|
||||||
|
|
||||||
export const REPORT_MODES = #{Report::MODES.to_json};
|
export const REPORT_MODES = #{Report::MODES.to_json};
|
||||||
|
|
||||||
|
export const REVIEWABLE_UNKNOWN_TYPE_SOURCE = "#{Reviewable::UNKNOWN_TYPE_SOURCE}";
|
||||||
JS
|
JS
|
||||||
|
|
||||||
pretty_notifications = Notification.types.map { |n| " #{n[0]}: #{n[1]}," }.join("\n")
|
pretty_notifications = Notification.types.map { |n| " #{n[0]}: #{n[1]}," }.join("\n")
|
||||||
|
@ -15,6 +15,7 @@ RSpec.describe DiscoursePluginRegistry do
|
|||||||
let(:plugin_class) do
|
let(:plugin_class) do
|
||||||
Class.new(Plugin::Instance) do
|
Class.new(Plugin::Instance) do
|
||||||
attr_accessor :enabled
|
attr_accessor :enabled
|
||||||
|
attr_accessor :name
|
||||||
def enabled?
|
def enabled?
|
||||||
@enabled
|
@enabled
|
||||||
end
|
end
|
||||||
@ -52,6 +53,20 @@ RSpec.describe DiscoursePluginRegistry do
|
|||||||
plugin.enabled = false
|
plugin.enabled = false
|
||||||
expect(fresh_registry.test_things.length).to eq(0)
|
expect(fresh_registry.test_things.length).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "runs the callback block" do
|
||||||
|
fresh_registry.define_filtered_register(:test_other_things) do |singleton|
|
||||||
|
singleton.define_singleton_method(:my_fun_method) { true }
|
||||||
|
end
|
||||||
|
|
||||||
|
fresh_registry.register_test_other_thing("mything", plugin)
|
||||||
|
|
||||||
|
plugin.enabled = true
|
||||||
|
expect(fresh_registry.test_other_things).to contain_exactly("mything")
|
||||||
|
|
||||||
|
expect(fresh_registry.methods.include?(:my_fun_method)).to eq(true)
|
||||||
|
expect(fresh_registry.my_fun_method).to eq(true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -625,13 +625,22 @@ TEXT
|
|||||||
subject(:register_reviewable_type) { plugin_instance.register_reviewable_type(new_type) }
|
subject(:register_reviewable_type) { plugin_instance.register_reviewable_type(new_type) }
|
||||||
|
|
||||||
context "when the provided class inherits from `Reviewable`" do
|
context "when the provided class inherits from `Reviewable`" do
|
||||||
let(:new_type) { Class.new(Reviewable) }
|
let(:new_type) do
|
||||||
|
class MyReviewable < Reviewable
|
||||||
|
end
|
||||||
|
MyReviewable
|
||||||
|
end
|
||||||
|
|
||||||
it "adds the provided class to the existing types" do
|
it "adds the provided class to the existing types" do
|
||||||
expect { register_reviewable_type }.to change { Reviewable.types.size }.by(1)
|
expect { register_reviewable_type }.to change { Reviewable.types.size }.by(1)
|
||||||
expect(Reviewable.types).to include(new_type)
|
expect(Reviewable.types).to include(new_type)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "shows the correct source for the new type" do
|
||||||
|
register_reviewable_type
|
||||||
|
expect(Reviewable.source_for(new_type)).to eq("discourse-sample-plugin")
|
||||||
|
end
|
||||||
|
|
||||||
context "when the plugin is disabled" do
|
context "when the plugin is disabled" do
|
||||||
before do
|
before do
|
||||||
register_reviewable_type
|
register_reviewable_type
|
||||||
|
@ -341,6 +341,89 @@ RSpec.describe Reviewable, type: :model do
|
|||||||
expect(Reviewable.valid_type?("User")).to eq(false)
|
expect(Reviewable.valid_type?("User")).to eq(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".source_for" do
|
||||||
|
it "returns the correct source" do
|
||||||
|
expect(Reviewable.source_for(ReviewablePost)).to eq("core")
|
||||||
|
expect(Reviewable.source_for(ReviewableFlaggedPost)).to eq("core")
|
||||||
|
expect(Reviewable.source_for(ReviewableQueuedPost)).to eq("core")
|
||||||
|
expect(Reviewable.source_for(ReviewableUser)).to eq("core")
|
||||||
|
expect(Reviewable.source_for("NonExistentType")).to eq("unknown")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".unknown_types_and_sources" do
|
||||||
|
it "returns an empty array when no unknown types are present" do
|
||||||
|
expect(Reviewable.unknown_types_and_sources).to eq([])
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with reviewables of unknown type or sources" do
|
||||||
|
fab!(:core_type) do
|
||||||
|
type = Fabricate(:reviewable)
|
||||||
|
type.update_columns(type: "ReviewableDoesntExist", type_source: "core")
|
||||||
|
type
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:known_core_type) do
|
||||||
|
type = Fabricate(:reviewable)
|
||||||
|
type.update_columns(type: "ReviewableFlaggedPost", type_source: "core")
|
||||||
|
type
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:unknown_type) do
|
||||||
|
type = Fabricate(:reviewable)
|
||||||
|
type.update_columns(type: "UnknownType", type_source: "unknown")
|
||||||
|
type
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:plugin_type) do
|
||||||
|
type = Fabricate(:reviewable)
|
||||||
|
type.update_columns(type: "PluginReviewableDoesntExist", type_source: "my-plugin")
|
||||||
|
type
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:plugin_type2) do
|
||||||
|
type = Fabricate(:reviewable)
|
||||||
|
type.update_columns(type: "PluginReviewableStillDoesntExist", type_source: "my-plugin")
|
||||||
|
type
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:plugin_type3) do
|
||||||
|
type = Fabricate(:reviewable)
|
||||||
|
type.update_columns(
|
||||||
|
type: "AnotherPluginReviewableDoesntExist",
|
||||||
|
type_source: "another-plugin",
|
||||||
|
)
|
||||||
|
type
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:plugin_type4) do
|
||||||
|
type = Fabricate(:reviewable)
|
||||||
|
type.update_columns(type: "ThisIsGettingSilly", type_source: "zzz-last-plugin")
|
||||||
|
type
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:unknown_type2) do
|
||||||
|
type = Fabricate(:reviewable)
|
||||||
|
type.update_columns(type: "AnotherUnknownType", type_source: "unknown")
|
||||||
|
type
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an array of unknown types, sorted by source (with 'unknown' always last), then by type" do
|
||||||
|
expect(Reviewable.unknown_types_and_sources).to eq(
|
||||||
|
[
|
||||||
|
{ type: "AnotherPluginReviewableDoesntExist", source: "another-plugin" },
|
||||||
|
{ type: "ReviewableDoesntExist", source: "core" },
|
||||||
|
{ type: "PluginReviewableDoesntExist", source: "my-plugin" },
|
||||||
|
{ type: "PluginReviewableStillDoesntExist", source: "my-plugin" },
|
||||||
|
{ type: "ThisIsGettingSilly", source: "zzz-last-plugin" },
|
||||||
|
{ type: "AnotherUnknownType", source: "unknown" },
|
||||||
|
{ type: "UnknownType", source: "unknown" },
|
||||||
|
],
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "events" do
|
describe "events" do
|
||||||
let!(:moderator) { Fabricate(:moderator) }
|
let!(:moderator) { Fabricate(:moderator) }
|
||||||
let(:reviewable) { Fabricate(:reviewable) }
|
let(:reviewable) { Fabricate(:reviewable) }
|
||||||
|
@ -10,6 +10,7 @@ RSpec.describe ReviewableSerializer do
|
|||||||
expect(json[:id]).to eq(reviewable.id)
|
expect(json[:id]).to eq(reviewable.id)
|
||||||
expect(json[:status]).to eq(reviewable.status_for_database)
|
expect(json[:status]).to eq(reviewable.status_for_database)
|
||||||
expect(json[:type]).to eq(reviewable.type)
|
expect(json[:type]).to eq(reviewable.type)
|
||||||
|
expect(json[:type_source]).to eq(reviewable.type_source)
|
||||||
expect(json[:created_at]).to eq(reviewable.created_at)
|
expect(json[:created_at]).to eq(reviewable.created_at)
|
||||||
expect(json[:category_id]).to eq(reviewable.category_id)
|
expect(json[:category_id]).to eq(reviewable.category_id)
|
||||||
expect(json[:can_edit]).to eq(true)
|
expect(json[:can_edit]).to eq(true)
|
||||||
|
@ -92,6 +92,26 @@ module PageObjects
|
|||||||
page.has_no_css?(".unknown-reviewables")
|
page.has_no_css?(".unknown-reviewables")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def has_listing_for_unknown_reviewables_plugin?(reviewable_type, plugin_name)
|
||||||
|
page.has_css?(
|
||||||
|
".unknown-reviewables ul li",
|
||||||
|
text:
|
||||||
|
I18n.t(
|
||||||
|
"js.review.unknown.reviewable_known_source",
|
||||||
|
reviewableType: reviewable_type,
|
||||||
|
pluginName: plugin_name,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_listing_for_unknown_reviewables_unknown_source?(reviewable_type)
|
||||||
|
page.has_css?(
|
||||||
|
".unknown-reviewables ul li",
|
||||||
|
text:
|
||||||
|
I18n.t("js.review.unknown.reviewable_unknown_source", reviewableType: reviewable_type),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def reviewable_action_dropdown
|
def reviewable_action_dropdown
|
||||||
|
@ -216,12 +216,21 @@ describe "Reviewables", type: :system do
|
|||||||
|
|
||||||
describe "when there is an unknown plugin reviewable" do
|
describe "when there is an unknown plugin reviewable" do
|
||||||
fab!(:reviewable) { Fabricate(:reviewable_flagged_post, target: long_post) }
|
fab!(:reviewable) { Fabricate(:reviewable_flagged_post, target: long_post) }
|
||||||
|
fab!(:reviewable2) { Fabricate(:reviewable) }
|
||||||
|
|
||||||
before { reviewable.update_column(:type, "UnknownPlugin") }
|
before do
|
||||||
|
reviewable.update_columns(type: "UnknownPlugin", type_source: "some-plugin")
|
||||||
|
reviewable2.update_columns(type: "UnknownSource", type_source: "unknown")
|
||||||
|
end
|
||||||
|
|
||||||
it "informs admin and allows to delete them" do
|
it "informs admin and allows to delete them" do
|
||||||
visit("/review")
|
visit("/review")
|
||||||
expect(review_page).to have_information_about_unknown_reviewables_visible
|
expect(review_page).to have_information_about_unknown_reviewables_visible
|
||||||
|
expect(review_page).to have_listing_for_unknown_reviewables_plugin(
|
||||||
|
reviewable.type,
|
||||||
|
reviewable.type_source,
|
||||||
|
)
|
||||||
|
expect(review_page).to have_listing_for_unknown_reviewables_unknown_source(reviewable2.type)
|
||||||
review_page.click_ignore_all_unknown_reviewables
|
review_page.click_ignore_all_unknown_reviewables
|
||||||
expect(review_page).to have_no_information_about_unknown_reviewables_visible
|
expect(review_page).to have_no_information_about_unknown_reviewables_visible
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user