mirror of https://github.com/zulip/zulip.git
thumbnail: Advertize the thumbnail formats at client registration.
This commit is contained in:
parent
6c624805ce
commit
556b92810b
|
@ -20,6 +20,11 @@ format used by the Zulip server that they are interacting with.
|
||||||
|
|
||||||
## Changes in Zulip 9.0
|
## Changes in Zulip 9.0
|
||||||
|
|
||||||
|
**Feature level 273**
|
||||||
|
|
||||||
|
* [`POST /register`](/api/register-queue): Added `server_thumbnail_formats`
|
||||||
|
describing what formats the server will thumbnail images into.
|
||||||
|
|
||||||
**Feature level 272**
|
**Feature level 272**
|
||||||
|
|
||||||
* [`POST /user_uploads`](/api/upload-file): `uri` was renamed
|
* [`POST /user_uploads`](/api/upload-file): `uri` was renamed
|
||||||
|
|
|
@ -252,6 +252,7 @@ EXEMPT_FILES = make_set(
|
||||||
"web/src/submessage.ts",
|
"web/src/submessage.ts",
|
||||||
"web/src/subscriber_api.ts",
|
"web/src/subscriber_api.ts",
|
||||||
"web/src/theme.ts",
|
"web/src/theme.ts",
|
||||||
|
"web/src/thumbnail.ts",
|
||||||
"web/src/timerender.ts",
|
"web/src/timerender.ts",
|
||||||
"web/src/tippyjs.ts",
|
"web/src/tippyjs.ts",
|
||||||
"web/src/todo_widget.js",
|
"web/src/todo_widget.js",
|
||||||
|
|
|
@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
||||||
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
||||||
# entries in the endpoint's documentation in `zulip.yaml`.
|
# entries in the endpoint's documentation in `zulip.yaml`.
|
||||||
|
|
||||||
API_FEATURE_LEVEL = 272 # Last bumped for "POST /user_uploads"
|
API_FEATURE_LEVEL = 273 # Last bumped for server_thumbnail_formats
|
||||||
|
|
||||||
|
|
||||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||||
|
|
|
@ -179,6 +179,14 @@ const one_time_notice_schema = z.object({
|
||||||
type: z.literal("one_time_notice"),
|
type: z.literal("one_time_notice"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const thumbnail_format_schema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
max_width: z.number(),
|
||||||
|
max_height: z.number(),
|
||||||
|
format: z.string(),
|
||||||
|
animated: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
/* We may introduce onboarding step of types other than 'one time notice'
|
/* We may introduce onboarding step of types other than 'one time notice'
|
||||||
in future. Earlier, we had 'hotspot' and 'one time notice' as the two
|
in future. Earlier, we had 'hotspot' and 'one time notice' as the two
|
||||||
types. We can simply do:
|
types. We can simply do:
|
||||||
|
@ -374,6 +382,7 @@ const realm_schema = z.object({
|
||||||
stream: z.record(group_permission_setting_schema),
|
stream: z.record(group_permission_setting_schema),
|
||||||
group: z.record(group_permission_setting_schema),
|
group: z.record(group_permission_setting_schema),
|
||||||
}),
|
}),
|
||||||
|
server_thumbnail_formats: z.array(thumbnail_format_schema),
|
||||||
server_typing_started_expiry_period_milliseconds: z.number(),
|
server_typing_started_expiry_period_milliseconds: z.number(),
|
||||||
server_typing_started_wait_period_milliseconds: z.number(),
|
server_typing_started_wait_period_milliseconds: z.number(),
|
||||||
server_typing_stopped_wait_period_milliseconds: z.number(),
|
server_typing_stopped_wait_period_milliseconds: z.number(),
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import type {z} from "zod";
|
||||||
|
|
||||||
|
import {realm} from "./state_data";
|
||||||
|
import type {thumbnail_format_schema} from "./state_data";
|
||||||
|
|
||||||
|
type ThumbnailFormat = z.infer<typeof thumbnail_format_schema>;
|
||||||
|
|
||||||
|
export const thumbnail_formats: ThumbnailFormat[] = [];
|
||||||
|
|
||||||
|
export let preferred_format: ThumbnailFormat;
|
||||||
|
export let animated_format: ThumbnailFormat;
|
||||||
|
|
||||||
|
export function initialize(): void {
|
||||||
|
// Go looking for the size closest to 300x200, of the smallest format. We assume all browsers
|
||||||
|
// support webp.
|
||||||
|
const format_preferences = ["webp", "jpg", "gif"];
|
||||||
|
const sorted_formats = realm.server_thumbnail_formats.sort((a, b) => {
|
||||||
|
if (a.max_width !== b.max_width) {
|
||||||
|
return Math.abs(a.max_width - 300) < Math.abs(b.max_width - 300) ? -1 : 1;
|
||||||
|
} else if (a.format !== b.format) {
|
||||||
|
let a_index = format_preferences.indexOf(a.format);
|
||||||
|
if (a_index === -1) {
|
||||||
|
a_index = format_preferences.length;
|
||||||
|
}
|
||||||
|
let b_index = format_preferences.indexOf(b.format);
|
||||||
|
if (b_index === -1) {
|
||||||
|
b_index = format_preferences.length;
|
||||||
|
}
|
||||||
|
return a_index - b_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
preferred_format = sorted_formats.find((format) => !format.animated)!;
|
||||||
|
animated_format = sorted_formats.find((format) => format.animated)!;
|
||||||
|
}
|
|
@ -126,6 +126,7 @@ import * as stream_topic_history from "./stream_topic_history";
|
||||||
import * as stream_topic_history_util from "./stream_topic_history_util";
|
import * as stream_topic_history_util from "./stream_topic_history_util";
|
||||||
import * as sub_store from "./sub_store";
|
import * as sub_store from "./sub_store";
|
||||||
import * as theme from "./theme";
|
import * as theme from "./theme";
|
||||||
|
import * as thumbnail from "./thumbnail";
|
||||||
import * as timerender from "./timerender";
|
import * as timerender from "./timerender";
|
||||||
import * as tippyjs from "./tippyjs";
|
import * as tippyjs from "./tippyjs";
|
||||||
import * as topic_list from "./topic_list";
|
import * as topic_list from "./topic_list";
|
||||||
|
@ -426,6 +427,7 @@ export function initialize_everything(state_data) {
|
||||||
if (page_params.is_spectator) {
|
if (page_params.is_spectator) {
|
||||||
theme.initialize_theme_for_spectator();
|
theme.initialize_theme_for_spectator();
|
||||||
}
|
}
|
||||||
|
thumbnail.initialize();
|
||||||
widgets.initialize();
|
widgets.initialize();
|
||||||
tippyjs.initialize();
|
tippyjs.initialize();
|
||||||
compose_tooltips.initialize();
|
compose_tooltips.initialize();
|
||||||
|
|
|
@ -54,6 +54,7 @@ from zerver.lib.subscription_info import (
|
||||||
gather_subscriptions_helper,
|
gather_subscriptions_helper,
|
||||||
get_web_public_subs,
|
get_web_public_subs,
|
||||||
)
|
)
|
||||||
|
from zerver.lib.thumbnail import THUMBNAIL_OUTPUT_FORMATS
|
||||||
from zerver.lib.timestamp import datetime_to_timestamp
|
from zerver.lib.timestamp import datetime_to_timestamp
|
||||||
from zerver.lib.timezone import canonicalize_timezone
|
from zerver.lib.timezone import canonicalize_timezone
|
||||||
from zerver.lib.topic import TOPIC_NAME
|
from zerver.lib.topic import TOPIC_NAME
|
||||||
|
@ -381,6 +382,16 @@ def fetch_initial_state_data(
|
||||||
state["password_min_guesses"] = settings.PASSWORD_MIN_GUESSES
|
state["password_min_guesses"] = settings.PASSWORD_MIN_GUESSES
|
||||||
state["server_inline_image_preview"] = settings.INLINE_IMAGE_PREVIEW
|
state["server_inline_image_preview"] = settings.INLINE_IMAGE_PREVIEW
|
||||||
state["server_inline_url_embed_preview"] = settings.INLINE_URL_EMBED_PREVIEW
|
state["server_inline_url_embed_preview"] = settings.INLINE_URL_EMBED_PREVIEW
|
||||||
|
state["server_thumbnail_formats"] = [
|
||||||
|
{
|
||||||
|
"name": str(thumbnail_format),
|
||||||
|
"max_width": thumbnail_format.max_width,
|
||||||
|
"max_height": thumbnail_format.max_height,
|
||||||
|
"format": thumbnail_format.extension,
|
||||||
|
"animated": thumbnail_format.animated,
|
||||||
|
}
|
||||||
|
for thumbnail_format in THUMBNAIL_OUTPUT_FORMATS
|
||||||
|
]
|
||||||
state["server_avatar_changes_disabled"] = settings.AVATAR_CHANGES_DISABLED
|
state["server_avatar_changes_disabled"] = settings.AVATAR_CHANGES_DISABLED
|
||||||
state["server_name_changes_disabled"] = settings.NAME_CHANGES_DISABLED
|
state["server_name_changes_disabled"] = settings.NAME_CHANGES_DISABLED
|
||||||
state["server_web_public_streams_enabled"] = settings.WEB_PUBLIC_STREAMS_ENABLED
|
state["server_web_public_streams_enabled"] = settings.WEB_PUBLIC_STREAMS_ENABLED
|
||||||
|
|
|
@ -16397,6 +16397,43 @@ paths:
|
||||||
Clients containing administrative UI for changing
|
Clients containing administrative UI for changing
|
||||||
`realm_inline_url_embed_preview` should consult this field before offering
|
`realm_inline_url_embed_preview` should consult this field before offering
|
||||||
that feature.
|
that feature.
|
||||||
|
server_thumbnail_formats:
|
||||||
|
description: |
|
||||||
|
A list describing the image formats that uploaded
|
||||||
|
images will be thumbnailed into. Any image with a
|
||||||
|
source starting with `/user_uploads/thumbnail/` can
|
||||||
|
have its last path component replaced with any of the
|
||||||
|
names contained in this list, to obtain the desired
|
||||||
|
thumbnail size.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 9.0 (feature level 273).
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
The file path component of the thumbnail format.
|
||||||
|
max_width:
|
||||||
|
type: integer
|
||||||
|
description: |
|
||||||
|
The maximum width of this format.
|
||||||
|
max_height:
|
||||||
|
type: integer
|
||||||
|
description: |
|
||||||
|
The maximum height of this format.
|
||||||
|
format:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
The extension of this format.
|
||||||
|
animated:
|
||||||
|
type: boolean
|
||||||
|
description: |
|
||||||
|
If this file format is animated. These formats
|
||||||
|
are only generated for uploaded imates which
|
||||||
|
themselves are animated.
|
||||||
server_avatar_changes_disabled:
|
server_avatar_changes_disabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: |
|
description: |
|
||||||
|
|
|
@ -219,6 +219,7 @@ class HomeTest(ZulipTestCase):
|
||||||
"server_presence_offline_threshold_seconds",
|
"server_presence_offline_threshold_seconds",
|
||||||
"server_presence_ping_interval_seconds",
|
"server_presence_ping_interval_seconds",
|
||||||
"server_supported_permission_settings",
|
"server_supported_permission_settings",
|
||||||
|
"server_thumbnail_formats",
|
||||||
"server_timestamp",
|
"server_timestamp",
|
||||||
"server_typing_started_expiry_period_milliseconds",
|
"server_typing_started_expiry_period_milliseconds",
|
||||||
"server_typing_started_wait_period_milliseconds",
|
"server_typing_started_wait_period_milliseconds",
|
||||||
|
|
Loading…
Reference in New Issue