snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
This commit is contained in:
460
zerver/lib/types.py
Normal file
460
zerver/lib/types.py
Normal file
@@ -0,0 +1,460 @@
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from enum import IntEnum
|
||||
from typing import TYPE_CHECKING, Any, TypeAlias, TypeVar
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from zerver.models import Stream
|
||||
|
||||
from django_stubs_ext import StrPromise
|
||||
from typing_extensions import NotRequired, TypedDict
|
||||
|
||||
# See zerver/lib/validator.py for more details of Validators,
|
||||
# including many examples
|
||||
ResultT = TypeVar("ResultT")
|
||||
Validator: TypeAlias = Callable[[str, object], ResultT]
|
||||
ExtendedValidator: TypeAlias = Callable[[str, str, object], str]
|
||||
RealmUserValidator: TypeAlias = Callable[[int, object, bool], list[int]]
|
||||
|
||||
|
||||
ProfileDataElementValue: TypeAlias = str | list[int]
|
||||
|
||||
|
||||
class ProfileDataElementBase(TypedDict, total=False):
|
||||
id: int
|
||||
name: str
|
||||
type: int
|
||||
hint: str
|
||||
display_in_profile_summary: bool
|
||||
required: bool
|
||||
editable_by_user: bool
|
||||
use_for_user_matching: bool
|
||||
field_data: str
|
||||
order: int
|
||||
|
||||
|
||||
class ProfileDataElement(ProfileDataElementBase):
|
||||
value: ProfileDataElementValue | None
|
||||
rendered_value: str | None
|
||||
|
||||
|
||||
class ProfileDataElementUpdateDict(TypedDict):
|
||||
id: int
|
||||
value: ProfileDataElementValue
|
||||
|
||||
|
||||
class UserProfileChangeDict(TypedDict):
|
||||
field_name: str
|
||||
old_value: str
|
||||
new_value: str
|
||||
|
||||
|
||||
ProfileData: TypeAlias = list[ProfileDataElement]
|
||||
|
||||
FieldElement: TypeAlias = tuple[
|
||||
int, StrPromise, Validator[ProfileDataElementValue], Callable[[Any], Any], str
|
||||
]
|
||||
ExtendedFieldElement: TypeAlias = tuple[
|
||||
int, StrPromise, ExtendedValidator, Callable[[Any], Any], str
|
||||
]
|
||||
UserFieldElement: TypeAlias = tuple[int, StrPromise, RealmUserValidator, Callable[[Any], Any], str]
|
||||
|
||||
ProfileFieldData: TypeAlias = dict[str, dict[str, str] | str]
|
||||
|
||||
|
||||
class UserDisplayRecipient(TypedDict):
|
||||
email: str
|
||||
full_name: str
|
||||
id: int
|
||||
is_mirror_dummy: bool
|
||||
|
||||
|
||||
DisplayRecipientT: TypeAlias = str | list[UserDisplayRecipient]
|
||||
|
||||
|
||||
class LinkifierDict(TypedDict):
|
||||
pattern: str
|
||||
url_template: str
|
||||
id: int
|
||||
example_input: str | None
|
||||
reverse_template: str | None
|
||||
alternative_url_templates: list[str]
|
||||
|
||||
|
||||
class Unset:
|
||||
"""In most API endpoints, we use a default value of `None"` to encode
|
||||
parameters that the client did not pass, which is nicely Pythonic.
|
||||
|
||||
However, that design does not work for those few endpoints where
|
||||
we want to allow clients to pass an explicit `null` (which
|
||||
JSON-decodes to `None`).
|
||||
|
||||
We use this type as an explicit sentinel value for such endpoints.
|
||||
|
||||
TODO: Can this be merged with the _NotSpecified class, which is
|
||||
currently an internal implementation detail of the typed_endpoint?
|
||||
"""
|
||||
|
||||
|
||||
UNSET = Unset()
|
||||
|
||||
|
||||
class EditHistoryEvent(TypedDict, total=False):
|
||||
"""
|
||||
Database format for edit history events.
|
||||
"""
|
||||
|
||||
# user_id is null for precisely those edit history events
|
||||
# predating March 2017, when we started tracking the person who
|
||||
# made edits, which is still years after the introduction of topic
|
||||
# editing support in Zulip.
|
||||
user_id: int | None
|
||||
timestamp: int
|
||||
prev_stream: int
|
||||
stream: int
|
||||
prev_topic: str
|
||||
topic: str
|
||||
prev_content: str
|
||||
prev_rendered_content: str | None
|
||||
prev_rendered_content_version: int | None
|
||||
|
||||
|
||||
class FormattedEditHistoryEvent(TypedDict, total=False):
|
||||
"""
|
||||
Extended format used in the edit history endpoint.
|
||||
"""
|
||||
|
||||
# See EditHistoryEvent for details on when this can be null.
|
||||
user_id: int | None
|
||||
timestamp: int
|
||||
prev_stream: int
|
||||
stream: int
|
||||
prev_topic: str
|
||||
topic: str
|
||||
prev_content: str
|
||||
content: str
|
||||
prev_rendered_content: str | None
|
||||
rendered_content: str | None
|
||||
content_html_diff: str
|
||||
|
||||
|
||||
class UserTopicDict(TypedDict, total=False):
|
||||
"""Dictionary containing fields fetched from the UserTopic model that
|
||||
are needed to encode the UserTopic object for the API.
|
||||
"""
|
||||
|
||||
stream_id: int
|
||||
stream__name: str
|
||||
topic_name: str
|
||||
last_updated: int
|
||||
visibility_policy: int
|
||||
|
||||
|
||||
class UserGroupMembersDict(TypedDict):
|
||||
direct_members: list[int]
|
||||
direct_subgroups: list[int]
|
||||
|
||||
|
||||
@dataclass
|
||||
class UserGroupMembersData:
|
||||
direct_members: list[int]
|
||||
direct_subgroups: list[int]
|
||||
|
||||
|
||||
# This next batch of types is for Stream/Subscription objects.
|
||||
class RawStreamDict(TypedDict):
|
||||
"""Dictionary containing fields fetched from the Stream model that
|
||||
are needed to encode the stream for the API.
|
||||
"""
|
||||
|
||||
can_add_subscribers_group_id: int
|
||||
can_administer_channel_group_id: int
|
||||
can_create_topic_group_id: int
|
||||
can_delete_any_message_group_id: int
|
||||
can_delete_own_message_group_id: int
|
||||
can_move_messages_out_of_channel_group_id: int
|
||||
can_move_messages_within_channel_group_id: int
|
||||
can_send_message_group_id: int
|
||||
can_remove_subscribers_group_id: int
|
||||
can_resolve_topics_group_id: int
|
||||
can_subscribe_group_id: int
|
||||
creator_id: int | None
|
||||
date_created: datetime
|
||||
deactivated: bool
|
||||
default_push_notifications: bool
|
||||
description: str
|
||||
first_message_id: int | None
|
||||
folder_id: int | None
|
||||
history_public_to_subscribers: bool
|
||||
id: int
|
||||
invite_only: bool
|
||||
is_recently_active: bool
|
||||
is_web_public: bool
|
||||
message_retention_days: int | None
|
||||
name: str
|
||||
rendered_description: str
|
||||
stream_post_policy: int
|
||||
subscriber_count: int
|
||||
topics_policy: str
|
||||
|
||||
|
||||
class RawSubscriptionDict(TypedDict):
|
||||
"""Dictionary containing fields fetched from the Subscription model
|
||||
that are needed to encode the subscription for the API.
|
||||
"""
|
||||
|
||||
active: bool
|
||||
audible_notifications: bool | None
|
||||
color: str
|
||||
desktop_notifications: bool | None
|
||||
email_notifications: bool | None
|
||||
is_muted: bool
|
||||
pin_to_top: bool
|
||||
push_notifications: bool | None
|
||||
recipient_id: int
|
||||
wildcard_mentions_notify: bool | None
|
||||
|
||||
|
||||
class SubscriptionStreamDict(TypedDict):
|
||||
"""Conceptually, the union of RawSubscriptionDict and RawStreamDict
|
||||
(i.e. containing all the user's personal settings for the stream
|
||||
as well as the stream's global settings), with a few additional
|
||||
computed fields.
|
||||
"""
|
||||
|
||||
audible_notifications: bool | None
|
||||
can_add_subscribers_group: int | UserGroupMembersDict
|
||||
can_administer_channel_group: int | UserGroupMembersDict
|
||||
can_create_topic_group: int | UserGroupMembersDict
|
||||
can_delete_any_message_group: int | UserGroupMembersDict
|
||||
can_delete_own_message_group: int | UserGroupMembersDict
|
||||
can_move_messages_out_of_channel_group: int | UserGroupMembersDict
|
||||
can_move_messages_within_channel_group: int | UserGroupMembersDict
|
||||
can_send_message_group: int | UserGroupMembersDict
|
||||
can_remove_subscribers_group: int | UserGroupMembersDict
|
||||
can_resolve_topics_group: int | UserGroupMembersDict
|
||||
can_subscribe_group: int | UserGroupMembersDict
|
||||
color: str
|
||||
creator_id: int | None
|
||||
date_created: int
|
||||
default_push_notifications: bool
|
||||
description: str
|
||||
desktop_notifications: bool | None
|
||||
email_notifications: bool | None
|
||||
first_message_id: int | None
|
||||
folder_id: int | None
|
||||
history_public_to_subscribers: bool
|
||||
in_home_view: bool
|
||||
invite_only: bool
|
||||
is_announcement_only: bool
|
||||
is_archived: bool
|
||||
is_muted: bool
|
||||
is_recently_active: bool
|
||||
is_web_public: bool
|
||||
message_retention_days: int | None
|
||||
name: str
|
||||
partial_subscribers: NotRequired[list[int]]
|
||||
pin_to_top: bool
|
||||
push_notifications: bool | None
|
||||
rendered_description: str
|
||||
stream_id: int
|
||||
stream_post_policy: int
|
||||
stream_weekly_traffic: int | None
|
||||
subscriber_count: int
|
||||
subscribers: NotRequired[list[int]]
|
||||
topics_policy: str
|
||||
wildcard_mentions_notify: bool | None
|
||||
|
||||
|
||||
class NeverSubscribedStreamDict(TypedDict):
|
||||
can_add_subscribers_group: int | UserGroupMembersDict
|
||||
can_administer_channel_group: int | UserGroupMembersDict
|
||||
can_create_topic_group: int | UserGroupMembersDict
|
||||
can_delete_any_message_group: int | UserGroupMembersDict
|
||||
can_delete_own_message_group: int | UserGroupMembersDict
|
||||
can_move_messages_out_of_channel_group: int | UserGroupMembersDict
|
||||
can_move_messages_within_channel_group: int | UserGroupMembersDict
|
||||
can_send_message_group: int | UserGroupMembersDict
|
||||
can_remove_subscribers_group: int | UserGroupMembersDict
|
||||
can_resolve_topics_group: int | UserGroupMembersDict
|
||||
can_subscribe_group: int | UserGroupMembersDict
|
||||
creator_id: int | None
|
||||
date_created: int
|
||||
default_push_notifications: bool
|
||||
description: str
|
||||
first_message_id: int | None
|
||||
folder_id: int | None
|
||||
history_public_to_subscribers: bool
|
||||
invite_only: bool
|
||||
is_announcement_only: bool
|
||||
is_archived: bool
|
||||
is_recently_active: bool
|
||||
is_web_public: bool
|
||||
message_retention_days: int | None
|
||||
name: str
|
||||
partial_subscribers: NotRequired[list[int]]
|
||||
rendered_description: str
|
||||
stream_id: int
|
||||
stream_post_policy: int
|
||||
stream_weekly_traffic: int | None
|
||||
subscriber_count: int
|
||||
subscribers: NotRequired[list[int]]
|
||||
topics_policy: str
|
||||
|
||||
|
||||
class DefaultStreamDict(TypedDict):
|
||||
"""Stream information provided to Zulip clients as a dictionary via API.
|
||||
It should contain all the fields specified in `zerver.models.Stream.API_FIELDS`
|
||||
with few exceptions and possible additional fields.
|
||||
"""
|
||||
|
||||
can_add_subscribers_group: int | UserGroupMembersDict
|
||||
can_administer_channel_group: int | UserGroupMembersDict
|
||||
can_create_topic_group: int | UserGroupMembersDict
|
||||
can_delete_any_message_group: int | UserGroupMembersDict
|
||||
can_delete_own_message_group: int | UserGroupMembersDict
|
||||
can_move_messages_out_of_channel_group: int | UserGroupMembersDict
|
||||
can_move_messages_within_channel_group: int | UserGroupMembersDict
|
||||
can_send_message_group: int | UserGroupMembersDict
|
||||
can_remove_subscribers_group: int | UserGroupMembersDict
|
||||
can_resolve_topics_group: int | UserGroupMembersDict
|
||||
can_subscribe_group: int | UserGroupMembersDict
|
||||
creator_id: int | None
|
||||
date_created: int
|
||||
default_push_notifications: bool
|
||||
description: str
|
||||
first_message_id: int | None
|
||||
folder_id: int | None
|
||||
history_public_to_subscribers: bool
|
||||
invite_only: bool
|
||||
is_archived: bool
|
||||
is_recently_active: bool
|
||||
is_web_public: bool
|
||||
message_retention_days: int | None
|
||||
name: str
|
||||
rendered_description: str
|
||||
stream_id: int # `stream_id` represents `id` of the `Stream` object in `API_FIELDS`
|
||||
stream_post_policy: int
|
||||
subscriber_count: int
|
||||
topics_policy: str
|
||||
# Computed fields not specified in `Stream.API_FIELDS`
|
||||
is_announcement_only: bool
|
||||
is_default: NotRequired[bool]
|
||||
|
||||
|
||||
class APIStreamDict(DefaultStreamDict):
|
||||
stream_weekly_traffic: int | None
|
||||
|
||||
|
||||
class APISubscriptionDict(APIStreamDict):
|
||||
"""Similar to StreamClientDict, it should contain all the fields specified in
|
||||
`zerver.models.Subscription.API_FIELDS` and several additional fields.
|
||||
"""
|
||||
|
||||
audible_notifications: bool | None
|
||||
color: str
|
||||
desktop_notifications: bool | None
|
||||
email_notifications: bool | None
|
||||
is_muted: bool
|
||||
pin_to_top: bool
|
||||
push_notifications: bool | None
|
||||
wildcard_mentions_notify: bool | None
|
||||
# Computed fields not specified in `Subscription.API_FIELDS`
|
||||
in_home_view: bool
|
||||
subscribers: list[int]
|
||||
|
||||
|
||||
@dataclass
|
||||
class SubscriptionInfo:
|
||||
subscriptions: list[SubscriptionStreamDict]
|
||||
unsubscribed: list[SubscriptionStreamDict]
|
||||
never_subscribed: list[NeverSubscribedStreamDict]
|
||||
|
||||
|
||||
class RealmPlaygroundDict(TypedDict):
|
||||
id: int
|
||||
name: str
|
||||
pygments_language: str
|
||||
url_template: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class GroupPermissionSetting:
|
||||
allow_nobody_group: bool
|
||||
allow_everyone_group: bool
|
||||
default_group_name: str
|
||||
require_system_group: bool = False
|
||||
allow_internet_group: bool = False
|
||||
default_for_system_groups: str | None = None
|
||||
allowed_system_groups: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ServerSupportedPermissionSettings:
|
||||
realm: dict[str, GroupPermissionSetting]
|
||||
stream: dict[str, GroupPermissionSetting]
|
||||
group: dict[str, GroupPermissionSetting]
|
||||
|
||||
|
||||
class RawUserDict(TypedDict):
|
||||
id: int
|
||||
full_name: str
|
||||
email: str
|
||||
avatar_source: str
|
||||
avatar_version: int
|
||||
is_active: bool
|
||||
role: int
|
||||
is_bot: bool
|
||||
timezone: str
|
||||
date_joined: datetime
|
||||
bot_owner_id: int | None
|
||||
delivery_email: str
|
||||
bot_type: int | None
|
||||
long_term_idle: bool
|
||||
email_address_visibility: int
|
||||
is_imported_stub: bool
|
||||
is_deleted: bool
|
||||
|
||||
|
||||
class RemoteRealmDictValue(TypedDict):
|
||||
can_push: bool
|
||||
expected_end_timestamp: int | None
|
||||
|
||||
|
||||
class AnalyticsDataUploadLevel(IntEnum):
|
||||
NONE = 0
|
||||
BASIC = 1
|
||||
BILLING = 2
|
||||
ALL = 3
|
||||
|
||||
|
||||
@dataclass
|
||||
class StreamMessageEditRequest:
|
||||
is_content_edited: bool
|
||||
is_topic_edited: bool
|
||||
is_stream_edited: bool
|
||||
is_message_moved: bool
|
||||
is_nontrivial_move: bool
|
||||
topic_resolved: bool
|
||||
topic_unresolved: bool
|
||||
content: str
|
||||
target_topic_name: str
|
||||
target_stream: "Stream"
|
||||
orig_content: str
|
||||
orig_topic_name: str
|
||||
orig_stream: "Stream"
|
||||
propagate_mode: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class DirectMessageEditRequest:
|
||||
content: str
|
||||
orig_content: str
|
||||
is_content_edited: bool
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Invitee:
|
||||
email: str
|
||||
full_name: str = ""
|
||||
Reference in New Issue
Block a user