mirror of https://github.com/zulip/zulip.git
page_params: Parse page_params and state_data with Zod.
This establishes a runtime check that their types continue to reflect reality going forward. Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
4f1659fe8f
commit
a4938d3760
|
@ -80,7 +80,9 @@ def render_stats(
|
|||
translation.get_language_from_path(request.path_info),
|
||||
)
|
||||
|
||||
# Sync this with stats_params_schema in base_page_params.ts.
|
||||
page_params = dict(
|
||||
page_type="stats",
|
||||
data_url_suffix=data_url_suffix,
|
||||
upload_space_used=space_used,
|
||||
guest_users=guest_users,
|
||||
|
|
|
@ -8,7 +8,18 @@ from datetime import datetime, timedelta, timezone
|
|||
from decimal import Decimal
|
||||
from enum import Enum
|
||||
from functools import wraps
|
||||
from typing import Any, Callable, Dict, Generator, Optional, Tuple, TypedDict, TypeVar, Union
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
Dict,
|
||||
Generator,
|
||||
Literal,
|
||||
Optional,
|
||||
Tuple,
|
||||
TypedDict,
|
||||
TypeVar,
|
||||
Union,
|
||||
)
|
||||
from urllib.parse import urlencode, urljoin
|
||||
|
||||
import stripe
|
||||
|
@ -615,7 +626,9 @@ class BillingSessionAuditLogEventError(Exception):
|
|||
super().__init__(self.message)
|
||||
|
||||
|
||||
# Sync this with upgrade_params_schema in base_page_params.ts.
|
||||
class UpgradePageParams(TypedDict):
|
||||
page_type: Literal["upgrade"]
|
||||
annual_price: int
|
||||
demo_organization_scheduled_deletion_date: Optional[datetime]
|
||||
monthly_price: int
|
||||
|
@ -2395,6 +2408,7 @@ class BillingSession(ABC):
|
|||
"remote_server_legacy_plan_end_date": remote_server_legacy_plan_end_date,
|
||||
"manual_license_management": initial_upgrade_request.manual_license_management,
|
||||
"page_params": {
|
||||
"page_type": "upgrade",
|
||||
"annual_price": get_price_per_license(
|
||||
tier, CustomerPlan.BILLING_SCHEDULE_ANNUAL, percent_off
|
||||
),
|
||||
|
|
|
@ -278,7 +278,9 @@ def team_view(request: HttpRequest) -> HttpResponse:
|
|||
request,
|
||||
"corporate/team.html",
|
||||
context={
|
||||
# Sync this with team_params_schema in base_page_params.ts.
|
||||
"page_params": {
|
||||
"page_type": "team",
|
||||
"contributors": data["contributors"],
|
||||
},
|
||||
"date": data["date"],
|
||||
|
|
|
@ -56,6 +56,7 @@ EXEMPT_FILES = make_set(
|
|||
"web/src/attachments_ui.ts",
|
||||
"web/src/audible_notifications.ts",
|
||||
"web/src/avatar.ts",
|
||||
"web/src/base_page_params.ts",
|
||||
"web/src/billing/event_status.ts",
|
||||
"web/src/billing/helpers.ts",
|
||||
"web/src/blueslip.ts",
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
import $ from "jquery";
|
||||
import {z} from "zod";
|
||||
|
||||
import {state_data_schema, term_schema} from "./state_data";
|
||||
|
||||
const t1 = performance.now();
|
||||
|
||||
// Sync this with zerver.context_processors.zulip_default_context.
|
||||
const default_params_schema = z.object({
|
||||
page_type: z.literal("default"),
|
||||
development_environment: z.boolean(),
|
||||
realm_sentry_key: z.optional(z.string()),
|
||||
request_language: z.string(),
|
||||
server_sentry_dsn: z.nullable(z.string()),
|
||||
server_sentry_environment: z.optional(z.string()),
|
||||
server_sentry_sample_rate: z.optional(z.number()),
|
||||
server_sentry_trace_rate: z.optional(z.number()),
|
||||
});
|
||||
|
||||
// These parameters are sent in #page-params for both users and spectators.
|
||||
//
|
||||
// Sync this with zerver.lib.home.build_page_params_for_home_page_load.
|
||||
const home_params_schema = default_params_schema
|
||||
.extend({
|
||||
page_type: z.literal("home"),
|
||||
apps_page_url: z.string(),
|
||||
bot_types: z.array(
|
||||
z.object({
|
||||
type_id: z.number(),
|
||||
name: z.string(),
|
||||
allowed: z.boolean(),
|
||||
}),
|
||||
),
|
||||
corporate_enabled: z.boolean(),
|
||||
furthest_read_time: z.nullable(z.number()),
|
||||
is_spectator: z.boolean(),
|
||||
language_list: z.array(
|
||||
z.object({
|
||||
code: z.string(),
|
||||
locale: z.string(),
|
||||
name: z.string(),
|
||||
percent_translated: z.optional(z.number()),
|
||||
}),
|
||||
),
|
||||
login_page: z.string(),
|
||||
narrow: z.optional(z.array(term_schema)),
|
||||
narrow_stream: z.optional(z.string()),
|
||||
needs_tutorial: z.boolean(),
|
||||
promote_sponsoring_zulip: z.boolean(),
|
||||
show_billing: z.boolean(),
|
||||
show_plans: z.boolean(),
|
||||
show_webathena: z.boolean(),
|
||||
sponsorship_pending: z.boolean(),
|
||||
state_data: state_data_schema.optional(),
|
||||
translation_data: z.record(z.string()),
|
||||
})
|
||||
// TODO/typescript: Remove .passthrough() when all consumers have been
|
||||
// converted to TypeScript and the schema is complete.
|
||||
.passthrough();
|
||||
|
||||
// Sync this with analytics.views.stats.render_stats.
|
||||
const stats_params_schema = default_params_schema.extend({
|
||||
page_type: z.literal("stats"),
|
||||
data_url_suffix: z.string(),
|
||||
upload_space_used: z.nullable(z.number()),
|
||||
guest_users: z.nullable(z.number()),
|
||||
translation_data: z.record(z.string()),
|
||||
});
|
||||
|
||||
// Sync this with corporate.views.portico.team_view.
|
||||
const team_params_schema = default_params_schema.extend({
|
||||
page_type: z.literal("team"),
|
||||
contributors: z.unknown(),
|
||||
});
|
||||
|
||||
// Sync this with corporate.lib.stripe.UpgradePageParams.
|
||||
const upgrade_params_schema = default_params_schema.extend({
|
||||
page_type: z.literal("upgrade"),
|
||||
annual_price: z.number(),
|
||||
demo_organization_scheduled_deletion_date: z.nullable(z.number()),
|
||||
monthly_price: z.number(),
|
||||
seat_count: z.number(),
|
||||
billing_base_url: z.string(),
|
||||
tier: z.number(),
|
||||
flat_discount: z.number(),
|
||||
flat_discounted_months: z.number(),
|
||||
fixed_price: z.number().nullable(),
|
||||
});
|
||||
|
||||
const page_params_schema = z.discriminatedUnion("page_type", [
|
||||
default_params_schema,
|
||||
home_params_schema,
|
||||
stats_params_schema,
|
||||
team_params_schema,
|
||||
upgrade_params_schema,
|
||||
]);
|
||||
|
||||
export const page_params = page_params_schema.parse($("#page-params").remove().data("params"));
|
||||
|
||||
const t2 = performance.now();
|
||||
export const page_params_parse_time = t2 - t1;
|
|
@ -1,19 +1,9 @@
|
|||
import $ from "jquery";
|
||||
import assert from "minimalistic-assert";
|
||||
|
||||
// Don't remove page_params here yet, since we still use them later.
|
||||
// For example, "#page_params" is used again through `sentry.ts`, which
|
||||
// imports the main `src/page_params` module.
|
||||
export const page_params: {
|
||||
annual_price: number;
|
||||
monthly_price: number;
|
||||
seat_count: number;
|
||||
billing_base_url: string;
|
||||
tier: number;
|
||||
flat_discount: number;
|
||||
flat_discounted_months: number;
|
||||
fixed_price: number | null;
|
||||
} = $("#page-params").data("params");
|
||||
import {page_params as base_page_params} from "../base_page_params";
|
||||
|
||||
if (!page_params) {
|
||||
throw new Error("Missing page-params");
|
||||
}
|
||||
assert(base_page_params.page_type === "upgrade");
|
||||
|
||||
// We need to export with a narrowed TypeScript type
|
||||
// eslint-disable-next-line unicorn/prefer-export-from
|
||||
export const page_params = base_page_params;
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
import * as Sentry from "@sentry/browser";
|
||||
import $ from "jquery";
|
||||
|
||||
import {page_params} from "./base_page_params";
|
||||
import {BlueslipError, display_stacktrace} from "./blueslip_stacktrace";
|
||||
import {page_params} from "./page_params";
|
||||
|
||||
if (Error.stackTraceLimit !== undefined) {
|
||||
Error.stackTraceLimit = 100000;
|
||||
|
|
|
@ -12,6 +12,7 @@ import type {Message} from "./message_store";
|
|||
import {page_params} from "./page_params";
|
||||
import * as people from "./people";
|
||||
import {realm} from "./state_data";
|
||||
import type {Term} from "./state_data";
|
||||
import * as stream_data from "./stream_data";
|
||||
import type {StreamSubscription} from "./sub_store";
|
||||
import * as unread from "./unread";
|
||||
|
@ -234,12 +235,6 @@ function message_matches_search_term(message: Message, operator: string, operand
|
|||
return true; // unknown operators return true (effectively ignored)
|
||||
}
|
||||
|
||||
export type Term = {
|
||||
negated?: boolean;
|
||||
operator: string;
|
||||
operand: string;
|
||||
};
|
||||
|
||||
export class Filter {
|
||||
_terms: Term[];
|
||||
_sub?: StreamSubscription;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {realm} from "./state_data";
|
||||
import type {GroupPermissionSetting} from "./types";
|
||||
import type {GroupPermissionSetting} from "./state_data";
|
||||
|
||||
export function get_group_permission_setting_config(
|
||||
setting_name: string,
|
||||
|
|
|
@ -6,14 +6,14 @@ import {DEFAULT_INTL_CONFIG, IntlErrorCode, createIntl, createIntlCache} from "@
|
|||
import type {FormatXMLElementFn, PrimitiveType} from "intl-messageformat";
|
||||
import _ from "lodash";
|
||||
|
||||
import {page_params} from "./page_params";
|
||||
import {page_params} from "./base_page_params";
|
||||
|
||||
const cache = createIntlCache();
|
||||
export const intl = createIntl(
|
||||
{
|
||||
locale: page_params.request_language,
|
||||
defaultLocale: "en",
|
||||
messages: page_params.translation_data,
|
||||
messages: "translation_data" in page_params ? page_params.translation_data : {},
|
||||
/* istanbul ignore next */
|
||||
onError(error) {
|
||||
// Ignore complaints about untranslated strings that were
|
||||
|
@ -50,7 +50,7 @@ export function $t_html(
|
|||
});
|
||||
}
|
||||
|
||||
export let language_list: (typeof page_params)["language_list"];
|
||||
export let language_list: (typeof page_params & {page_type: "home"})["language_list"];
|
||||
|
||||
export function get_language_name(language_code: string): string {
|
||||
const language_list_map: Record<string, string> = {};
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import * as blueslip from "./blueslip";
|
||||
import {Filter} from "./filter";
|
||||
import type {Term} from "./filter";
|
||||
import * as inbox_util from "./inbox_util";
|
||||
import {page_params} from "./page_params";
|
||||
import * as people from "./people";
|
||||
import * as recent_view_util from "./recent_view_util";
|
||||
import type {Term} from "./state_data";
|
||||
import * as stream_data from "./stream_data";
|
||||
import type {StreamSubscription} from "./sub_store";
|
||||
import * as unread from "./unread";
|
||||
|
|
|
@ -1,44 +1,9 @@
|
|||
import $ from "jquery";
|
||||
import assert from "minimalistic-assert";
|
||||
|
||||
import type {Term} from "./filter";
|
||||
import {page_params as base_page_params} from "./base_page_params";
|
||||
|
||||
const t1 = performance.now();
|
||||
export const page_params: {
|
||||
apps_page_url: string;
|
||||
bot_types: {
|
||||
type_id: number;
|
||||
name: string;
|
||||
allowed: boolean;
|
||||
}[];
|
||||
corporate_enabled: boolean;
|
||||
development_environment: boolean;
|
||||
furthest_read_time: number | null;
|
||||
is_spectator: boolean;
|
||||
language_list: {
|
||||
code: string;
|
||||
locale: string;
|
||||
name: string;
|
||||
percent_translated?: number;
|
||||
}[];
|
||||
login_page: string;
|
||||
narrow?: Term[];
|
||||
narrow_stream?: string;
|
||||
needs_tutorial: boolean;
|
||||
promote_sponsoring_zulip: boolean;
|
||||
realm_sentry_key?: string;
|
||||
request_language: string;
|
||||
server_sentry_dsn: string | null;
|
||||
server_sentry_environment?: string;
|
||||
server_sentry_sample_rate?: number;
|
||||
server_sentry_trace_rate?: number;
|
||||
show_billing: boolean;
|
||||
show_plans: boolean;
|
||||
show_webathena: boolean;
|
||||
sponsorship_pending: boolean;
|
||||
translation_data: Record<string, string>;
|
||||
} = $("#page-params").remove().data("params");
|
||||
const t2 = performance.now();
|
||||
export const page_params_parse_time = t2 - t1;
|
||||
if (!page_params) {
|
||||
throw new Error("Missing page-params");
|
||||
}
|
||||
assert(base_page_params.page_type === "home");
|
||||
|
||||
// We need to export with a narrowed TypeScript type.
|
||||
// eslint-disable-next-line unicorn/prefer-export-from
|
||||
export const page_params = base_page_params;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {gtag, install} from "ga-gtag";
|
||||
|
||||
import {page_params} from "../page_params";
|
||||
import {page_params} from "../base_page_params";
|
||||
|
||||
export let config;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import $ from "jquery";
|
||||
import assert from "minimalistic-assert";
|
||||
|
||||
import {page_params} from "../page_params";
|
||||
import {page_params} from "../base_page_params";
|
||||
|
||||
import {detect_user_os} from "./tabbed-instructions";
|
||||
import render_tabs from "./team";
|
||||
|
@ -119,6 +120,7 @@ $(() => {
|
|||
events();
|
||||
|
||||
if (window.location.pathname === "/team/") {
|
||||
assert(page_params.page_type === "team");
|
||||
const contributors = page_params.contributors;
|
||||
delete page_params.contributors;
|
||||
render_tabs(contributors);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as Sentry from "@sentry/browser";
|
||||
|
||||
import {page_params} from "./page_params";
|
||||
import {page_params} from "./base_page_params";
|
||||
import {current_user, realm} from "./state_data";
|
||||
|
||||
type UserInfo = {
|
||||
|
@ -76,7 +76,11 @@ if (page_params.server_sentry_dsn) {
|
|||
const user_info: UserInfo = {
|
||||
realm: sentry_key,
|
||||
};
|
||||
if (sentry_key !== "www" && current_user !== undefined) {
|
||||
if (
|
||||
sentry_key !== "www" &&
|
||||
page_params.page_type === "home" &&
|
||||
current_user !== undefined
|
||||
) {
|
||||
user_info.role = current_user.is_owner
|
||||
? "Organization owner"
|
||||
: current_user.is_admin
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Handlebars from "handlebars/runtime";
|
||||
|
||||
import {page_params} from "./base_page_params";
|
||||
import {$t, $t_html} from "./i18n";
|
||||
import {page_params} from "./page_params";
|
||||
import type {RealmDefaultSettings} from "./realm_user_settings_defaults";
|
||||
import {realm} from "./state_data";
|
||||
import type {StreamSpecificNotificationSettings} from "./sub_store";
|
||||
|
|
|
@ -1,131 +1,145 @@
|
|||
import type {GroupPermissionSetting} from "./types";
|
||||
import {z} from "zod";
|
||||
|
||||
export let current_user: {
|
||||
avatar_source: string;
|
||||
delivery_email: string;
|
||||
is_admin: boolean;
|
||||
is_billing_admin: boolean;
|
||||
is_guest: boolean;
|
||||
is_moderator: boolean;
|
||||
is_owner: boolean;
|
||||
user_id: number;
|
||||
};
|
||||
const group_permission_setting_schema = z.object({
|
||||
require_system_group: z.boolean(),
|
||||
allow_internet_group: z.boolean(),
|
||||
allow_owners_group: z.boolean(),
|
||||
allow_nobody_group: z.boolean(),
|
||||
allow_everyone_group: z.boolean(),
|
||||
default_group_name: z.string(),
|
||||
id_field_name: z.string(),
|
||||
default_for_system_groups: z.nullable(z.string()),
|
||||
allowed_system_groups: z.array(z.string()),
|
||||
});
|
||||
export type GroupPermissionSetting = z.output<typeof group_permission_setting_schema>;
|
||||
|
||||
export let realm: {
|
||||
custom_profile_fields: {
|
||||
display_in_profile_summary?: boolean;
|
||||
field_data: string;
|
||||
hint: string;
|
||||
id: number;
|
||||
name: string;
|
||||
order: number;
|
||||
type: number;
|
||||
}[];
|
||||
custom_profile_field_types: {
|
||||
SHORT_TEXT: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
LONG_TEXT: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
DATE: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
SELECT: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
URL: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
EXTERNAL_ACCOUNT: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
USER: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
PRONOUNS: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
};
|
||||
max_avatar_file_size_mib: number;
|
||||
max_icon_file_size_mib: number;
|
||||
max_logo_file_size_mib: number;
|
||||
realm_add_custom_emoji_policy: number;
|
||||
realm_available_video_chat_providers: {
|
||||
disabled: {name: string; id: number};
|
||||
jitsi_meet: {name: string; id: number};
|
||||
zoom?: {name: string; id: number};
|
||||
big_blue_button?: {name: string; id: number};
|
||||
};
|
||||
realm_avatar_changes_disabled: boolean;
|
||||
realm_bot_domain: string;
|
||||
realm_can_access_all_users_group: number;
|
||||
realm_create_multiuse_invite_group: number;
|
||||
realm_create_private_stream_policy: number;
|
||||
realm_create_public_stream_policy: number;
|
||||
realm_create_web_public_stream_policy: number;
|
||||
realm_delete_own_message_policy: number;
|
||||
realm_description: string;
|
||||
realm_domains: {domain: string; allow_subdomains: boolean}[];
|
||||
realm_edit_topic_policy: number;
|
||||
realm_email_changes_disabled: boolean;
|
||||
realm_enable_guest_user_indicator: boolean;
|
||||
realm_enable_spectator_access: boolean;
|
||||
realm_icon_source: string;
|
||||
realm_icon_url: string;
|
||||
realm_invite_to_realm_policy: number;
|
||||
realm_invite_to_stream_policy: number;
|
||||
realm_is_zephyr_mirror_realm: boolean;
|
||||
realm_jitsi_server_url: string | null;
|
||||
realm_logo_source: string;
|
||||
realm_logo_url: string;
|
||||
realm_move_messages_between_streams_policy: number;
|
||||
realm_name_changes_disabled: boolean;
|
||||
realm_name: string;
|
||||
realm_night_logo_source: string;
|
||||
realm_night_logo_url: string;
|
||||
realm_notifications_stream_id: number;
|
||||
realm_org_type: number;
|
||||
realm_plan_type: number;
|
||||
realm_private_message_policy: number;
|
||||
realm_push_notifications_enabled: boolean;
|
||||
realm_upload_quota_mib: number | null;
|
||||
realm_uri: string;
|
||||
realm_user_group_edit_policy: number;
|
||||
realm_video_chat_provider: number;
|
||||
realm_waiting_period_threshold: number;
|
||||
server_avatar_changes_disabled: boolean;
|
||||
server_jitsi_server_url: string | null;
|
||||
server_name_changes_disabled: boolean;
|
||||
server_needs_upgrade: boolean;
|
||||
server_presence_offline_threshold_seconds: number;
|
||||
server_supported_permission_settings: {
|
||||
realm: Record<string, GroupPermissionSetting>;
|
||||
stream: Record<string, GroupPermissionSetting>;
|
||||
group: Record<string, GroupPermissionSetting>;
|
||||
};
|
||||
server_typing_started_expiry_period_milliseconds: number;
|
||||
server_typing_started_wait_period_milliseconds: number;
|
||||
server_typing_stopped_wait_period_milliseconds: number;
|
||||
server_web_public_streams_enabled: boolean;
|
||||
stop_words: string[];
|
||||
zulip_merge_base: string;
|
||||
zulip_plan_is_not_limited: boolean;
|
||||
zulip_version: string;
|
||||
};
|
||||
export const term_schema = z.object({
|
||||
negated: z.optional(z.boolean()),
|
||||
operator: z.string(),
|
||||
operand: z.string(),
|
||||
});
|
||||
export type Term = z.output<typeof term_schema>;
|
||||
// Sync this with zerver.lib.events.do_events_register.
|
||||
|
||||
export function set_current_user(initial_current_user: typeof current_user): void {
|
||||
export const current_user_schema = z.object({
|
||||
avatar_source: z.string(),
|
||||
delivery_email: z.string(),
|
||||
is_admin: z.boolean(),
|
||||
is_billing_admin: z.boolean(),
|
||||
is_guest: z.boolean(),
|
||||
is_moderator: z.boolean(),
|
||||
is_owner: z.boolean(),
|
||||
user_id: z.number(),
|
||||
});
|
||||
// Sync this with zerver.lib.events.do_events_register.
|
||||
|
||||
export const realm_schema = z.object({
|
||||
custom_profile_fields: z.array(
|
||||
z.object({
|
||||
display_in_profile_summary: z.optional(z.boolean()),
|
||||
field_data: z.string(),
|
||||
hint: z.string(),
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
order: z.number(),
|
||||
type: z.number(),
|
||||
}),
|
||||
),
|
||||
custom_profile_field_types: z.object({
|
||||
SHORT_TEXT: z.object({id: z.number(), name: z.string()}),
|
||||
LONG_TEXT: z.object({id: z.number(), name: z.string()}),
|
||||
DATE: z.object({id: z.number(), name: z.string()}),
|
||||
SELECT: z.object({id: z.number(), name: z.string()}),
|
||||
URL: z.object({id: z.number(), name: z.string()}),
|
||||
EXTERNAL_ACCOUNT: z.object({id: z.number(), name: z.string()}),
|
||||
USER: z.object({id: z.number(), name: z.string()}),
|
||||
PRONOUNS: z.object({id: z.number(), name: z.string()}),
|
||||
}),
|
||||
max_avatar_file_size_mib: z.number(),
|
||||
max_icon_file_size_mib: z.number(),
|
||||
max_logo_file_size_mib: z.number(),
|
||||
realm_add_custom_emoji_policy: z.number(),
|
||||
realm_available_video_chat_providers: z.object({
|
||||
disabled: z.object({name: z.string(), id: z.number()}),
|
||||
jitsi_meet: z.object({name: z.string(), id: z.number()}),
|
||||
zoom: z.optional(z.object({name: z.string(), id: z.number()})),
|
||||
big_blue_button: z.optional(z.object({name: z.string(), id: z.number()})),
|
||||
}),
|
||||
realm_avatar_changes_disabled: z.boolean(),
|
||||
realm_bot_domain: z.string(),
|
||||
realm_can_access_all_users_group: z.number(),
|
||||
realm_create_multiuse_invite_group: z.number(),
|
||||
realm_create_private_stream_policy: z.number(),
|
||||
realm_create_public_stream_policy: z.number(),
|
||||
realm_create_web_public_stream_policy: z.number(),
|
||||
realm_delete_own_message_policy: z.number(),
|
||||
realm_description: z.string(),
|
||||
realm_domains: z.array(
|
||||
z.object({
|
||||
domain: z.string(),
|
||||
allow_subdomains: z.boolean(),
|
||||
}),
|
||||
),
|
||||
realm_edit_topic_policy: z.number(),
|
||||
realm_email_changes_disabled: z.boolean(),
|
||||
realm_enable_guest_user_indicator: z.boolean(),
|
||||
realm_enable_spectator_access: z.boolean(),
|
||||
realm_icon_source: z.string(),
|
||||
realm_icon_url: z.string(),
|
||||
realm_invite_to_realm_policy: z.number(),
|
||||
realm_invite_to_stream_policy: z.number(),
|
||||
realm_is_zephyr_mirror_realm: z.boolean(),
|
||||
realm_jitsi_server_url: z.nullable(z.string()),
|
||||
realm_logo_source: z.string(),
|
||||
realm_logo_url: z.string(),
|
||||
realm_move_messages_between_streams_policy: z.number(),
|
||||
realm_name_changes_disabled: z.boolean(),
|
||||
realm_name: z.string(),
|
||||
realm_night_logo_source: z.string(),
|
||||
realm_night_logo_url: z.string(),
|
||||
realm_notifications_stream_id: z.number(),
|
||||
realm_org_type: z.number(),
|
||||
realm_plan_type: z.number(),
|
||||
realm_private_message_policy: z.number(),
|
||||
realm_push_notifications_enabled: z.boolean(),
|
||||
realm_upload_quota_mib: z.nullable(z.number()),
|
||||
realm_uri: z.string(),
|
||||
realm_user_group_edit_policy: z.number(),
|
||||
realm_video_chat_provider: z.number(),
|
||||
realm_waiting_period_threshold: z.number(),
|
||||
server_avatar_changes_disabled: z.boolean(),
|
||||
server_jitsi_server_url: z.nullable(z.string()),
|
||||
server_name_changes_disabled: z.boolean(),
|
||||
server_needs_upgrade: z.boolean(),
|
||||
server_presence_offline_threshold_seconds: z.number(),
|
||||
server_supported_permission_settings: z.object({
|
||||
realm: z.record(group_permission_setting_schema),
|
||||
stream: z.record(group_permission_setting_schema),
|
||||
group: z.record(group_permission_setting_schema),
|
||||
}),
|
||||
server_typing_started_expiry_period_milliseconds: z.number(),
|
||||
server_typing_started_wait_period_milliseconds: z.number(),
|
||||
server_typing_stopped_wait_period_milliseconds: z.number(),
|
||||
server_web_public_streams_enabled: z.boolean(),
|
||||
stop_words: z.array(z.string()),
|
||||
zulip_merge_base: z.string(),
|
||||
zulip_plan_is_not_limited: z.boolean(),
|
||||
zulip_version: z.string(),
|
||||
});
|
||||
|
||||
export const state_data_schema = current_user_schema
|
||||
.merge(realm_schema)
|
||||
// TODO/typescript: Remove .passthrough() when all consumers have been
|
||||
// converted to TypeScript and the schema is complete.
|
||||
.passthrough();
|
||||
|
||||
export let current_user: z.infer<typeof current_user_schema>;
|
||||
export let realm: z.infer<typeof realm_schema>;
|
||||
|
||||
export function set_current_user(initial_current_user: z.infer<typeof current_user_schema>): void {
|
||||
current_user = initial_current_user;
|
||||
}
|
||||
|
||||
export function set_realm(initial_realm: typeof realm): void {
|
||||
export function set_realm(initial_realm: z.infer<typeof realm_schema>): void {
|
||||
realm = initial_realm;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import $ from "jquery";
|
||||
import assert from "minimalistic-assert";
|
||||
|
||||
export const page_params: {
|
||||
data_url_suffix: string;
|
||||
guest_users: number | null;
|
||||
upload_space_used: number | null;
|
||||
} = $("#page-params").data("params");
|
||||
import {page_params as base_page_params} from "../base_page_params";
|
||||
|
||||
if (!page_params) {
|
||||
throw new Error("Missing page-params");
|
||||
}
|
||||
assert(base_page_params.page_type === "stats");
|
||||
|
||||
// We need to export with a narrowed TypeScript type
|
||||
// eslint-disable-next-line unicorn/prefer-export-from
|
||||
export const page_params = base_page_params;
|
||||
|
|
|
@ -52,15 +52,3 @@ export type UpdateMessageEvent = {
|
|||
// This will not be set until it gets fixed.
|
||||
topic?: string;
|
||||
};
|
||||
|
||||
export type GroupPermissionSetting = {
|
||||
require_system_group: boolean;
|
||||
allow_internet_group: boolean;
|
||||
allow_owners_group: boolean;
|
||||
allow_nobody_group: boolean;
|
||||
allow_everyone_group: boolean;
|
||||
default_group_name: string;
|
||||
id_field_name: string;
|
||||
default_for_system_groups: string | null;
|
||||
allowed_system_groups: string[];
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import $ from "jquery";
|
||||
import _ from "lodash";
|
||||
import assert from "minimalistic-assert";
|
||||
|
||||
import generated_emoji_codes from "../../static/generated/emoji/emoji_codes.json";
|
||||
import * as fenced_code from "../shared/src/fenced_code";
|
||||
|
@ -114,7 +115,7 @@ import * as sidebar_ui from "./sidebar_ui";
|
|||
import * as spoilers from "./spoilers";
|
||||
import * as starred_messages from "./starred_messages";
|
||||
import * as starred_messages_ui from "./starred_messages_ui";
|
||||
import {current_user, realm, set_current_user, set_realm} from "./state_data";
|
||||
import {current_user, realm, set_current_user, set_realm, state_data_schema} from "./state_data";
|
||||
import * as stream_data from "./stream_data";
|
||||
import * as stream_edit from "./stream_edit";
|
||||
import * as stream_edit_subscribers from "./stream_edit_subscribers";
|
||||
|
@ -874,7 +875,8 @@ $(async () => {
|
|||
url: "/json/register",
|
||||
data,
|
||||
success(response_data) {
|
||||
initialize_everything(response_data);
|
||||
const state_data = state_data_schema.parse(response_data);
|
||||
initialize_everything(state_data);
|
||||
},
|
||||
error() {
|
||||
$("#app-loading-middle-content").hide();
|
||||
|
@ -884,6 +886,7 @@ $(async () => {
|
|||
},
|
||||
});
|
||||
} else {
|
||||
assert(page_params.state_data !== undefined);
|
||||
initialize_everything(page_params.state_data);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ export {get_stream_id, get_sub, get_subscriber_count} from "./stream_data";
|
|||
export {get_by_user_id as get_person_by_user_id, get_user_id_from_name} from "./people";
|
||||
export {last_visible as last_visible_row, id as row_id} from "./rows";
|
||||
export {cancel as cancel_compose} from "./compose_actions";
|
||||
export {page_params, page_params_parse_time} from "./page_params";
|
||||
export {page_params, page_params_parse_time} from "./base_page_params";
|
||||
export {initiate as initiate_reload} from "./reload";
|
||||
export {page_load_time} from "./setup";
|
||||
export {current_user, realm} from "./state_data";
|
||||
|
|
|
@ -118,6 +118,8 @@ test.set_verbose(files.length === 1);
|
|||
require("../../src/blueslip");
|
||||
namespace.mock_esm("../../src/i18n", stub_i18n);
|
||||
require("../../src/i18n");
|
||||
namespace.mock_esm("../../src/base_page_params", zpage_params);
|
||||
require("../../src/base_page_params");
|
||||
namespace.mock_esm("../../src/billing/page_params", zpage_billing_params);
|
||||
require("../../src/billing/page_params");
|
||||
namespace.mock_esm("../../src/page_params", zpage_params);
|
||||
|
|
|
@ -32,6 +32,7 @@ from zproject.backends import (
|
|||
from zproject.config import get_config
|
||||
|
||||
DEFAULT_PAGE_PARAMS: Mapping[str, Any] = {
|
||||
"page_type": "default",
|
||||
"development_environment": settings.DEVELOPMENT,
|
||||
}
|
||||
|
||||
|
@ -165,6 +166,7 @@ def zulip_default_context(request: HttpRequest) -> Dict[str, Any]:
|
|||
f'<a href="mailto:{escape(support_email)}">{escape(support_email)}</a>'
|
||||
)
|
||||
|
||||
# Sync this with default_params_schema in base_page_params.ts.
|
||||
default_page_params: Dict[str, Any] = {
|
||||
**DEFAULT_PAGE_PARAMS,
|
||||
"server_sentry_dsn": settings.SENTRY_FRONTEND_DSN,
|
||||
|
|
|
@ -195,7 +195,10 @@ def build_page_params_for_home_page_load(
|
|||
|
||||
# Pass parameters to the client-side JavaScript code.
|
||||
# These end up in a JavaScript Object named 'page_params'.
|
||||
#
|
||||
# Sync this with home_params_schema in base_page_params.ts.
|
||||
page_params: Dict[str, object] = dict(
|
||||
page_type="home",
|
||||
## Server settings.
|
||||
test_suite=settings.TEST_SUITE,
|
||||
insecure_desktop_app=insecure_desktop_app,
|
||||
|
|
|
@ -52,6 +52,7 @@ class HomeTest(ZulipTestCase):
|
|||
"narrow_stream",
|
||||
"needs_tutorial",
|
||||
"no_event_queue",
|
||||
"page_type",
|
||||
"promote_sponsoring_zulip",
|
||||
"request_language",
|
||||
"server_sentry_dsn",
|
||||
|
@ -347,6 +348,7 @@ class HomeTest(ZulipTestCase):
|
|||
"login_page",
|
||||
"needs_tutorial",
|
||||
"no_event_queue",
|
||||
"page_type",
|
||||
"promote_sponsoring_zulip",
|
||||
"realm_rendered_description",
|
||||
"request_language",
|
||||
|
|
Loading…
Reference in New Issue