Use "Enable Gravatar" but not "Disable" (#36771)

* Fix #35685
* Fix #35627
* Fix #31112


Introduce "fipped" config value type, remove unused setting variables.
Make DisableGravatar=true by defult, remove useless config options from
the "Install" page.

The legacy config options are still kept because they are still the
fallback values for the system config options.

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
wxiaoguang
2026-02-28 00:39:26 +08:00
committed by GitHub
parent fde7f7db28
commit ae2b19849d
20 changed files with 43 additions and 130 deletions

View File

@@ -7,10 +7,15 @@ test('ConfigFormValueMapper', () => {
<!-- top-level key -->
<input name="k1" type="checkbox" value="v-key-only" data-config-dyn-key="k1" data-config-value-json="true" data-config-value-type="boolean">
<input type="hidden" data-config-dyn-key="k2" data-config-value-json='"k2-val"'>
<input name="k2">
<textarea name="repository.open-with.editor-apps"> a = b\n</textarea>
<input name="k-flipped-true" type="checkbox" data-config-value-type="flipped">
<input name="k-flipped-false" type="checkbox" checked data-config-value-type="flipped">
<!-- sub key -->
<input type="hidden" data-config-dyn-key="struct" data-config-value-json='{"SubBoolean": true, "SubTimestamp": 123456789, "OtherKey": "other-value"}'>
<input name="struct.SubBoolean" type="checkbox" data-config-value-type="boolean">
@@ -35,6 +40,8 @@ test('ConfigFormValueMapper', () => {
expect(result).toEqual({
'k1': 'true',
'k2': '"k2-val"',
'k-flipped-false': 'false',
'k-flipped-true': 'true',
'repository.open-with.editor-apps': '[{"DisplayName":"a","OpenURL":"b"}]', // TODO: OPEN-WITH-EDITOR-APP-JSON: it must match backend
'struct': '{"SubBoolean":true,"SubTimestamp":123456780,"OtherKey":"other-value","NewKey":"new-value"}',
});

View File

@@ -6,14 +6,23 @@ import {submitFormFetchAction} from '../common-fetch-action.ts';
const {appSubUrl} = window.config;
function collectCheckboxBooleanValue(el: HTMLInputElement): boolean {
const valType = el.getAttribute('data-config-value-type') as ConfigValueType;
if (valType === 'boolean') return el.checked;
if (valType === 'flipped') return !el.checked;
requireExplicitValueType(el);
}
function initSystemConfigAutoCheckbox(el: HTMLInputElement) {
el.addEventListener('change', async () => {
// if the checkbox is inside a form, we assume it's handled by the form submit and do not send an individual request
if (el.closest('form')) return;
try {
const resp = await POST(`${appSubUrl}/-/admin/config`, {
data: new URLSearchParams({key: el.getAttribute('data-config-dyn-key')!, value: String(el.checked)}),
const data = new URLSearchParams({
key: el.getAttribute('data-config-dyn-key')!,
value: String(collectCheckboxBooleanValue(el)),
});
const resp = await POST(`${appSubUrl}/-/admin/config`, {data});
const json: Record<string, any> = await resp.json();
if (json.errorMessage) throw new Error(json.errorMessage);
} catch (ex) {
@@ -47,7 +56,7 @@ function extractElemConfigSubKey(el: GeneralFormFieldElement, dynKey: string): s
// Due to the different design between HTML form elements and the JSON struct of the config values, we need to explicitly define some types.
// * checkbox can be used for boolean value, it can also be used for multiple values (array)
type ConfigValueType = 'boolean' | 'string' | 'number' | 'timestamp'; // TODO: support more types like array, not used at the moment.
type ConfigValueType = 'boolean' | 'flipped' | 'string' | 'number' | 'timestamp'; // TODO: support more types like array, not used at the moment.
function toDatetimeLocalValue(unixSeconds: number) {
const d = new Date(unixSeconds * 1000);
@@ -102,13 +111,14 @@ export class ConfigFormValueMapper {
return true;
}
collectConfigValueFromElement(el: GeneralFormFieldElement, _oldVal: any = null) {
collectConfigValueFromElement(el: GeneralFormFieldElement) {
let val: any;
const valType = this.presetValueTypes[el.name];
if (el.matches('[type="checkbox"]')) {
if (valType !== 'boolean') requireExplicitValueType(el);
val = el.checked;
// oldVal: for future use when we support array value with checkbox
// TODO: if it needs to support array values in the future,
// it needs to iterate the "namedElems" to find all the checkboxes with the same name and collect values accordingly,
// and set the namedElems[matchedIdx] to null to avoid duplicate processing.
val = collectCheckboxBooleanValue(el);
} else if (el.matches('[type="datetime-local"]')) {
if (valType !== 'timestamp') requireExplicitValueType(el);
val = Math.floor(new Date(el.value).getTime() / 1000) ?? 0; // NaN is fine to JSON.stringify, it becomes null.
@@ -128,7 +138,7 @@ export class ConfigFormValueMapper {
if (!el) continue;
const subKey = extractElemConfigSubKey(el, dynKey);
if (!subKey) continue; // if not match, skip
cfgVal[subKey] = this.collectConfigValueFromElement(el, cfgVal[subKey]);
cfgVal[subKey] = this.collectConfigValueFromElement(el);
namedElems[idx] = null;
}
}
@@ -180,6 +190,7 @@ export class ConfigFormValueMapper {
// now, the namedElems should only contain the config options without sub values,
// directly store the value in formData with key as the element name, for example:
// "foo.enabled" => "true"
for (const el of namedElems) {
if (!el) continue;
const dynKey = el.name;

View File

@@ -60,25 +60,6 @@ function initPreInstall() {
}
// TODO: better handling of exclusive relations.
document.querySelector<HTMLInputElement>('#offline-mode input')!.addEventListener('change', function () {
if (this.checked) {
document.querySelector<HTMLInputElement>('#disable-gravatar input')!.checked = true;
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input')!.checked = false;
}
});
document.querySelector<HTMLInputElement>('#disable-gravatar input')!.addEventListener('change', function () {
if (this.checked) {
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input')!.checked = false;
} else {
document.querySelector<HTMLInputElement>('#offline-mode input')!.checked = false;
}
});
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input')!.addEventListener('change', function () {
if (this.checked) {
document.querySelector<HTMLInputElement>('#disable-gravatar input')!.checked = false;
document.querySelector<HTMLInputElement>('#offline-mode input')!.checked = false;
}
});
document.querySelector<HTMLInputElement>('#enable-openid-signin input')!.addEventListener('change', function () {
if (this.checked) {
if (!document.querySelector<HTMLInputElement>('#disable-registration input')!.checked) {