diff --git a/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 b/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 index c974fafb..bd3c3d2d 100644 --- a/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 +++ b/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 @@ -83,6 +83,16 @@ export default { } }, }); + + api.modifyClass("component:category-chooser", { + categoriesByScope(options = {}) { + let categories = this._super(options); + + return categories.filter((category) => { + return !category.custom_fields?.create_topic_wizard; + }); + }, + }); }); }, }; diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index e8ceb44b..9fa23d53 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -55,6 +55,8 @@ en: liquid_syntax_error: "Liquid syntax error in %{attribute}: %{message}" subscription: "%{type} %{property} usage is not supported on your subscription" not_permitted_for_guests: "%{object_id} is not permitted when guests can access the wizard" + error_messages: + wizard_replacing_composer: "Category not allowed for topic creation." site_settings: custom_wizard_enabled: "Enable custom wizards." diff --git a/plugin.rb b/plugin.rb index 0634ef8c..7d3f7679 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.4.22 +# version: 2.4.23 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever, Juan Marcos Gutierrez Ramos # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech @@ -236,4 +236,13 @@ after_initialize do end DiscourseEvent.trigger(:custom_wizard_ready) + + on(:before_create_topic) do |topic_params, user| + category = topic_params.category + if category&.custom_fields&.[]('create_topic_wizard').present? + raise Discourse::InvalidParameters.new( + I18n.t('wizard.error_messages.wizard_replacing_composer') + ) + end + end end diff --git a/spec/extensions/topic_extension_spec.rb b/spec/extensions/topic_extension_spec.rb new file mode 100644 index 00000000..da4f416e --- /dev/null +++ b/spec/extensions/topic_extension_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +describe Topic, type: :model do + fab!(:category_with_wizard) do + Fabricate(:category, custom_fields: { create_topic_wizard: 'true' }) + end + fab!(:category_without_wizard) { Fabricate(:category) } + fab!(:user) { Fabricate(:user) } + let(:valid_attrs) { Fabricate.attributes_for(:topic) } + + context 'with a create_topic_wizard custom field in the category' do + it 'will not allow creating a topic directly' do + expect do + TopicCreator.create( + user, + Guardian.new(user), + valid_attrs.merge( + title: 'A valid and sufficiently long title for testing', + category: category_with_wizard.id, + raw: 'hello this is a test topic with category with custom fields' + ) + ) + end.to raise_error( + Discourse::InvalidParameters, + 'Category not allowed for topic creation.' + ) + end + end + + context 'without a create_topic_wizard custom field in the category' do + it 'will allow creating a topic directly' do + expect do + TopicCreator.create( + user, + Guardian.new(user), + valid_attrs.merge( + category: category_without_wizard.id, + title: 'Another valid and sufficiently long title for testing', + raw: 'This is the body of a valid topic' + ) + ) + end.not_to raise_error + end + end +end diff --git a/test/javascripts/acceptance/category-chooser-initializer-test.js b/test/javascripts/acceptance/category-chooser-initializer-test.js new file mode 100644 index 00000000..f7e02bb8 --- /dev/null +++ b/test/javascripts/acceptance/category-chooser-initializer-test.js @@ -0,0 +1,82 @@ +import { click, visit } from "@ember/test-helpers"; +import { acceptance } from "discourse/tests/helpers/qunit-helpers"; +import selectKit from "discourse/tests/helpers/select-kit-helper"; +import { test } from "qunit"; + +acceptance("Category Chooser Initializer", function (needs) { + needs.user(); + needs.settings({ + allow_uncategorized_topics: false, + }); + needs.site({ + can_tag_topics: true, + categories: [ + { + id: 1, + name: "General", + slug: "general", + permission: 1, + topic_template: null, + }, + { + id: 2, + name: "Category with custom field", + slug: "category-custom-field", + permission: 1, + topic_template: "", + custom_fields: { + create_topic_wizard: "21", + }, + }, + { + id: 3, + name: "Category 1", + slug: "category-1", + permission: 1, + topic_template: "", + }, + { + id: 4, + name: "Category 2", + slug: "category-2", + permission: 1, + topic_template: "", + }, + ], + }); + + test("does not display category with create_topic_wizard custom field", async function (assert) { + const categoryChooser = selectKit(".category-chooser"); + + await visit("/"); + await click("#create-topic"); + await categoryChooser.expand(); + let categories = Array.from( + document.querySelectorAll(".category-chooser .category-row") + ).filter((category) => category.getAttribute("data-name")); // Filter elements with a data-name attribute + assert.equal( + categories.length, + 3, + "Correct number of categories are displayed" + ); + const categoryNames = ["General", "Category 1", "Category 2"]; + + categoryNames.forEach((categoryName) => { + assert.ok( + categories.some( + (category) => category.getAttribute("data-name") === categoryName + ), + `Category '${categoryName}' is displayed` + ); + }); + + const categoryNameWithCustomField = "Category with custom field"; + assert.notOk( + categories.some( + (category) => + category.getAttribute("data-name") === categoryNameWithCustomField + ), + `Category '${categoryNameWithCustomField}' is not displayed` + ); + }); +});