mirror of
https://github.com/discourse/discourse.git
synced 2025-06-11 07:13:40 +08:00
DEV: Add file_size_restriction site setting type (#24704)
This change will allow admins to configure file sizes in mb instead of having to convert to kb. Co-authored-by: Ella <ella.estigoy@gmail.com>
This commit is contained in:
@ -0,0 +1,150 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { on } from "@ember/modifier";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
|
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
|
||||||
|
import TextField from "discourse/components/text-field";
|
||||||
|
import { allowOnlyNumericInput } from "discourse/lib/utilities";
|
||||||
|
import I18n from "discourse-i18n";
|
||||||
|
import ComboBox from "select-kit/components/combo-box";
|
||||||
|
|
||||||
|
const UNIT_KB = "kb";
|
||||||
|
const UNIT_MB = "mb";
|
||||||
|
const UNIT_GB = "gb";
|
||||||
|
|
||||||
|
export default class FileSizeInput extends Component {
|
||||||
|
@tracked fileSizeUnit;
|
||||||
|
@tracked sizeValue;
|
||||||
|
@tracked pendingSizeValue;
|
||||||
|
@tracked pendingFileSizeUnit;
|
||||||
|
|
||||||
|
constructor(owner, args) {
|
||||||
|
super(owner, args);
|
||||||
|
this.originalSizeKB = this.args.sizeValueKB;
|
||||||
|
this.sizeValue = this.args.sizeValueKB;
|
||||||
|
|
||||||
|
this._defaultUnit();
|
||||||
|
}
|
||||||
|
|
||||||
|
_defaultUnit() {
|
||||||
|
this.fileSizeUnit = UNIT_KB;
|
||||||
|
if (this.originalSizeKB <= 1024) {
|
||||||
|
this.onFileSizeUnitChange(UNIT_KB);
|
||||||
|
} else if (
|
||||||
|
this.originalSizeKB > 1024 &&
|
||||||
|
this.originalSizeKB <= 1024 * 1024
|
||||||
|
) {
|
||||||
|
this.onFileSizeUnitChange(UNIT_MB);
|
||||||
|
} else if (this.originalSizeKB > 1024 * 1024) {
|
||||||
|
this.onFileSizeUnitChange(UNIT_GB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
keyDown(event) {
|
||||||
|
allowOnlyNumericInput(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
get dropdownOptions() {
|
||||||
|
return [
|
||||||
|
{ label: I18n.t("number.human.storage_units.units.kb"), value: UNIT_KB },
|
||||||
|
{ label: I18n.t("number.human.storage_units.units.mb"), value: UNIT_MB },
|
||||||
|
{ label: I18n.t("number.human.storage_units.units.gb"), value: UNIT_GB },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
handleFileSizeChange(value) {
|
||||||
|
if (value !== "") {
|
||||||
|
this.pendingSizeValue = value;
|
||||||
|
this._onFileSizeChange(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onFileSizeChange(newSize) {
|
||||||
|
let fileSizeKB;
|
||||||
|
switch (this.fileSizeUnit) {
|
||||||
|
case "kb":
|
||||||
|
fileSizeKB = newSize;
|
||||||
|
break;
|
||||||
|
case "mb":
|
||||||
|
fileSizeKB = newSize * 1024;
|
||||||
|
break;
|
||||||
|
case "gb":
|
||||||
|
fileSizeKB = newSize * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fileSizeKB > this.args.max) {
|
||||||
|
this.args.updateValidationMessage(
|
||||||
|
I18n.t("file_size_input.error.size_too_large", {
|
||||||
|
provided_file_size: I18n.toHumanSize(fileSizeKB * 1024),
|
||||||
|
max_file_size: I18n.toHumanSize(this.args.max * 1024),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
// Removes the green save checkmark button
|
||||||
|
this.args.onChangeSize(this.originalSizeKB);
|
||||||
|
} else {
|
||||||
|
this.args.onChangeSize(fileSizeKB);
|
||||||
|
this.args.updateValidationMessage(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
onFileSizeUnitChange(newUnit) {
|
||||||
|
if (this.fileSizeUnit === "kb" && newUnit === "kb") {
|
||||||
|
this.pendingSizeValue = this.sizeValue;
|
||||||
|
}
|
||||||
|
if (this.fileSizeUnit === "kb" && newUnit === "mb") {
|
||||||
|
this.pendingSizeValue = this.sizeValue / 1024;
|
||||||
|
}
|
||||||
|
if (this.fileSizeUnit === "kb" && newUnit === "gb") {
|
||||||
|
this.pendingSizeValue = this.sizeValue / 1024 / 1024;
|
||||||
|
}
|
||||||
|
if (this.fileSizeUnit === "mb" && newUnit === "kb") {
|
||||||
|
this.pendingSizeValue = this.sizeValue * 1024;
|
||||||
|
}
|
||||||
|
if (this.fileSizeUnit === "mb" && newUnit === "gb") {
|
||||||
|
this.pendingSizeValue = this.sizeValue / 1024;
|
||||||
|
}
|
||||||
|
if (this.fileSizeUnit === "gb" && newUnit === "mb") {
|
||||||
|
this.pendingSizeValue = this.sizeValue * 1024;
|
||||||
|
}
|
||||||
|
if (this.fileSizeUnit === "gb" && newUnit === "kb") {
|
||||||
|
this.pendingSizeValue = this.sizeValue * 1024 * 1024;
|
||||||
|
}
|
||||||
|
this.pendingFileSizeUnit = newUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
applySizeValueChanges() {
|
||||||
|
this.sizeValue = this.pendingSizeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
applyUnitChanges() {
|
||||||
|
this.fileSizeUnit = this.pendingFileSizeUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="file-size-picker">
|
||||||
|
<TextField
|
||||||
|
class="file-size-input"
|
||||||
|
@value={{this.sizeValue}}
|
||||||
|
@onChange={{this.handleFileSizeChange}}
|
||||||
|
{{on "keydown" this.keyDown}}
|
||||||
|
{{didInsert this.applySizeValueChanges}}
|
||||||
|
{{didUpdate this.applySizeValueChanges this.pendingSizeValue}}
|
||||||
|
/>
|
||||||
|
<ComboBox
|
||||||
|
class="file-size-unit-selector"
|
||||||
|
@valueProperty="value"
|
||||||
|
@content={{this.dropdownOptions}}
|
||||||
|
@value={{this.fileSizeUnit}}
|
||||||
|
@onChange={{this.onFileSizeUnitChange}}
|
||||||
|
{{didInsert this.applyUnitChanges}}
|
||||||
|
{{didUpdate this.applyUnitChanges this.pendingFileSizeUnit}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { fn } from "@ember/helper";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { htmlSafe } from "@ember/template";
|
||||||
|
import FileSizeInput from "admin/components/file-size-input";
|
||||||
|
import SettingValidationMessage from "admin/components/setting-validation-message";
|
||||||
|
|
||||||
|
export default class FileSizeRestriction extends Component {
|
||||||
|
@tracked _validationMessage = this.args.validationMessage;
|
||||||
|
|
||||||
|
@action
|
||||||
|
updateValidationMessage(message) {
|
||||||
|
this._validationMessage = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
get validationMessage() {
|
||||||
|
return this._validationMessage ?? this.args.validationMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FileSizeInput
|
||||||
|
@sizeValueKB={{@value}}
|
||||||
|
@onChangeSize={{fn (mut @value)}}
|
||||||
|
@updateValidationMessage={{this.updateValidationMessage}}
|
||||||
|
@min={{if @setting.min @setting.min null}}
|
||||||
|
@max={{if @setting.max @setting.max null}}
|
||||||
|
@message={{this.validationMessage}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingValidationMessage @message={{this.validationMessage}} />
|
||||||
|
<div class="desc">{{htmlSafe @setting.description}}</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -33,6 +33,7 @@ const CUSTOM_TYPES = [
|
|||||||
"simple_list",
|
"simple_list",
|
||||||
"emoji_list",
|
"emoji_list",
|
||||||
"named_list",
|
"named_list",
|
||||||
|
"file_size_restriction",
|
||||||
];
|
];
|
||||||
|
|
||||||
const AUTO_REFRESH_ON_SAVE = ["logo", "logo_small", "large_icon"];
|
const AUTO_REFRESH_ON_SAVE = ["logo", "logo_small", "large_icon"];
|
||||||
|
@ -1,36 +1,13 @@
|
|||||||
import TextField from "discourse/components/text-field";
|
import TextField from "discourse/components/text-field";
|
||||||
|
import { allowOnlyNumericInput } from "discourse/lib/utilities";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
const ALLOWED_KEYS = [
|
|
||||||
"Enter",
|
|
||||||
"Backspace",
|
|
||||||
"Tab",
|
|
||||||
"Delete",
|
|
||||||
"ArrowLeft",
|
|
||||||
"ArrowUp",
|
|
||||||
"ArrowRight",
|
|
||||||
"ArrowDown",
|
|
||||||
"0",
|
|
||||||
"1",
|
|
||||||
"2",
|
|
||||||
"3",
|
|
||||||
"4",
|
|
||||||
"5",
|
|
||||||
"6",
|
|
||||||
"7",
|
|
||||||
"8",
|
|
||||||
"9",
|
|
||||||
];
|
|
||||||
|
|
||||||
export default TextField.extend({
|
export default TextField.extend({
|
||||||
classNameBindings: ["invalid"],
|
classNameBindings: ["invalid"],
|
||||||
|
|
||||||
keyDown: function (event) {
|
keyDown: function (event) {
|
||||||
return (
|
allowOnlyNumericInput(event, this._minNumber && this._minNumber < 0);
|
||||||
ALLOWED_KEYS.includes(event.key) ||
|
|
||||||
(event.key === "-" && this._minNumber && this._minNumber < 0)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
get _minNumber() {
|
get _minNumber() {
|
||||||
|
@ -693,3 +693,34 @@ export function tokenRange(tokens, start, end) {
|
|||||||
|
|
||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function allowOnlyNumericInput(event, allowNegative = false) {
|
||||||
|
const ALLOWED_KEYS = [
|
||||||
|
"Enter",
|
||||||
|
"Backspace",
|
||||||
|
"Tab",
|
||||||
|
"Delete",
|
||||||
|
"ArrowLeft",
|
||||||
|
"ArrowUp",
|
||||||
|
"ArrowRight",
|
||||||
|
"ArrowDown",
|
||||||
|
"0",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"6",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!ALLOWED_KEYS.includes(event.key)) {
|
||||||
|
if (allowNegative && event.key === "-") {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,128 @@
|
|||||||
|
import { click, fillIn, render } from "@ember/test-helpers";
|
||||||
|
import { hbs } from "ember-cli-htmlbars";
|
||||||
|
import { module, test } from "qunit";
|
||||||
|
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||||
|
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||||
|
|
||||||
|
module("Integration | Component | file-size-input", function (hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
|
test("file size unit selector kb", async function (assert) {
|
||||||
|
this.set("value", 1024);
|
||||||
|
this.set("max", 4096);
|
||||||
|
this.set("onChangeSize", () => {});
|
||||||
|
this.set("updateValidationMessage", () => {});
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
<FileSizeInput
|
||||||
|
@sizeValueKB={{readonly this.value}}
|
||||||
|
class="file-size-input-test"
|
||||||
|
@onChangeSize={{this.onChangeSize}}
|
||||||
|
@updateValidationMessage={{this.updateValidationMessage}}
|
||||||
|
@max=4096
|
||||||
|
@message=""
|
||||||
|
/>
|
||||||
|
`);
|
||||||
|
|
||||||
|
assert.dom(".file-size-input").hasValue("1024", "value is present");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("file size unit selector", async function (assert) {
|
||||||
|
this.set("value", 4096);
|
||||||
|
this.set("max", 8192);
|
||||||
|
this.set("onChangeSize", () => {});
|
||||||
|
this.set("updateValidationMessage", () => {});
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
<FileSizeInput
|
||||||
|
@sizeValueKB={{readonly this.value}}
|
||||||
|
class="file-size-input-test"
|
||||||
|
@onChangeSize={{this.onChangeSize}}
|
||||||
|
@updateValidationMessage={{this.updateValidationMessage}}
|
||||||
|
@max=4096
|
||||||
|
@message=""
|
||||||
|
/>
|
||||||
|
`);
|
||||||
|
|
||||||
|
await click(".file-size-unit-selector");
|
||||||
|
|
||||||
|
await selectKit(".file-size-unit-selector").expand();
|
||||||
|
await selectKit(".file-size-unit-selector").selectRowByValue("kb");
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom(".file-size-input")
|
||||||
|
.hasValue("4096", "value is change when then unit is changed");
|
||||||
|
|
||||||
|
await click(".file-size-unit-selector");
|
||||||
|
|
||||||
|
await selectKit(".file-size-unit-selector").expand();
|
||||||
|
await selectKit(".file-size-unit-selector").selectRowByValue("mb");
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom(".file-size-input")
|
||||||
|
.hasValue("4", "value is changed when the unit is changed");
|
||||||
|
|
||||||
|
await click(".file-size-unit-selector");
|
||||||
|
|
||||||
|
await selectKit(".file-size-unit-selector").expand();
|
||||||
|
await selectKit(".file-size-unit-selector").selectRowByValue("gb");
|
||||||
|
|
||||||
|
// TODO: Implement rounding or limit to X digits.
|
||||||
|
assert
|
||||||
|
.dom(".file-size-input")
|
||||||
|
.hasValue(
|
||||||
|
"0.00390625",
|
||||||
|
"value is changed when the unit is changed to gb"
|
||||||
|
);
|
||||||
|
|
||||||
|
await click(".file-size-unit-selector");
|
||||||
|
|
||||||
|
await selectKit(".file-size-unit-selector").expand();
|
||||||
|
await selectKit(".file-size-unit-selector").selectRowByValue("mb");
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom(".file-size-input")
|
||||||
|
.hasValue(
|
||||||
|
"4",
|
||||||
|
"value is changed backed to original size with no decimal places"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("file size input error message", async function (assert) {
|
||||||
|
this.set("value", 4096);
|
||||||
|
this.set("max", 8192);
|
||||||
|
this.set("onChangeSize", () => {});
|
||||||
|
|
||||||
|
let updateValidationMessage = (message) => {
|
||||||
|
this.set("message", message);
|
||||||
|
};
|
||||||
|
this.set("updateValidationMessage", updateValidationMessage);
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
<FileSizeInput
|
||||||
|
@sizeValueKB={{readonly this.value}}
|
||||||
|
class="file-size-input-test"
|
||||||
|
@onChangeSize={{this.onChangeSize}}
|
||||||
|
@updateValidationMessage={{this.updateValidationMessage}}
|
||||||
|
@max={{this.max}}
|
||||||
|
@message={{this.message}}
|
||||||
|
/>
|
||||||
|
`);
|
||||||
|
|
||||||
|
await fillIn(".file-size-input", 12);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
this.message,
|
||||||
|
"12 MB is greater than the max allowed 8 MB",
|
||||||
|
"A message is showed when the input is greater than the max"
|
||||||
|
);
|
||||||
|
|
||||||
|
await fillIn(".file-size-input", 4);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
this.message,
|
||||||
|
null,
|
||||||
|
"The message is cleared when the input is less than the max"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -14,6 +14,7 @@
|
|||||||
@import "date-picker";
|
@import "date-picker";
|
||||||
@import "date-time-input-range";
|
@import "date-time-input-range";
|
||||||
@import "date-time-input";
|
@import "date-time-input";
|
||||||
|
@import "file-size-input";
|
||||||
@import "footer-nav";
|
@import "footer-nav";
|
||||||
@import "form-template-field";
|
@import "form-template-field";
|
||||||
@import "group-member-dropdown";
|
@import "group-member-dropdown";
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
.file-size-picker {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.file-size-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-size-unit-selector {
|
||||||
|
flex: 0 0 8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-kit .select-kit-header {
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,8 @@ class Admin::SiteSettingsController < Admin::AdminController
|
|||||||
case SiteSetting.type_supervisor.get_type(id)
|
case SiteSetting.type_supervisor.get_type(id)
|
||||||
when :integer
|
when :integer
|
||||||
value = value.tr("^-0-9", "")
|
value = value.tr("^-0-9", "")
|
||||||
|
when :file_size_restriction
|
||||||
|
value = value.tr("^-0-9", "")
|
||||||
when :uploaded_image_list
|
when :uploaded_image_list
|
||||||
value = Upload.get_from_urls(value.split("|")).to_a
|
value = Upload.get_from_urls(value.split("|")).to_a
|
||||||
end
|
end
|
||||||
|
@ -2348,6 +2348,10 @@ en:
|
|||||||
from: From
|
from: From
|
||||||
to: To
|
to: To
|
||||||
|
|
||||||
|
file_size_input:
|
||||||
|
error:
|
||||||
|
size_too_large: "%{provided_file_size} is greater than the max allowed %{max_file_size}"
|
||||||
|
|
||||||
emoji_picker:
|
emoji_picker:
|
||||||
filter_placeholder: Search for emoji
|
filter_placeholder: Search for emoji
|
||||||
smileys_&_emotion: Smileys and Emotion
|
smileys_&_emotion: Smileys and Emotion
|
||||||
|
@ -2017,8 +2017,8 @@ en:
|
|||||||
default_dark_mode_color_scheme_id: "The color scheme used when in dark mode."
|
default_dark_mode_color_scheme_id: "The color scheme used when in dark mode."
|
||||||
dark_mode_none: "None"
|
dark_mode_none: "None"
|
||||||
|
|
||||||
max_image_size_kb: "The maximum image upload size in kB. This must be configured in nginx (client_max_body_size) / apache or proxy as well. Images larger than this and smaller than client_max_body_size will be resized to fit on upload."
|
max_image_size_kb: "The maximum image upload size. This must be configured in nginx (client_max_body_size) / apache or proxy as well. Images larger than this and smaller than client_max_body_size will be resized to fit on upload."
|
||||||
max_attachment_size_kb: "The maximum attachment files upload size in kB. This must be configured in nginx (client_max_body_size) / apache or proxy as well."
|
max_attachment_size_kb: "The maximum attachment files upload size. This must be configured in nginx (client_max_body_size) / apache or proxy as well."
|
||||||
authorized_extensions: "A list of file extensions allowed for upload (use '*' to enable all file types)"
|
authorized_extensions: "A list of file extensions allowed for upload (use '*' to enable all file types)"
|
||||||
authorized_extensions_for_staff: "A list of file extensions allowed for upload for staff users in addition to the list defined in the `authorized_extensions` site setting. (use '*' to enable all file types)"
|
authorized_extensions_for_staff: "A list of file extensions allowed for upload for staff users in addition to the list defined in the `authorized_extensions` site setting. (use '*' to enable all file types)"
|
||||||
theme_authorized_extensions: "A list of file extensions allowed for theme uploads (use '*' to enable all file types)"
|
theme_authorized_extensions: "A list of file extensions allowed for theme uploads (use '*' to enable all file types)"
|
||||||
@ -2125,7 +2125,7 @@ en:
|
|||||||
always_show_trimmed_content: "Always show trimmed part of incoming emails. WARNING: might reveal email addresses."
|
always_show_trimmed_content: "Always show trimmed part of incoming emails. WARNING: might reveal email addresses."
|
||||||
trim_incoming_emails: "Trim part of the incoming emails that isn't relevant."
|
trim_incoming_emails: "Trim part of the incoming emails that isn't relevant."
|
||||||
private_email: "Don't include content from posts or topics in email title or email body. NOTE: also disables digest emails."
|
private_email: "Don't include content from posts or topics in email title or email body. NOTE: also disables digest emails."
|
||||||
email_total_attachment_size_limit_kb: "Max total size of files attached to outgoing emails in kB. Set to 0 to disable sending of attachments."
|
email_total_attachment_size_limit_kb: "Max total size of files attached to outgoing emails. Set to 0 to disable sending of attachments."
|
||||||
post_excerpts_in_emails: "In notification emails, always send excerpts instead of full posts"
|
post_excerpts_in_emails: "In notification emails, always send excerpts instead of full posts"
|
||||||
raw_email_max_length: "How many characters should be stored for incoming email."
|
raw_email_max_length: "How many characters should be stored for incoming email."
|
||||||
raw_rejected_email_max_length: "How many characters should be stored for rejected incoming email."
|
raw_rejected_email_max_length: "How many characters should be stored for rejected incoming email."
|
||||||
|
@ -1396,6 +1396,7 @@ email:
|
|||||||
email_total_attachment_size_limit_kb:
|
email_total_attachment_size_limit_kb:
|
||||||
default: 0
|
default: 0
|
||||||
max: 51200
|
max: 51200
|
||||||
|
type: file_size_restriction
|
||||||
post_excerpts_in_emails: false
|
post_excerpts_in_emails: false
|
||||||
raw_email_max_length: 220000
|
raw_email_max_length: 220000
|
||||||
raw_rejected_email_max_length: 4000
|
raw_rejected_email_max_length: 4000
|
||||||
@ -1416,10 +1417,12 @@ files:
|
|||||||
client: true
|
client: true
|
||||||
default: 4096
|
default: 4096
|
||||||
max: 102400
|
max: 102400
|
||||||
|
type: file_size_restriction
|
||||||
max_attachment_size_kb:
|
max_attachment_size_kb:
|
||||||
client: true
|
client: true
|
||||||
default: 4096
|
default: 4096
|
||||||
max: 1024000
|
max: 1024000
|
||||||
|
type: file_size_restriction
|
||||||
max_image_megapixels:
|
max_image_megapixels:
|
||||||
default: 40
|
default: 40
|
||||||
min: 5
|
min: 5
|
||||||
@ -1428,6 +1431,7 @@ files:
|
|||||||
hidden: true
|
hidden: true
|
||||||
default: 50000
|
default: 50000
|
||||||
max: 1024000
|
max: 1024000
|
||||||
|
type: file_size_restriction
|
||||||
theme_authorized_extensions:
|
theme_authorized_extensions:
|
||||||
default: "wasm|jpg|jpeg|png|woff|woff2|svg|eot|ttf|otf|gif|webp|avif|js"
|
default: "wasm|jpg|jpeg|png|woff|woff2|svg|eot|ttf|otf|gif|webp|avif|js"
|
||||||
type: list
|
type: list
|
||||||
@ -1490,6 +1494,7 @@ files:
|
|||||||
default: 1024
|
default: 1024
|
||||||
min: 1
|
min: 1
|
||||||
max: 10240
|
max: 10240
|
||||||
|
type: file_size_restriction
|
||||||
secure_uploads_pm_only:
|
secure_uploads_pm_only:
|
||||||
default: false
|
default: false
|
||||||
hidden: true
|
hidden: true
|
||||||
|
@ -55,6 +55,7 @@ class SiteSettings::TypeSupervisor
|
|||||||
emoji_list: 24,
|
emoji_list: 24,
|
||||||
html_deprecated: 25,
|
html_deprecated: 25,
|
||||||
tag_group_list: 26,
|
tag_group_list: 26,
|
||||||
|
file_size_restriction: 27,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -180,7 +181,7 @@ class SiteSettings::TypeSupervisor
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if type == :integer
|
if type == :integer || type == :file_size_restriction
|
||||||
result[:min] = @validators[name].dig(:opts, :min) if @validators[name].dig(
|
result[:min] = @validators[name].dig(:opts, :min) if @validators[name].dig(
|
||||||
:opts,
|
:opts,
|
||||||
:min,
|
:min,
|
||||||
@ -304,6 +305,8 @@ class SiteSettings::TypeSupervisor
|
|||||||
GroupSettingValidator
|
GroupSettingValidator
|
||||||
when self.class.types[:integer]
|
when self.class.types[:integer]
|
||||||
IntegerSettingValidator
|
IntegerSettingValidator
|
||||||
|
when self.class.types[:file_size_restriction]
|
||||||
|
IntegerSettingValidator
|
||||||
when self.class.types[:regex]
|
when self.class.types[:regex]
|
||||||
RegexSettingValidator
|
RegexSettingValidator
|
||||||
when self.class.types[:string], self.class.types[:list], self.class.types[:enum]
|
when self.class.types[:string], self.class.types[:list], self.class.types[:enum]
|
||||||
|
@ -86,7 +86,7 @@ RSpec.describe ShrinkUploadedImage do
|
|||||||
it "returns false when the upload is above the size limit" do
|
it "returns false when the upload is above the size limit" do
|
||||||
post = Fabricate(:post, raw: "<img src='#{upload.url}'>")
|
post = Fabricate(:post, raw: "<img src='#{upload.url}'>")
|
||||||
post.link_post_uploads
|
post.link_post_uploads
|
||||||
SiteSetting.max_image_size_kb = 0.001 # 1 byte
|
SiteSetting.max_image_size_kb = 0
|
||||||
|
|
||||||
result =
|
result =
|
||||||
ShrinkUploadedImage.new(
|
ShrinkUploadedImage.new(
|
||||||
|
@ -240,7 +240,7 @@ RSpec.describe "tasks/uploads" do
|
|||||||
|
|
||||||
it "updates attributes of uploads that are over the size limit" do
|
it "updates attributes of uploads that are over the size limit" do
|
||||||
upload.update!(thumbnail_height: 0)
|
upload.update!(thumbnail_height: 0)
|
||||||
SiteSetting.max_image_size_kb = 0.001 # 1 byte
|
SiteSetting.max_image_size_kb = 1
|
||||||
|
|
||||||
expect { invoke_task }.to change { upload.reload.thumbnail_height }.to(200)
|
expect { invoke_task }.to change { upload.reload.thumbnail_height }.to(200)
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user