tlgr-cli 2.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tlgr/__init__.py +3 -0
- tlgr/__main__.py +6 -0
- tlgr/actions/__init__.py +45 -0
- tlgr/actions/forward.py +74 -0
- tlgr/actions/reply.py +32 -0
- tlgr/cli/__init__.py +259 -0
- tlgr/cli/confirm.py +55 -0
- tlgr/cli/errors.py +84 -0
- tlgr/cli/gen.py +690 -0
- tlgr/cli/globals.py +273 -0
- tlgr/cli/introspect.py +170 -0
- tlgr/cli/params.py +189 -0
- tlgr/cli/render.py +418 -0
- tlgr/core/__init__.py +0 -0
- tlgr/core/accounts.py +384 -0
- tlgr/core/config.py +358 -0
- tlgr/core/custom_tl.py +170 -0
- tlgr/core/errors.py +687 -0
- tlgr/core/eventtypes.py +1170 -0
- tlgr/core/identity.py +127 -0
- tlgr/core/launchd.py +122 -0
- tlgr/core/logging.py +194 -0
- tlgr/core/media.py +134 -0
- tlgr/core/output.py +251 -0
- tlgr/core/pagination.py +227 -0
- tlgr/core/paths.py +360 -0
- tlgr/core/peers.py +427 -0
- tlgr/core/process.py +138 -0
- tlgr/core/signing.py +38 -0
- tlgr/core/systemd.py +96 -0
- tlgr/core/telethon_compat.py +295 -0
- tlgr/core/text.py +211 -0
- tlgr/core/timefmt.py +199 -0
- tlgr/core/tl.py +98 -0
- tlgr/daemon/__init__.py +0 -0
- tlgr/daemon/app.py +869 -0
- tlgr/daemon/dispatch.py +446 -0
- tlgr/daemon/events.py +723 -0
- tlgr/daemon/files.py +431 -0
- tlgr/daemon/idle.py +119 -0
- tlgr/daemon/jobs.py +68 -0
- tlgr/daemon/main.py +161 -0
- tlgr/daemon/peercred.py +75 -0
- tlgr/daemon/policy.py +113 -0
- tlgr/daemon/preauth.py +366 -0
- tlgr/daemon/ratelimit.py +391 -0
- tlgr/daemon/server.py +24 -0
- tlgr/daemon/session.py +648 -0
- tlgr/daemon/sessions.py +274 -0
- tlgr/daemon/singleton.py +114 -0
- tlgr/daemon/stream.py +193 -0
- tlgr/daemon/transfers.py +219 -0
- tlgr/daemon/webhook.py +390 -0
- tlgr/data/catalog_index.json +1 -0
- tlgr/data/parity_waivers.toml +90 -0
- tlgr/filters/__init__.py +42 -0
- tlgr/filters/compose.py +121 -0
- tlgr/filters/content.py +85 -0
- tlgr/filters/context.py +114 -0
- tlgr/filters/message.py +161 -0
- tlgr/filters/temporal.py +87 -0
- tlgr/filters/user.py +36 -0
- tlgr/gateway/__init__.py +1 -0
- tlgr/gateway/config.py +161 -0
- tlgr/gateway/engine.py +215 -0
- tlgr/gateway/event.py +22 -0
- tlgr/jobs/__init__.py +0 -0
- tlgr/jobs/base.py +81 -0
- tlgr/jobs/client.py +37 -0
- tlgr/models/__init__.py +1220 -0
- tlgr/models/admin.py +744 -0
- tlgr/models/auth.py +510 -0
- tlgr/models/base.py +81 -0
- tlgr/models/bot.py +576 -0
- tlgr/models/business.py +265 -0
- tlgr/models/call.py +586 -0
- tlgr/models/config.py +101 -0
- tlgr/models/contact.py +481 -0
- tlgr/models/daemon.py +336 -0
- tlgr/models/dialog.py +626 -0
- tlgr/models/envelope.py +68 -0
- tlgr/models/error.py +30 -0
- tlgr/models/event.py +79 -0
- tlgr/models/export.py +66 -0
- tlgr/models/gift.py +275 -0
- tlgr/models/inline.py +84 -0
- tlgr/models/location.py +115 -0
- tlgr/models/media.py +507 -0
- tlgr/models/message.py +584 -0
- tlgr/models/net.py +232 -0
- tlgr/models/notify.py +105 -0
- tlgr/models/page.py +32 -0
- tlgr/models/payment.py +172 -0
- tlgr/models/peer.py +400 -0
- tlgr/models/poll.py +119 -0
- tlgr/models/premium.py +161 -0
- tlgr/models/privacy.py +93 -0
- tlgr/models/profile.py +217 -0
- tlgr/models/reaction.py +160 -0
- tlgr/models/resolve.py +175 -0
- tlgr/models/settings.py +103 -0
- tlgr/models/stars.py +101 -0
- tlgr/models/sticker.py +243 -0
- tlgr/models/story.py +467 -0
- tlgr/models/sync.py +105 -0
- tlgr/models/todo.py +36 -0
- tlgr/models/webapp.py +89 -0
- tlgr/ops/__init__.py +63 -0
- tlgr/ops/_admin.py +313 -0
- tlgr/ops/_auth.py +599 -0
- tlgr/ops/_bots.py +586 -0
- tlgr/ops/_calls.py +535 -0
- tlgr/ops/_common.py +160 -0
- tlgr/ops/_layer.py +46 -0
- tlgr/ops/_media.py +592 -0
- tlgr/ops/_params.py +212 -0
- tlgr/ops/_rights.py +402 -0
- tlgr/ops/_send.py +593 -0
- tlgr/ops/_serialize.py +667 -0
- tlgr/ops/_settings.py +306 -0
- tlgr/ops/_spec.py +167 -0
- tlgr/ops/_story.py +743 -0
- tlgr/ops/account.py +2604 -0
- tlgr/ops/agent.py +937 -0
- tlgr/ops/auth.py +1282 -0
- tlgr/ops/bot.py +4880 -0
- tlgr/ops/business.py +1520 -0
- tlgr/ops/call.py +1610 -0
- tlgr/ops/chat.py +4025 -0
- tlgr/ops/chat_admin.py +929 -0
- tlgr/ops/chat_extra.py +1061 -0
- tlgr/ops/chat_invite.py +716 -0
- tlgr/ops/chat_manage.py +1691 -0
- tlgr/ops/chat_member.py +1357 -0
- tlgr/ops/chat_stats.py +902 -0
- tlgr/ops/chat_topic.py +905 -0
- tlgr/ops/conference.py +791 -0
- tlgr/ops/config.py +1698 -0
- tlgr/ops/contact.py +2330 -0
- tlgr/ops/daemon.py +1397 -0
- tlgr/ops/draft.py +299 -0
- tlgr/ops/emoji.py +343 -0
- tlgr/ops/events.py +1327 -0
- tlgr/ops/export.py +596 -0
- tlgr/ops/folder.py +1322 -0
- tlgr/ops/gif.py +522 -0
- tlgr/ops/gift.py +1546 -0
- tlgr/ops/giveaway.py +541 -0
- tlgr/ops/inline.py +773 -0
- tlgr/ops/job.py +799 -0
- tlgr/ops/location.py +917 -0
- tlgr/ops/media.py +4495 -0
- tlgr/ops/message.py +3769 -0
- tlgr/ops/net.py +536 -0
- tlgr/ops/notify.py +840 -0
- tlgr/ops/passport.py +464 -0
- tlgr/ops/payment.py +907 -0
- tlgr/ops/poll.py +1078 -0
- tlgr/ops/premium.py +488 -0
- tlgr/ops/privacy.py +794 -0
- tlgr/ops/profile.py +1481 -0
- tlgr/ops/proxy.py +750 -0
- tlgr/ops/reaction.py +1475 -0
- tlgr/ops/resolve.py +1140 -0
- tlgr/ops/search.py +521 -0
- tlgr/ops/settings.py +1066 -0
- tlgr/ops/stars.py +594 -0
- tlgr/ops/sticker.py +1602 -0
- tlgr/ops/story.py +3216 -0
- tlgr/ops/sync.py +788 -0
- tlgr/ops/todo.py +514 -0
- tlgr/ops/user.py +1406 -0
- tlgr/ops/vc.py +2351 -0
- tlgr/ops/webapp.py +717 -0
- tlgr/ops/webhook.py +418 -0
- tlgr/parity.py +386 -0
- tlgr/processors/__init__.py +125 -0
- tlgr/processors/regex.py +26 -0
- tlgr/processors/text.py +56 -0
- tlgr/registry.py +519 -0
- tlgr/schema.py +173 -0
- tlgr/transport/__init__.py +30 -0
- tlgr/transport/autostart.py +293 -0
- tlgr/transport/client.py +805 -0
- tlgr/transport/ndjson.py +44 -0
- tlgr/version.py +31 -0
- tlgr_cli-2.0.1.dist-info/METADATA +957 -0
- tlgr_cli-2.0.1.dist-info/RECORD +192 -0
- tlgr_cli-2.0.1.dist-info/WHEEL +5 -0
- tlgr_cli-2.0.1.dist-info/entry_points.txt +2 -0
- tlgr_cli-2.0.1.dist-info/licenses/LICENSE +21 -0
- tlgr_cli-2.0.1.dist-info/top_level.txt +1 -0
tlgr/models/dialog.py
ADDED
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
"""Dialogs, drafts and folders — the chat-list side of the model.
|
|
2
|
+
|
|
3
|
+
Everything the chat list shows is here: the dialog row itself, the chat
|
|
4
|
+
folders that re-slice it, the notification exception behind the little
|
|
5
|
+
bell, the action bar Telegram puts above a stranger's chat, and the
|
|
6
|
+
per-chat decorations (theme, wallpaper, auto-delete timer).
|
|
7
|
+
|
|
8
|
+
Two shapes are deliberate.
|
|
9
|
+
|
|
10
|
+
* **A dialog carries its peer, not a flattened copy of it.** v1 spelled the
|
|
11
|
+
chat three different ways depending on which command answered; here every
|
|
12
|
+
row embeds the same `Peer`, so `chat.id` means one thing everywhere.
|
|
13
|
+
* **A notification setting is a tri-state.** `peerNotifySettings` fields are
|
|
14
|
+
*unset* when the chat inherits the scope default, and `None` here means
|
|
15
|
+
exactly that — not "off". Collapsing the two is how a client ends up
|
|
16
|
+
reporting a muted chat as unmuted.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
from tlgr.models.base import Model
|
|
24
|
+
from tlgr.models.message import Message, MessageEntity
|
|
25
|
+
from tlgr.models.peer import Peer
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"ActionBar",
|
|
29
|
+
"ArchiveResult",
|
|
30
|
+
"ArchiveSettings",
|
|
31
|
+
"Badge",
|
|
32
|
+
"Catchup",
|
|
33
|
+
"CatchupChat",
|
|
34
|
+
"ChatInfo",
|
|
35
|
+
"ChatSwitches",
|
|
36
|
+
"ChatTheme",
|
|
37
|
+
"ChatWallpaper",
|
|
38
|
+
"ChatlistInvite",
|
|
39
|
+
"ChatlistJoin",
|
|
40
|
+
"ChatlistUpdates",
|
|
41
|
+
"ClearResult",
|
|
42
|
+
"DeleteChatResult",
|
|
43
|
+
"Dialog",
|
|
44
|
+
"Draft",
|
|
45
|
+
"Folder",
|
|
46
|
+
"FolderBadge",
|
|
47
|
+
"FolderDeleted",
|
|
48
|
+
"FolderList",
|
|
49
|
+
"FolderOrder",
|
|
50
|
+
"ImportState",
|
|
51
|
+
"LeaveResult",
|
|
52
|
+
"MuteResult",
|
|
53
|
+
"NotifySettings",
|
|
54
|
+
"NotifyView",
|
|
55
|
+
"OpenResult",
|
|
56
|
+
"PeerResult",
|
|
57
|
+
"PinnedDialogs",
|
|
58
|
+
"Poster",
|
|
59
|
+
"PosterReport",
|
|
60
|
+
"Promo",
|
|
61
|
+
"ReadChats",
|
|
62
|
+
"SavedDialog",
|
|
63
|
+
"SecretChat",
|
|
64
|
+
"ShareDeleted",
|
|
65
|
+
"SuggestedFolder",
|
|
66
|
+
"ThemeResult",
|
|
67
|
+
"TranslateResult",
|
|
68
|
+
"TtlResult",
|
|
69
|
+
"TypingResult",
|
|
70
|
+
"UnreadResult",
|
|
71
|
+
"WallpaperResult",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class NotifySettings(Model):
|
|
76
|
+
"""One chat's notification exception.
|
|
77
|
+
|
|
78
|
+
`muted` is the answer to the question a human asks; the fields under it
|
|
79
|
+
are what Telegram actually stores, and a `None` among them means "not
|
|
80
|
+
set here, inherit the scope default".
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
muted: bool = False
|
|
84
|
+
mute_until: str | None = None
|
|
85
|
+
mute_until_unix: int | None = None
|
|
86
|
+
silent: bool | None = None
|
|
87
|
+
show_previews: bool | None = None
|
|
88
|
+
sound: str | None = None
|
|
89
|
+
stories_muted: bool | None = None
|
|
90
|
+
stories_hide_sender: bool | None = None
|
|
91
|
+
stories_sound: str | None = None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class NotifyView(Model):
|
|
95
|
+
"""`chat notify get`: the exception, and what it resolves to.
|
|
96
|
+
|
|
97
|
+
Both halves are reported because they answer different questions. The
|
|
98
|
+
exception is what you must send back to change one field without
|
|
99
|
+
clobbering the others; the effective value is what the user is asking
|
|
100
|
+
about when they say "is this chat muted?".
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
chat_id: int
|
|
104
|
+
settings: NotifySettings
|
|
105
|
+
effective: NotifySettings | None = None
|
|
106
|
+
scope: str = ""
|
|
107
|
+
scope_default: NotifySettings | None = None
|
|
108
|
+
#: Field names taken from the scope default rather than set on the chat.
|
|
109
|
+
inherited: list[str] = []
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class Draft(Model):
|
|
113
|
+
chat_id: int
|
|
114
|
+
chat: Peer | None = None
|
|
115
|
+
text: str = ""
|
|
116
|
+
entities: list[MessageEntity] = []
|
|
117
|
+
reply_to_msg_id: int | None = None
|
|
118
|
+
top_msg_id: int | None = None
|
|
119
|
+
no_webpage: bool = False
|
|
120
|
+
effect_id: int | None = None
|
|
121
|
+
date: str | None = None
|
|
122
|
+
empty: bool = False
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class Dialog(Model):
|
|
126
|
+
"""One row of the chat list."""
|
|
127
|
+
|
|
128
|
+
chat: Peer
|
|
129
|
+
unread_count: int = 0
|
|
130
|
+
unread_mentions_count: int = 0
|
|
131
|
+
unread_reactions_count: int = 0
|
|
132
|
+
unread_poll_votes_count: int = 0
|
|
133
|
+
unread_mark: bool = False
|
|
134
|
+
read_inbox_max_id: int = 0
|
|
135
|
+
# The highest message of OURS the other side has read — the only honest
|
|
136
|
+
# answer to "have they seen it?", and not derivable from read_inbox_max_id.
|
|
137
|
+
read_outbox_max_id: int = 0
|
|
138
|
+
top_message_id: int | None = None
|
|
139
|
+
pinned: bool = False
|
|
140
|
+
pinned_order: int | None = None
|
|
141
|
+
folder_id: int = 0
|
|
142
|
+
archived: bool = False
|
|
143
|
+
#: Ids of the chat *folders* (dialog filters) this chat falls into. Not
|
|
144
|
+
#: the same thing as `folder_id`, which is Telegram's peer-folder (0 or 1).
|
|
145
|
+
folders: list[int] = []
|
|
146
|
+
notify: NotifySettings | None = None
|
|
147
|
+
draft: Draft | None = None
|
|
148
|
+
ttl_period: int | None = None
|
|
149
|
+
view_forum_as_messages: bool | None = None
|
|
150
|
+
requests_pending: int | None = None
|
|
151
|
+
restricted: bool = False
|
|
152
|
+
restriction_reason: list[str] = []
|
|
153
|
+
participants_count: int | None = None
|
|
154
|
+
#: `channels.getInactiveChannels` only: when the chat was last active.
|
|
155
|
+
inactive_since: str | None = None
|
|
156
|
+
last_message: Message | None = None
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class SavedDialog(Model):
|
|
160
|
+
"""A Saved-Messages sublist, or a channel direct-message topic.
|
|
161
|
+
|
|
162
|
+
The same TL family answers both, which is why one model does: a monoforum
|
|
163
|
+
topic *is* a saved dialog whose parent peer is the channel.
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
origin_peer: Peer | None = None
|
|
167
|
+
origin_id: int = 0
|
|
168
|
+
parent_peer: int | None = None
|
|
169
|
+
top_message_id: int | None = None
|
|
170
|
+
pinned: bool = False
|
|
171
|
+
unread_count: int = 0
|
|
172
|
+
unread_mark: bool = False
|
|
173
|
+
date: str | None = None
|
|
174
|
+
date_unix: int | None = None
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class Folder(Model):
|
|
178
|
+
"""A chat folder (`dialogFilter`), or a shared one (`dialogFilterChatlist`).
|
|
179
|
+
|
|
180
|
+
A shared folder carries no type flags at all — Telegram will not accept
|
|
181
|
+
them on one — so `is_chatlist` is the flag that says which half of this
|
|
182
|
+
model is meaningful.
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
id: int
|
|
186
|
+
title: str
|
|
187
|
+
emoticon: str | None = None
|
|
188
|
+
color: int | None = None
|
|
189
|
+
title_noanimate: bool = False
|
|
190
|
+
include_peers: list[int] = []
|
|
191
|
+
exclude_peers: list[int] = []
|
|
192
|
+
pinned_peers: list[int] = []
|
|
193
|
+
contacts: bool = False
|
|
194
|
+
non_contacts: bool = False
|
|
195
|
+
groups: bool = False
|
|
196
|
+
broadcasts: bool = False
|
|
197
|
+
bots: bool = False
|
|
198
|
+
exclude_muted: bool = False
|
|
199
|
+
exclude_read: bool = False
|
|
200
|
+
exclude_archived: bool = False
|
|
201
|
+
is_chatlist: bool = False
|
|
202
|
+
has_my_invites: bool = False
|
|
203
|
+
is_default: bool = False
|
|
204
|
+
#: Populated by `folder list --with-counts`.
|
|
205
|
+
chats: int | None = None
|
|
206
|
+
unread_chats: int | None = None
|
|
207
|
+
unread_messages: int | None = None
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class FolderList(Model):
|
|
211
|
+
tags_enabled: bool = False
|
|
212
|
+
folders: list[Folder] = []
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class FolderOrder(Model):
|
|
216
|
+
order: list[int] = []
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class FolderDeleted(Model):
|
|
220
|
+
id: int
|
|
221
|
+
deleted: bool = False
|
|
222
|
+
left_chats: list[int] = []
|
|
223
|
+
suggested: list[int] = []
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class SuggestedFolder(Model):
|
|
227
|
+
title: str
|
|
228
|
+
description: str = ""
|
|
229
|
+
emoticon: str | None = None
|
|
230
|
+
contacts: bool = False
|
|
231
|
+
non_contacts: bool = False
|
|
232
|
+
groups: bool = False
|
|
233
|
+
broadcasts: bool = False
|
|
234
|
+
bots: bool = False
|
|
235
|
+
exclude_muted: bool = False
|
|
236
|
+
exclude_read: bool = False
|
|
237
|
+
exclude_archived: bool = False
|
|
238
|
+
#: Set when `--add` created the folder from this suggestion.
|
|
239
|
+
added_id: int | None = None
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class ChatlistInvite(Model):
|
|
243
|
+
slug: str
|
|
244
|
+
url: str = ""
|
|
245
|
+
title: str = ""
|
|
246
|
+
peers: list[int] = []
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class ChatlistJoin(Model):
|
|
250
|
+
slug: str
|
|
251
|
+
title: str = ""
|
|
252
|
+
emoticon: str | None = None
|
|
253
|
+
already_member: bool = False
|
|
254
|
+
filter_id: int | None = None
|
|
255
|
+
peers: list[int] = []
|
|
256
|
+
missing_peers: list[int] = []
|
|
257
|
+
already_peers: list[int] = []
|
|
258
|
+
joined: list[int] = []
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class ChatlistUpdates(Model):
|
|
262
|
+
id: int
|
|
263
|
+
missing_peers: list[int] = []
|
|
264
|
+
joined: list[int] = []
|
|
265
|
+
dismissed: bool = False
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
class ShareDeleted(Model):
|
|
269
|
+
slug: str
|
|
270
|
+
deleted: bool = False
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
# ---------------------------------------------------------------------------
|
|
274
|
+
# Per-chat state
|
|
275
|
+
# ---------------------------------------------------------------------------
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class ActionBar(Model):
|
|
279
|
+
"""`peerSettings` — the bar Telegram shows above a chat with a stranger.
|
|
280
|
+
|
|
281
|
+
The four date-ish fields at the bottom are the strongest cold-outreach
|
|
282
|
+
triage signals a client is given, and no other call reports them.
|
|
283
|
+
"""
|
|
284
|
+
|
|
285
|
+
chat_id: int
|
|
286
|
+
report_spam: bool = False
|
|
287
|
+
add_contact: bool = False
|
|
288
|
+
block_contact: bool = False
|
|
289
|
+
share_contact: bool = False
|
|
290
|
+
need_contacts_exception: bool = False
|
|
291
|
+
report_geo: bool = False
|
|
292
|
+
autoarchived: bool = False
|
|
293
|
+
invite_members: bool = False
|
|
294
|
+
request_chat_title: str | None = None
|
|
295
|
+
request_chat_date: str | None = None
|
|
296
|
+
request_chat_broadcast: bool = False
|
|
297
|
+
business_bot_id: int | None = None
|
|
298
|
+
business_bot_paused: bool = False
|
|
299
|
+
business_bot_can_reply: bool = False
|
|
300
|
+
charge_paid_message_stars: int | None = None
|
|
301
|
+
registration_month: str | None = None
|
|
302
|
+
phone_country: str | None = None
|
|
303
|
+
name_change_date: str | None = None
|
|
304
|
+
photo_change_date: str | None = None
|
|
305
|
+
geo_distance: int | None = None
|
|
306
|
+
hidden: bool = False
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class ChatTheme(Model):
|
|
310
|
+
emoticon: str | None = None
|
|
311
|
+
gift_id: int | None = None
|
|
312
|
+
gift_slug: str | None = None
|
|
313
|
+
title: str = ""
|
|
314
|
+
premium_required: bool = False
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class ChatWallpaper(Model):
|
|
318
|
+
id: int | None = None
|
|
319
|
+
slug: str | None = None
|
|
320
|
+
dark: bool = False
|
|
321
|
+
pattern: bool = False
|
|
322
|
+
blur: bool = False
|
|
323
|
+
intensity: int | None = None
|
|
324
|
+
background_color: int | None = None
|
|
325
|
+
second_background_color: int | None = None
|
|
326
|
+
emoticon: str | None = None
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class ChatInfo(Model):
|
|
330
|
+
"""`chat get`: the dialog row, the peer, and whatever `--full` added.
|
|
331
|
+
|
|
332
|
+
One flat object rather than three nested ones because this is the command
|
|
333
|
+
a script runs to answer a single question, and `--select` is how it picks
|
|
334
|
+
the field it wants.
|
|
335
|
+
"""
|
|
336
|
+
|
|
337
|
+
id: int
|
|
338
|
+
raw_id: int = 0
|
|
339
|
+
type: str = "unknown"
|
|
340
|
+
title: str = ""
|
|
341
|
+
username: str | None = None
|
|
342
|
+
usernames: list[str] = []
|
|
343
|
+
# -- dialog record --
|
|
344
|
+
folder_id: int | None = None
|
|
345
|
+
pinned: bool | None = None
|
|
346
|
+
unread: int | None = None
|
|
347
|
+
unread_mentions: int | None = None
|
|
348
|
+
unread_reactions: int | None = None
|
|
349
|
+
unread_mark: bool | None = None
|
|
350
|
+
read_inbox_max_id: int | None = None
|
|
351
|
+
read_outbox_max_id: int | None = None
|
|
352
|
+
top_message_id: int | None = None
|
|
353
|
+
notify_settings: NotifySettings | None = None
|
|
354
|
+
draft: Draft | None = None
|
|
355
|
+
ttl_period: int | None = None
|
|
356
|
+
theme: ChatTheme | None = None
|
|
357
|
+
wallpaper: ChatWallpaper | None = None
|
|
358
|
+
translations_disabled: bool | None = None
|
|
359
|
+
view_forum_as_messages: bool | None = None
|
|
360
|
+
settings: ActionBar | None = None
|
|
361
|
+
# -- full info --
|
|
362
|
+
blocked: bool | None = None
|
|
363
|
+
blocked_my_stories_from: bool | None = None
|
|
364
|
+
requests_pending: int | None = None
|
|
365
|
+
recent_requesters: list[int] = []
|
|
366
|
+
common_chats_count: int | None = None
|
|
367
|
+
personal_channel_id: int | None = None
|
|
368
|
+
online_count: int | None = None
|
|
369
|
+
restricted: bool | None = None
|
|
370
|
+
restriction_reason: list[str] = []
|
|
371
|
+
default_send_as: int | None = None
|
|
372
|
+
noforwards: bool | None = None
|
|
373
|
+
about: str | None = None
|
|
374
|
+
participants_count: int | None = None
|
|
375
|
+
admins_count: int | None = None
|
|
376
|
+
kicked_count: int | None = None
|
|
377
|
+
banned_count: int | None = None
|
|
378
|
+
creator: bool | None = None
|
|
379
|
+
left: bool | None = None
|
|
380
|
+
forum: bool | None = None
|
|
381
|
+
gigagroup: bool | None = None
|
|
382
|
+
join_to_send: bool | None = None
|
|
383
|
+
join_request: bool | None = None
|
|
384
|
+
slowmode_seconds: int | None = None
|
|
385
|
+
hidden_prehistory: bool | None = None
|
|
386
|
+
participants_hidden: bool | None = None
|
|
387
|
+
antispam: bool | None = None
|
|
388
|
+
linked_chat_id: int | None = None
|
|
389
|
+
linked_monoforum_id: int | None = None
|
|
390
|
+
location: str | None = None
|
|
391
|
+
level: int | None = None
|
|
392
|
+
boosts_applied: int | None = None
|
|
393
|
+
sticker_set: str | None = None
|
|
394
|
+
emoji_set: str | None = None
|
|
395
|
+
available_reactions: list[str] | None = None
|
|
396
|
+
default_banned_rights: dict[str, Any] | None = None
|
|
397
|
+
admin_rights: dict[str, Any] | None = None
|
|
398
|
+
my_rank: str | None = None
|
|
399
|
+
stats_dc: int | None = None
|
|
400
|
+
can_view_stats: bool | None = None
|
|
401
|
+
can_view_participants: bool | None = None
|
|
402
|
+
can_set_stickers: bool | None = None
|
|
403
|
+
can_set_location: bool | None = None
|
|
404
|
+
can_delete_channel: bool | None = None
|
|
405
|
+
can_view_revenue: bool | None = None
|
|
406
|
+
can_view_stars_revenue: bool | None = None
|
|
407
|
+
paid_reactions_available: bool | None = None
|
|
408
|
+
has_welcome_messages: bool | None = None
|
|
409
|
+
exported_invite: str | None = None
|
|
410
|
+
pending_suggestions: list[str] = []
|
|
411
|
+
main_tab: str | None = None
|
|
412
|
+
#: v1's `chat get` spelled the title `name`; kept so a v1 script still reads.
|
|
413
|
+
name: str = ""
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
class ChatSwitches(Model):
|
|
417
|
+
chat_id: int
|
|
418
|
+
noforwards: bool | None = None
|
|
419
|
+
view_forum_as_messages: bool | None = None
|
|
420
|
+
default_send_as: int | None = None
|
|
421
|
+
send_as_options: list[Peer] = []
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
class TtlResult(Model):
|
|
425
|
+
chat_id: int
|
|
426
|
+
ttl_period: int | None = None
|
|
427
|
+
set: bool = False
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
class ThemeResult(Model):
|
|
431
|
+
chat_id: int
|
|
432
|
+
theme: ChatTheme | None = None
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
class WallpaperResult(Model):
|
|
436
|
+
chat_id: int
|
|
437
|
+
wallpaper: ChatWallpaper | None = None
|
|
438
|
+
for_both: bool = False
|
|
439
|
+
overridden: bool = False
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
class TranslateResult(Model):
|
|
443
|
+
chat_id: int
|
|
444
|
+
translations_disabled: bool = False
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
class TypingResult(Model):
|
|
448
|
+
chat_id: int
|
|
449
|
+
action: str = "typing"
|
|
450
|
+
duration: float = 0.0
|
|
451
|
+
#: v1 answered `{"typing": true, "chat_id": …}`; AGENT.md documents it.
|
|
452
|
+
typing: bool = False
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
class UnreadResult(Model):
|
|
456
|
+
chat_id: int
|
|
457
|
+
unread: bool = False
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
class PeerResult(Model):
|
|
461
|
+
"""One peer's outcome inside a bulk operation."""
|
|
462
|
+
|
|
463
|
+
chat_id: int
|
|
464
|
+
ok: bool = False
|
|
465
|
+
error: str | None = None
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
class MuteResult(Model):
|
|
469
|
+
muted: bool = False
|
|
470
|
+
chat_id: int | None = None
|
|
471
|
+
chat_ids: list[int] = []
|
|
472
|
+
mute_until: str | None = None
|
|
473
|
+
mute_until_unix: int | None = None
|
|
474
|
+
stories: bool = False
|
|
475
|
+
results: list[PeerResult] = []
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
class ArchiveResult(Model):
|
|
479
|
+
archived: bool = False
|
|
480
|
+
chat_id: int | None = None
|
|
481
|
+
chat_ids: list[int] = []
|
|
482
|
+
bar_hidden: bool = False
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
class ArchiveSettings(Model):
|
|
486
|
+
archive_and_mute_new_noncontact_peers: bool = False
|
|
487
|
+
keep_archived_unmuted: bool = False
|
|
488
|
+
keep_archived_folders: bool = False
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
class PinnedDialogs(Model):
|
|
492
|
+
pinned: bool = False
|
|
493
|
+
chat_id: int | None = None
|
|
494
|
+
chat_ids: list[int] = []
|
|
495
|
+
folder: str = "main"
|
|
496
|
+
order: list[int] = []
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
class ReadChats(Model):
|
|
500
|
+
read: bool = False
|
|
501
|
+
chat_id: int | None = None
|
|
502
|
+
results: list[PeerResult] = []
|
|
503
|
+
mentions_read: int | None = None
|
|
504
|
+
reactions_read: int | None = None
|
|
505
|
+
polls_read: bool | None = None
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
class ClearResult(Model):
|
|
509
|
+
chat_id: int
|
|
510
|
+
cleared: bool = False
|
|
511
|
+
messages_affected: int = 0
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
class DeleteChatResult(Model):
|
|
515
|
+
chat_id: int
|
|
516
|
+
deleted: bool = False
|
|
517
|
+
#: `me` | `both` | `everyone` — who the chat is gone for.
|
|
518
|
+
scope: str = "me"
|
|
519
|
+
left: bool = False
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
class LeaveResult(Model):
|
|
523
|
+
left: bool = False
|
|
524
|
+
chat_id: int | None = None
|
|
525
|
+
chat_ids: list[int] = []
|
|
526
|
+
errors: list[PeerResult] = []
|
|
527
|
+
#: `messages.getFutureChatCreatorAfterLeave` — who inherits a basic group.
|
|
528
|
+
successor: int | None = None
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
class OpenResult(Model):
|
|
532
|
+
chat_id: int
|
|
533
|
+
marked_read: bool = False
|
|
534
|
+
messages: list[Message] = []
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
class CatchupChat(Model):
|
|
538
|
+
id: int
|
|
539
|
+
chat: Peer | None = None
|
|
540
|
+
name: str = ""
|
|
541
|
+
unread_count: int = 0
|
|
542
|
+
unread_mark: bool = False
|
|
543
|
+
messages: list[Message] = []
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
class Catchup(Model):
|
|
547
|
+
chats: list[CatchupChat] = []
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
class FolderBadge(Model):
|
|
551
|
+
id: int
|
|
552
|
+
title: str = ""
|
|
553
|
+
chats: int = 0
|
|
554
|
+
messages: int = 0
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
class Badge(Model):
|
|
558
|
+
"""The number on the app icon, computed the way a client computes it."""
|
|
559
|
+
|
|
560
|
+
chats: int = 0
|
|
561
|
+
messages: int = 0
|
|
562
|
+
muted_chats: int = 0
|
|
563
|
+
muted_messages: int = 0
|
|
564
|
+
mentions: int = 0
|
|
565
|
+
reactions: int = 0
|
|
566
|
+
folders: list[FolderBadge] = []
|
|
567
|
+
limits: dict[str, Any] | None = None
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
class Poster(Model):
|
|
571
|
+
"""One sender in a chat's recent history."""
|
|
572
|
+
|
|
573
|
+
user_id: int
|
|
574
|
+
#: v1 spelled it `id`; both are emitted so a v1 script keeps working.
|
|
575
|
+
id: int = 0
|
|
576
|
+
username: str | None = None
|
|
577
|
+
name: str = ""
|
|
578
|
+
count: int = 0
|
|
579
|
+
is_bot: bool = False
|
|
580
|
+
is_deleted: bool = False
|
|
581
|
+
last_msg_id: int | None = None
|
|
582
|
+
date: str | None = None
|
|
583
|
+
date_unix: int | None = None
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
class PosterReport(Model):
|
|
587
|
+
posters: list[Poster] = []
|
|
588
|
+
scanned_messages: int = 0
|
|
589
|
+
distinct_posters: int = 0
|
|
590
|
+
#: True when a flood wait cut the scan short: the harvest is a prefix of
|
|
591
|
+
#: the truth, and reporting it as complete is the bug this flag prevents.
|
|
592
|
+
partial: bool = False
|
|
593
|
+
flood_wait: int | None = None
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
class Promo(Model):
|
|
597
|
+
pending_suggestions: list[str] = []
|
|
598
|
+
dismissed_suggestions: list[str] = []
|
|
599
|
+
promo_peer: int | None = None
|
|
600
|
+
psa_type: str | None = None
|
|
601
|
+
psa_message: str | None = None
|
|
602
|
+
birthdays_today: list[int] = []
|
|
603
|
+
hidden: bool = False
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
class SecretChat(Model):
|
|
607
|
+
id: int
|
|
608
|
+
peer: int | None = None
|
|
609
|
+
state: str = "unknown"
|
|
610
|
+
layer: int | None = None
|
|
611
|
+
created: str | None = None
|
|
612
|
+
key_fingerprint: str | None = None
|
|
613
|
+
ttl: int | None = None
|
|
614
|
+
discarded: bool = False
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
class ImportState(Model):
|
|
618
|
+
chat_id: int
|
|
619
|
+
import_id: int | None = None
|
|
620
|
+
media_count: int = 0
|
|
621
|
+
started: bool = False
|
|
622
|
+
messages: int = 0
|
|
623
|
+
media: int = 0
|
|
624
|
+
#: `checked` | `started`. Defaulted to the empty string so the field a
|
|
625
|
+
#: caller branches on is always present in the JSON.
|
|
626
|
+
state: str = ""
|
tlgr/models/envelope.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Request and response envelopes — data only; the transport lives elsewhere.
|
|
2
|
+
|
|
3
|
+
These are defined in `models/` (not `transport/`) because both ends of the
|
|
4
|
+
socket and the CLI renderer need the same shape, and because a test should be
|
|
5
|
+
able to build one without opening a socket.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from tlgr.models.base import Model, Request
|
|
13
|
+
from tlgr.models.error import ErrorBody
|
|
14
|
+
from tlgr.models.page import PageInfo
|
|
15
|
+
|
|
16
|
+
__all__ = ["ErrEnvelope", "Meta", "OkEnvelope", "OpRequest"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class OpRequest(Request):
|
|
20
|
+
"""`POST /v1/op` body.
|
|
21
|
+
|
|
22
|
+
`limit`/`cursor`/`all` sit beside the request rather than inside it so
|
|
23
|
+
that pagination is uniform across every op and no request struct has to
|
|
24
|
+
redeclare it (registry lint L5 forbids those field names).
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
op: str
|
|
28
|
+
account: str = ""
|
|
29
|
+
request: dict[str, Any] = {}
|
|
30
|
+
dry_run: bool = False
|
|
31
|
+
flood_wait_max: int | None = None
|
|
32
|
+
request_id: str = ""
|
|
33
|
+
client_version: str = ""
|
|
34
|
+
protocol: int = 2
|
|
35
|
+
stream: bool = False
|
|
36
|
+
limit: int | None = None
|
|
37
|
+
cursor: str | None = None
|
|
38
|
+
all: bool = False
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Meta(Model):
|
|
42
|
+
request_id: str = ""
|
|
43
|
+
elapsed_ms: int = 0
|
|
44
|
+
flood_wait_slept: int = 0
|
|
45
|
+
warnings: list[str] = []
|
|
46
|
+
# `already: true` is how an idempotent no-op is reported. It is not an
|
|
47
|
+
# error: MESSAGE_NOT_MODIFIED means the world already looks the way the
|
|
48
|
+
# caller asked for, which is success.
|
|
49
|
+
already: bool = False
|
|
50
|
+
daemon_version: str = ""
|
|
51
|
+
protocol: int = 2
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class OkEnvelope(Model):
|
|
55
|
+
ok: bool = True
|
|
56
|
+
op: str = ""
|
|
57
|
+
account: str | None = None
|
|
58
|
+
result: Any = None
|
|
59
|
+
page: PageInfo | None = None
|
|
60
|
+
meta: Meta | None = None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ErrEnvelope(Model):
|
|
64
|
+
error: ErrorBody
|
|
65
|
+
ok: bool = False
|
|
66
|
+
op: str = ""
|
|
67
|
+
account: str | None = None
|
|
68
|
+
meta: Meta | None = None
|
tlgr/models/error.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""The wire error shape and the stable machine names that go in it."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from tlgr.models.base import Model
|
|
8
|
+
|
|
9
|
+
__all__ = ["ErrorBody"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ErrorBody(Model):
|
|
13
|
+
"""One error, everywhere: daemon response body, CLI JSON output, event.
|
|
14
|
+
|
|
15
|
+
`code` is the stable machine name and `exit_code` is what the CLI exits
|
|
16
|
+
with; the two are looked up together from a single table (`core.errors`)
|
|
17
|
+
so a new error can never arrive with a plausible-looking wrong exit.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
code: str
|
|
21
|
+
message: str
|
|
22
|
+
exit_code: int
|
|
23
|
+
retryable: bool = False
|
|
24
|
+
wait_seconds: int | None = None
|
|
25
|
+
field: str | None = None
|
|
26
|
+
hint: str | None = None
|
|
27
|
+
rpc: dict[str, Any] | None = None
|
|
28
|
+
account: str | None = None
|
|
29
|
+
request_id: str | None = None
|
|
30
|
+
reason: str | None = None
|