2023-10-11 02:38:59 +08:00
|
|
|
import { warn } from "@ember/debug";
|
|
|
|
import { action } from "@ember/object";
|
2019-10-31 04:28:29 +08:00
|
|
|
import { alias, oneWay } from "@ember/object/computed";
|
2019-10-31 04:13:48 +08:00
|
|
|
import Mixin from "@ember/object/mixin";
|
2024-03-07 01:05:11 +08:00
|
|
|
import { service } from "@ember/service";
|
2020-05-01 04:41:02 +08:00
|
|
|
import { htmlSafe } from "@ember/template";
|
2023-10-11 02:38:59 +08:00
|
|
|
import { isNone } from "@ember/utils";
|
2024-06-19 14:01:24 +08:00
|
|
|
import { Promise } from "rsvp";
|
2024-03-06 08:24:29 +08:00
|
|
|
import JsonSchemaEditorModal from "discourse/components/modal/json-schema-editor";
|
2023-10-11 02:38:59 +08:00
|
|
|
import { ajax } from "discourse/lib/ajax";
|
|
|
|
import { fmt, propertyNotEqual } from "discourse/lib/computed";
|
2024-06-19 14:01:24 +08:00
|
|
|
import { SITE_SETTING_REQUIRES_CONFIRMATION_TYPES } from "discourse/lib/constants";
|
2021-09-27 16:43:26 +08:00
|
|
|
import { splitString } from "discourse/lib/utilities";
|
2024-03-13 06:52:46 +08:00
|
|
|
import { deepEqual } from "discourse-common/lib/object";
|
2023-10-11 02:38:59 +08:00
|
|
|
import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
2023-10-18 18:07:09 +08:00
|
|
|
import I18n from "discourse-i18n";
|
2023-08-10 17:31:34 +08:00
|
|
|
import SiteSettingDefaultCategoriesModal from "../components/modal/site-setting-default-categories";
|
2018-03-05 08:04:23 +08:00
|
|
|
|
2018-03-14 03:59:12 +08:00
|
|
|
const CUSTOM_TYPES = [
|
|
|
|
"bool",
|
2023-10-07 01:21:01 +08:00
|
|
|
"integer",
|
2018-03-14 03:59:12 +08:00
|
|
|
"enum",
|
|
|
|
"list",
|
|
|
|
"url_list",
|
|
|
|
"host_list",
|
|
|
|
"category_list",
|
|
|
|
"value_list",
|
2018-07-18 18:57:43 +08:00
|
|
|
"category",
|
2018-08-04 04:41:37 +08:00
|
|
|
"uploaded_image_list",
|
2018-10-15 13:03:53 +08:00
|
|
|
"compact_list",
|
2018-11-14 15:03:02 +08:00
|
|
|
"secret_list",
|
2019-04-19 01:44:58 +08:00
|
|
|
"upload",
|
2019-11-01 15:10:13 +08:00
|
|
|
"group_list",
|
2020-03-09 17:07:03 +08:00
|
|
|
"tag_list",
|
2023-06-09 23:02:55 +08:00
|
|
|
"tag_group_list",
|
2020-06-04 22:44:54 +08:00
|
|
|
"color",
|
|
|
|
"simple_list",
|
2021-04-07 21:32:05 +08:00
|
|
|
"emoji_list",
|
2022-03-08 19:18:43 +08:00
|
|
|
"named_list",
|
2023-12-14 07:22:48 +08:00
|
|
|
"file_size_restriction",
|
2023-12-22 08:23:42 +08:00
|
|
|
"file_types_list",
|
2018-03-14 03:59:12 +08:00
|
|
|
];
|
2018-03-05 08:04:23 +08:00
|
|
|
|
2019-06-20 22:57:31 +08:00
|
|
|
const AUTO_REFRESH_ON_SAVE = ["logo", "logo_small", "large_icon"];
|
|
|
|
|
2023-03-01 17:12:39 +08:00
|
|
|
const DEFAULT_USER_PREFERENCES = [
|
|
|
|
"default_email_digest_frequency",
|
|
|
|
"default_include_tl0_in_digests",
|
|
|
|
"default_email_level",
|
|
|
|
"default_email_messages_level",
|
|
|
|
"default_email_mailing_list_mode",
|
|
|
|
"default_email_mailing_list_mode_frequency",
|
|
|
|
"default_email_previous_replies",
|
|
|
|
"default_email_in_reply_to",
|
|
|
|
"default_hide_profile_and_presence",
|
|
|
|
"default_other_new_topic_duration_minutes",
|
|
|
|
"default_other_auto_track_topics_after_msecs",
|
|
|
|
"default_other_notification_level_when_replying",
|
|
|
|
"default_other_external_links_in_new_tab",
|
|
|
|
"default_other_enable_quoting",
|
|
|
|
"default_other_enable_defer",
|
|
|
|
"default_other_dynamic_favicon",
|
|
|
|
"default_other_like_notification_frequency",
|
|
|
|
"default_other_skip_new_user_tips",
|
|
|
|
"default_topics_automatic_unpin",
|
|
|
|
"default_categories_watching",
|
|
|
|
"default_categories_tracking",
|
|
|
|
"default_categories_muted",
|
|
|
|
"default_categories_watching_first_post",
|
|
|
|
"default_categories_normal",
|
|
|
|
"default_tags_watching",
|
|
|
|
"default_tags_tracking",
|
|
|
|
"default_tags_muted",
|
|
|
|
"default_tags_watching_first_post",
|
|
|
|
"default_text_size",
|
|
|
|
"default_title_count_mode",
|
2023-06-15 07:31:28 +08:00
|
|
|
"default_navigation_menu_categories",
|
|
|
|
"default_navigation_menu_tags",
|
2023-07-07 09:52:10 +08:00
|
|
|
"default_sidebar_link_to_filtered_list",
|
|
|
|
"default_sidebar_show_count_of_new_items",
|
2023-03-01 17:12:39 +08:00
|
|
|
];
|
|
|
|
|
2019-10-31 03:03:08 +08:00
|
|
|
export default Mixin.create({
|
2023-08-10 17:31:34 +08:00
|
|
|
modal: service(),
|
2024-03-06 08:24:29 +08:00
|
|
|
router: service(),
|
2023-08-10 17:31:34 +08:00
|
|
|
site: service(),
|
2024-06-19 14:01:24 +08:00
|
|
|
dialog: service(),
|
2023-03-01 17:12:39 +08:00
|
|
|
attributeBindings: ["setting.setting:data-setting"],
|
2019-01-11 16:39:21 +08:00
|
|
|
classNameBindings: [":row", ":setting", "overridden", "typeClass"],
|
2018-03-05 08:04:23 +08:00
|
|
|
validationMessage: null,
|
2021-09-27 16:43:26 +08:00
|
|
|
setting: null,
|
2023-03-01 17:12:39 +08:00
|
|
|
|
|
|
|
content: alias("setting"),
|
|
|
|
isSecret: oneWay("setting.secret"),
|
|
|
|
componentName: fmt("typeClass", "site-settings/%@"),
|
|
|
|
overridden: propertyNotEqual("setting.default", "buffered.value"),
|
|
|
|
|
|
|
|
didInsertElement() {
|
|
|
|
this._super(...arguments);
|
|
|
|
this.element.addEventListener("keydown", this._handleKeydown);
|
|
|
|
},
|
|
|
|
|
|
|
|
willDestroyElement() {
|
|
|
|
this._super(...arguments);
|
|
|
|
this.element.removeEventListener("keydown", this._handleKeydown);
|
|
|
|
},
|
2018-03-05 08:04:23 +08:00
|
|
|
|
2019-11-08 05:38:28 +08:00
|
|
|
@discourseComputed("buffered.value", "setting.value")
|
2018-03-05 08:04:23 +08:00
|
|
|
dirty(bufferVal, settingVal) {
|
2021-09-27 16:43:26 +08:00
|
|
|
if (isNone(bufferVal)) {
|
2020-09-22 22:28:28 +08:00
|
|
|
bufferVal = "";
|
|
|
|
}
|
2021-09-27 16:43:26 +08:00
|
|
|
|
|
|
|
if (isNone(settingVal)) {
|
2020-09-22 22:28:28 +08:00
|
|
|
settingVal = "";
|
|
|
|
}
|
2018-03-05 08:04:23 +08:00
|
|
|
|
2024-03-13 06:52:46 +08:00
|
|
|
return !deepEqual(bufferVal, settingVal);
|
2018-03-05 08:04:23 +08:00
|
|
|
},
|
|
|
|
|
2019-11-08 05:38:28 +08:00
|
|
|
@discourseComputed("setting", "buffered.value")
|
2018-03-05 08:04:23 +08:00
|
|
|
preview(setting, value) {
|
2021-09-27 16:43:26 +08:00
|
|
|
const preview = setting.preview;
|
2018-03-05 08:04:23 +08:00
|
|
|
if (preview) {
|
2021-09-27 16:43:26 +08:00
|
|
|
const escapedValue = preview.replace(/\{\{value\}\}/g, value);
|
|
|
|
return htmlSafe(`<div class='preview'>${escapedValue}</div>`);
|
2018-03-05 08:04:23 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-11-08 05:38:28 +08:00
|
|
|
@discourseComputed("componentType")
|
2018-03-05 08:04:23 +08:00
|
|
|
typeClass(componentType) {
|
|
|
|
return componentType.replace(/\_/g, "-");
|
|
|
|
},
|
|
|
|
|
2019-11-28 13:19:01 +08:00
|
|
|
@discourseComputed("setting.setting", "setting.label")
|
|
|
|
settingName(setting, label) {
|
|
|
|
return label || setting.replace(/\_/g, " ");
|
2018-03-05 08:04:23 +08:00
|
|
|
},
|
|
|
|
|
2019-11-08 05:38:28 +08:00
|
|
|
@discourseComputed("type")
|
2018-03-05 08:04:23 +08:00
|
|
|
componentType(type) {
|
2022-07-18 02:48:36 +08:00
|
|
|
return CUSTOM_TYPES.includes(type) ? type : "string";
|
2018-03-05 08:04:23 +08:00
|
|
|
},
|
|
|
|
|
2019-11-08 05:38:28 +08:00
|
|
|
@discourseComputed("setting")
|
2018-08-04 04:41:37 +08:00
|
|
|
type(setting) {
|
|
|
|
if (setting.type === "list" && setting.list_type) {
|
|
|
|
return `${setting.list_type}_list`;
|
|
|
|
}
|
|
|
|
|
|
|
|
return setting.type;
|
|
|
|
},
|
|
|
|
|
2019-11-28 13:19:01 +08:00
|
|
|
@discourseComputed("setting.anyValue")
|
|
|
|
allowAny(anyValue) {
|
|
|
|
return anyValue !== false;
|
|
|
|
},
|
|
|
|
|
2019-12-04 14:13:41 +08:00
|
|
|
@discourseComputed("buffered.value")
|
2021-09-27 16:43:26 +08:00
|
|
|
bufferedValues(value) {
|
|
|
|
return splitString(value, "|");
|
|
|
|
},
|
2019-12-04 14:13:41 +08:00
|
|
|
|
|
|
|
@discourseComputed("setting.defaultValues")
|
2021-09-27 16:43:26 +08:00
|
|
|
defaultValues(value) {
|
|
|
|
return splitString(value, "|");
|
|
|
|
},
|
2019-12-04 14:13:41 +08:00
|
|
|
|
|
|
|
@discourseComputed("defaultValues", "bufferedValues")
|
|
|
|
defaultIsAvailable(defaultValues, bufferedValues) {
|
|
|
|
return (
|
2019-12-05 05:25:49 +08:00
|
|
|
defaultValues.length > 0 &&
|
2019-12-04 14:13:41 +08:00
|
|
|
!defaultValues.every((value) => bufferedValues.includes(value))
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2024-03-06 08:24:29 +08:00
|
|
|
@discourseComputed("setting")
|
|
|
|
settingEditButton(setting) {
|
|
|
|
if (setting.json_schema) {
|
|
|
|
return {
|
|
|
|
action: () => {
|
|
|
|
this.modal.show(JsonSchemaEditorModal, {
|
|
|
|
model: {
|
|
|
|
updateValue: (value) => {
|
|
|
|
this.buffered.set("value", value);
|
|
|
|
},
|
|
|
|
value: this.buffered.get("value"),
|
|
|
|
settingName: setting.setting,
|
|
|
|
jsonSchema: setting.json_schema,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
label: "admin.site_settings.json_schema.edit",
|
|
|
|
icon: "pencil-alt",
|
|
|
|
};
|
|
|
|
} else if (setting.objects_schema) {
|
|
|
|
return {
|
|
|
|
action: () => {
|
|
|
|
this.router.transitionTo(
|
|
|
|
"adminCustomizeThemes.show.schema",
|
|
|
|
setting.setting
|
|
|
|
);
|
|
|
|
},
|
|
|
|
label: "admin.customize.theme.edit_objects_theme_setting",
|
|
|
|
icon: "pencil-alt",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2024-06-19 14:01:24 +08:00
|
|
|
confirmChanges(settingKey) {
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
// Fallback is needed in case the setting does not have a custom confirmation
|
|
|
|
// prompt/confirm defined.
|
|
|
|
this.dialog.alert({
|
|
|
|
message: I18n.t(
|
|
|
|
`admin.site_settings.requires_confirmation_messages.${settingKey}.prompt`,
|
|
|
|
{
|
|
|
|
translatedFallback: I18n.t(
|
|
|
|
"admin.site_settings.requires_confirmation_messages.default.prompt"
|
|
|
|
),
|
|
|
|
}
|
|
|
|
),
|
|
|
|
buttons: [
|
|
|
|
{
|
|
|
|
label: I18n.t(
|
|
|
|
`admin.site_settings.requires_confirmation_messages.${settingKey}.confirm`,
|
|
|
|
{
|
|
|
|
translatedFallback: I18n.t(
|
|
|
|
"admin.site_settings.requires_confirmation_messages.default.confirm"
|
|
|
|
),
|
|
|
|
}
|
|
|
|
),
|
|
|
|
class: "btn-primary",
|
|
|
|
action: () => resolve(true),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: I18n.t("no_value"),
|
|
|
|
class: "btn-default",
|
|
|
|
action: () => resolve(false),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2021-09-27 16:43:26 +08:00
|
|
|
@action
|
2023-03-01 17:12:39 +08:00
|
|
|
async update() {
|
2021-09-27 16:43:26 +08:00
|
|
|
const key = this.buffered.get("setting");
|
|
|
|
|
2024-06-19 14:01:24 +08:00
|
|
|
let confirm = true;
|
|
|
|
if (
|
|
|
|
this.buffered.get("requires_confirmation") ===
|
|
|
|
SITE_SETTING_REQUIRES_CONFIRMATION_TYPES.simple
|
|
|
|
) {
|
|
|
|
confirm = await this.confirmChanges(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!confirm) {
|
|
|
|
this.cancel();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-03-01 17:12:39 +08:00
|
|
|
if (!DEFAULT_USER_PREFERENCES.includes(key)) {
|
|
|
|
await this.save();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const data = {
|
|
|
|
[key]: this.buffered.get("value"),
|
|
|
|
};
|
|
|
|
|
|
|
|
const result = await ajax(`/admin/site_settings/${key}/user_count.json`, {
|
|
|
|
type: "PUT",
|
|
|
|
data,
|
|
|
|
});
|
|
|
|
|
|
|
|
const count = result.user_count;
|
|
|
|
if (count > 0) {
|
2023-08-10 17:31:34 +08:00
|
|
|
await this.modal.show(SiteSettingDefaultCategoriesModal, {
|
|
|
|
model: {
|
|
|
|
siteSetting: { count, key: key.replaceAll("_", " ") },
|
|
|
|
setUpdateExistingUsers: this.setUpdateExistingUsers,
|
|
|
|
},
|
2021-09-27 16:43:26 +08:00
|
|
|
});
|
2023-08-10 17:31:34 +08:00
|
|
|
this.save();
|
2021-09-27 16:43:26 +08:00
|
|
|
} else {
|
2023-03-01 17:12:39 +08:00
|
|
|
await this.save();
|
2021-09-27 16:43:26 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-08-10 17:31:34 +08:00
|
|
|
@action
|
|
|
|
setUpdateExistingUsers(value) {
|
|
|
|
this.updateExistingUsers = value;
|
|
|
|
},
|
|
|
|
|
2021-09-27 16:43:26 +08:00
|
|
|
@action
|
2023-03-01 17:12:39 +08:00
|
|
|
async save() {
|
|
|
|
try {
|
|
|
|
await this._save();
|
|
|
|
|
|
|
|
this.set("validationMessage", null);
|
|
|
|
this.commitBuffer();
|
|
|
|
if (AUTO_REFRESH_ON_SAVE.includes(this.setting.setting)) {
|
|
|
|
this.afterSave();
|
|
|
|
}
|
|
|
|
} catch (e) {
|
2023-05-05 04:01:19 +08:00
|
|
|
const json = e.jqXHR?.responseJSON;
|
|
|
|
if (json?.errors) {
|
|
|
|
let errorString = json.errors[0];
|
|
|
|
|
|
|
|
if (json.html_message) {
|
|
|
|
errorString = htmlSafe(errorString);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.set("validationMessage", errorString);
|
2023-03-01 17:12:39 +08:00
|
|
|
} else {
|
|
|
|
this.set("validationMessage", I18n.t("generic_error"));
|
|
|
|
}
|
|
|
|
}
|
2021-09-27 16:43:26 +08:00
|
|
|
},
|
|
|
|
|
2023-12-22 08:23:42 +08:00
|
|
|
@action
|
|
|
|
changeValueCallback(value) {
|
|
|
|
this.set("buffered.value", value);
|
|
|
|
},
|
|
|
|
|
2021-09-27 16:43:26 +08:00
|
|
|
@action
|
|
|
|
cancel() {
|
|
|
|
this.rollbackBuffer();
|
|
|
|
},
|
|
|
|
|
|
|
|
@action
|
|
|
|
resetDefault() {
|
2024-03-13 06:52:46 +08:00
|
|
|
this.set("buffered.value", this.setting.default);
|
2021-09-27 16:43:26 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
@action
|
|
|
|
toggleSecret() {
|
|
|
|
this.toggleProperty("isSecret");
|
|
|
|
},
|
|
|
|
|
|
|
|
@action
|
|
|
|
setDefaultValues() {
|
|
|
|
this.set(
|
|
|
|
"buffered.value",
|
|
|
|
this.bufferedValues.concat(this.defaultValues).uniq().join("|")
|
2018-03-05 08:04:23 +08:00
|
|
|
);
|
2021-09-27 16:43:26 +08:00
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
|
|
|
@bind
|
|
|
|
_handleKeydown(event) {
|
|
|
|
if (
|
|
|
|
event.key === "Enter" &&
|
|
|
|
event.target.classList.contains("input-setting-string")
|
|
|
|
) {
|
|
|
|
this.save();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-03-01 17:12:39 +08:00
|
|
|
async _save() {
|
2020-03-07 06:49:28 +08:00
|
|
|
warn("You should define a `_save` method", {
|
2019-01-17 03:53:13 +08:00
|
|
|
id: "discourse.setting-component.missing-save",
|
2018-03-05 08:04:23 +08:00
|
|
|
});
|
|
|
|
},
|
|
|
|
});
|