DEV: Add `getCategoryIdByName` helper function to theme migrations (#26601)

This commit adds a `getCategoryIdByName` helper function to the context in
which theme migrations are ran in. The purpose of this commit is to
allow themes which may have stored category names in theme settings to
migrate to objects typed theme settings which supports properties of
categories typed which stores the category ids in the value of the
property.
This commit is contained in:
Alan Guo Xiang Tan 2024-04-22 09:01:53 +08:00 committed by GitHub
parent a564274ba2
commit b3f1192312
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 57 additions and 1 deletions

View File

@ -1,25 +1,48 @@
# frozen_string_literal: true
class ThemeSettingsMigrationsRunner
# Methods defined in this module will be made available in the JS context where the theme settings migrations are
# executed.
#
# Defining a method `get_category_id_by_name` will result in the `getCategoryIdByName` function being made available
# in the JS context that migrations are ran in.
module Helpers
extend self
# @param [String] Name of the category to retrieve the id of.
# @return [Integer|nil] The id of the category with the given name or nil if a category does not exist for the given
# name.
def get_category_id_by_name(category_name)
Category.where(name_lower: category_name).pick(:id)
end
end
Migration = Struct.new(:version, :name, :original_name, :code, :theme_field_id)
MIGRATION_ENTRY_POINT_JS = <<~JS
const migrate = require("discourse/theme/migration")?.default;
const helpers = require("discourse/theme/migration-helpers")?.default;
function main(settingsObj) {
if (!migrate) {
throw new Error("no_exported_migration_function");
}
if (typeof migrate !== "function") {
throw new Error("default_export_is_not_a_function");
}
const map = new Map(Object.entries(settingsObj));
const updatedMap = migrate(map);
const updatedMap = migrate(map, helpers);
if (!updatedMap) {
throw new Error("migration_function_no_returned_value");
}
if (!(updatedMap instanceof Map)) {
throw new Error("migration_function_wrong_return_type");
}
return Object.fromEntries(updatedMap.entries());
}
JS
@ -168,7 +191,21 @@ class ThemeSettingsMigrationsRunner
filename: "theme-#{@theme.id}-migration.js",
)
Helpers.instance_methods.each do |method_name|
context.attach("__helpers.#{method_name.to_s.camelize(:lower)}", Helpers.method(method_name))
end
context.eval(
DiscourseJsProcessor.transpile(
"export default __helpers",
"",
"discourse/theme/migration-helpers",
),
filename: "theme-#{@theme.id}-migration-helpers.js",
)
context.eval(MIGRATION_ENTRY_POINT_JS, filename: "migration-entrypoint.js")
context.call("main", settings)
ensure
context&.dispose

View File

@ -281,5 +281,24 @@ describe ThemeSettingsMigrationsRunner do
expect(results[0][:settings_before]).to eq({})
expect(results[0][:settings_after]).to eq({})
end
it "attaches the getCategoryIdByName() function to the context of the migrations" do
category = Fabricate(:category, name: "some-category")
theme.update_setting(:integer_setting, -10)
theme.save!
migration_field.update!(value: <<~JS)
export default function migrate(settings, helpers) {
const categoryId = helpers.getCategoryIdByName("some-category");
settings.set("integer_setting", categoryId);
return settings;
}
JS
results = described_class.new(theme).run
expect(results[0][:settings_after]).to eq({ "integer_setting" => category.id })
end
end
end