mirror of https://github.com/zulip/zulip.git
realm: Add maximum file size upload restriction.
This commit adds a restriction to the maximum file size that can be uploaded to a realm based on its plan_type.
This commit is contained in:
parent
808acc9e47
commit
3314c89288
|
@ -28,6 +28,11 @@ format used by the Zulip server that they are interacting with.
|
|||
a standard `realm/update_dict` event to notify clients about changes
|
||||
in `plan_type` and other fields that atomically change with a given
|
||||
change in plan.
|
||||
* [`GET /events`](/api/get-events): Added `max_file_upload_size_mib`
|
||||
field to the `data` object in `realm/update_dict` event format;
|
||||
previously, this was a constant. Note that the field does not have a
|
||||
`realm_` prefix in the [`POST /register`](/api/register-queue)
|
||||
response.
|
||||
|
||||
**Feature level 305**
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
|||
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
||||
# entries in the endpoint's documentation in `zulip.yaml`.
|
||||
|
||||
API_FEATURE_LEVEL = 305 # Last bumped for adding can_add_members_group to usergroup.
|
||||
API_FEATURE_LEVEL = 306 # Last bumped for adding `max_file_upload_size_mib`.
|
||||
|
||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||
# only when going from an old version of the code to a newer version. Bump
|
||||
|
|
|
@ -284,7 +284,12 @@ export function dispatch_normal_event(event) {
|
|||
switch (event.property) {
|
||||
case "default":
|
||||
for (const [key, value] of Object.entries(event.data)) {
|
||||
realm["realm_" + key] = value;
|
||||
if (key === "max_file_upload_size_mib") {
|
||||
realm[key] = value;
|
||||
} else {
|
||||
realm["realm_" + key] = value;
|
||||
}
|
||||
|
||||
if (Object.hasOwn(realm_settings, key)) {
|
||||
settings_org.sync_realm_settings(key);
|
||||
}
|
||||
|
|
|
@ -586,6 +586,7 @@ run_test("realm settings", ({override}) => {
|
|||
override(realm, "realm_direct_message_permission_group", 1);
|
||||
override(realm, "realm_plan_type", 2);
|
||||
override(realm, "realm_upload_quota_mib", 5000);
|
||||
override(realm, "max_file_upload_size_mib", 10);
|
||||
override(settings_org, "populate_auth_methods", noop);
|
||||
dispatch(event);
|
||||
assert_same(realm.realm_create_multiuse_invite_group, 3);
|
||||
|
@ -599,6 +600,7 @@ run_test("realm settings", ({override}) => {
|
|||
assert_same(realm.realm_direct_message_permission_group, 3);
|
||||
assert_same(realm.realm_plan_type, 3);
|
||||
assert_same(realm.realm_upload_quota_mib, 50000);
|
||||
assert_same(realm.max_file_upload_size_mib, 1024);
|
||||
assert_same(update_stream_privacy_choices_called, true);
|
||||
|
||||
event = event_fixtures.realm__update_dict__icon;
|
||||
|
|
|
@ -372,6 +372,7 @@ exports.fixtures = {
|
|||
direct_message_permission_group: 3,
|
||||
plan_type: 3,
|
||||
upload_quota_mib: 50000,
|
||||
max_file_upload_size_mib: 1024,
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
@ -794,6 +794,7 @@ def do_change_realm_plan_type(
|
|||
data={
|
||||
"plan_type": plan_type,
|
||||
"upload_quota_mib": optional_bytes_to_mib(realm.upload_quota_bytes()),
|
||||
"max_file_upload_size_mib": realm.get_max_file_upload_size_mebibytes(),
|
||||
},
|
||||
)
|
||||
send_event_on_commit(realm, event, active_user_ids(realm.id))
|
||||
|
|
|
@ -1075,6 +1075,7 @@ plan_type_data = DictType(
|
|||
required_keys=[
|
||||
("plan_type", int),
|
||||
("upload_quota_mib", OptionalType(int)),
|
||||
("max_file_upload_size_mib", int),
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -350,7 +350,7 @@ def fetch_initial_state_data(
|
|||
|
||||
# Important: Encode units in the client-facing API name.
|
||||
state["max_avatar_file_size_mib"] = settings.MAX_AVATAR_FILE_SIZE_MIB
|
||||
state["max_file_upload_size_mib"] = settings.MAX_FILE_UPLOAD_SIZE
|
||||
state["max_file_upload_size_mib"] = realm.get_max_file_upload_size_mebibytes()
|
||||
state["max_icon_file_size_mib"] = settings.MAX_ICON_FILE_SIZE_MIB
|
||||
upload_quota_bytes = realm.upload_quota_bytes()
|
||||
state["realm_upload_quota_mib"] = optional_bytes_to_mib(upload_quota_bytes)
|
||||
|
@ -1308,6 +1308,10 @@ def apply_event(
|
|||
)
|
||||
elif event["op"] == "update_dict":
|
||||
for key, value in event["data"].items():
|
||||
if key == "max_file_upload_size_mib":
|
||||
state["max_file_upload_size_mib"] = value
|
||||
continue
|
||||
|
||||
state["realm_" + key] = value
|
||||
# It's a bit messy, but this is where we need to
|
||||
# update the state for whether password authentication
|
||||
|
|
|
@ -1011,6 +1011,21 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub
|
|||
# it as gibibytes (GiB) to be a bit more generous in case of confusion.
|
||||
return self.upload_quota_gb << 30
|
||||
|
||||
def get_max_file_upload_size_mebibytes(self) -> int:
|
||||
plan_type = self.plan_type
|
||||
if plan_type == Realm.PLAN_TYPE_SELF_HOSTED:
|
||||
return settings.MAX_FILE_UPLOAD_SIZE
|
||||
elif plan_type == Realm.PLAN_TYPE_LIMITED:
|
||||
return 10
|
||||
elif plan_type in [
|
||||
Realm.PLAN_TYPE_STANDARD,
|
||||
Realm.PLAN_TYPE_STANDARD_FREE,
|
||||
Realm.PLAN_TYPE_PLUS,
|
||||
]:
|
||||
return 1024
|
||||
else:
|
||||
raise AssertionError("Invalid plan type")
|
||||
|
||||
# `realm` instead of `self` here to make sure the parameters of the cache key
|
||||
# function matches the original method.
|
||||
@cache_with_key(
|
||||
|
|
|
@ -4679,6 +4679,14 @@ paths:
|
|||
type: boolean
|
||||
description: |
|
||||
Whether [topics are required](/help/require-topics) for messages in this organization.
|
||||
max_file_upload_size_mib:
|
||||
type: integer
|
||||
description: |
|
||||
The new maximum file size that can be uploaded to this Zulip organization.
|
||||
|
||||
**Changes**: New in Zulip 10.0 (feature level 306). Previously, this field of
|
||||
the core state did not support being updated via the events system, as it was
|
||||
typically hardcoded for a given Zulip installation.
|
||||
message_content_allowed_in_email_notifications:
|
||||
type: boolean
|
||||
description: |
|
||||
|
@ -17320,7 +17328,7 @@ paths:
|
|||
description: |
|
||||
Present if `realm` is present in `fetch_event_types`.
|
||||
|
||||
The maximum file size that can be uploaded to this Zulip server.
|
||||
The maximum file size that can be uploaded to this Zulip organization.
|
||||
max_avatar_file_size_mib:
|
||||
type: integer
|
||||
description: |
|
||||
|
|
|
@ -99,10 +99,11 @@ def handle_upload_pre_create_hook(
|
|||
if data.size_is_deferred or data.size is None:
|
||||
return reject_upload("SizeIsDeferred is not supported", 411)
|
||||
|
||||
if data.size > settings.MAX_FILE_UPLOAD_SIZE * 1024 * 1024:
|
||||
max_file_upload_size_mebibytes = user_profile.realm.get_max_file_upload_size_mebibytes()
|
||||
if data.size > max_file_upload_size_mebibytes * 1024 * 1024:
|
||||
return reject_upload(
|
||||
_("Uploaded file is larger than the allowed limit of {max_file_size} MiB").format(
|
||||
max_file_size=settings.MAX_FILE_UPLOAD_SIZE
|
||||
max_file_size=max_file_upload_size_mebibytes
|
||||
),
|
||||
413,
|
||||
)
|
||||
|
|
|
@ -448,10 +448,11 @@ def upload_file_backend(request: HttpRequest, user_profile: UserProfile) -> Http
|
|||
assert isinstance(user_file, UploadedFile)
|
||||
file_size = user_file.size
|
||||
assert file_size is not None
|
||||
if file_size > settings.MAX_FILE_UPLOAD_SIZE * 1024 * 1024:
|
||||
max_file_upload_size_mebibytes = user_profile.realm.get_max_file_upload_size_mebibytes()
|
||||
if file_size > max_file_upload_size_mebibytes * 1024 * 1024:
|
||||
raise JsonableError(
|
||||
_("Uploaded file is larger than the allowed limit of {max_size} MiB").format(
|
||||
max_size=settings.MAX_FILE_UPLOAD_SIZE,
|
||||
max_size=max_file_upload_size_mebibytes,
|
||||
)
|
||||
)
|
||||
check_upload_within_quota(user_profile.realm, file_size)
|
||||
|
|
Loading…
Reference in New Issue