git.iko.soy/personality-traits
on 4dcdcd8 help sign in
31 files changed+14−4720
since splitsnapshots
unifiedsplit
.env.example−5 .gitignore−7 Cargo.lock−3122 Cargo.toml−20 README.md−74 migrations/0001_init.sql−47 ac.md → questionnaire/abfi-1/ac.md questionnaire/abfi-1/centralkeys.yaml+14−303 questionnaire/abfi-1/data/1.2.png questionnaire/abfi-1/data/2.1.png questionnaire/abfi-1/data/2.10.png questionnaire/abfi-1/data/2.11.png questionnaire/abfi-1/data/2.12.png questionnaire/abfi-1/data/2.13.png questionnaire/abfi-1/data/2.14.png questionnaire/abfi-1/data/2.2.png questionnaire/abfi-1/data/2.3.png questionnaire/abfi-1/data/2.4.png questionnaire/abfi-1/data/2.5.png questionnaire/abfi-1/data/2.6.png questionnaire/abfi-1/data/2.7.png questionnaire/abfi-1/data/2.8.png questionnaire/abfi-1/data/2.9.png src/config.rs−25 src/db.rs−239 src/events.rs−161 src/handlers.rs−390 src/main.rs−52 src/media.rs−157 src/scheduler.rs−85 tests/parse_events.rs−33
.env.exampledeleted−5
@@ -1,5 +0,0 @@
1−TELOXIDE_TOKEN=put_your_bot_token_here
2−DATABASE_URL=sqlite://bot.db?mode=rwc
3−EVENTS_FILE=questionnaire/abfi-1/events.yaml
4−DATA_DIR=questionnaire/abfi-1/data
5−RUST_LOG=info,personality_traits_bot=debug,teloxide=info
.gitignore−7
@@ -13,13 +13,6 @@ target
1313# Contains mutation testing data
1414**/mutants.out*/
1515
16−# Env and local DB
17−.env
18−*.db
19−*.db-journal
20−*.db-wal
21−*.db-shm
22−
2316# RustRover
2417# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
2518# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
Cargo.lockdeleted−3122
@@ -1,3122 +0,0 @@
1−# This file is automatically @generated by Cargo.
2−# It is not intended for manual editing.
3−version = 4
4−
5−[[package]]
6−name = "aho-corasick"
7−version = "1.1.4"
8−source = "registry+https://github.com/rust-lang/crates.io-index"
9−checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
10−dependencies = [
11− "memchr",
12−]
13−
14−[[package]]
15−name = "allocator-api2"
16−version = "0.2.21"
17−source = "registry+https://github.com/rust-lang/crates.io-index"
18−checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
19−
20−[[package]]
21−name = "android_system_properties"
22−version = "0.1.5"
23−source = "registry+https://github.com/rust-lang/crates.io-index"
24−checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
25−dependencies = [
26− "libc",
27−]
28−
29−[[package]]
30−name = "anyhow"
31−version = "1.0.102"
32−source = "registry+https://github.com/rust-lang/crates.io-index"
33−checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
34−
35−[[package]]
36−name = "aquamarine"
37−version = "0.5.0"
38−source = "registry+https://github.com/rust-lang/crates.io-index"
39−checksum = "21cc1548309245035eb18aa7f0967da6bc65587005170c56e6ef2788a4cf3f4e"
40−dependencies = [
41− "include_dir",
42− "itertools",
43− "proc-macro-error",
44− "proc-macro2",
45− "quote",
46− "syn 2.0.117",
47−]
48−
49−[[package]]
50−name = "atoi"
51−version = "2.0.0"
52−source = "registry+https://github.com/rust-lang/crates.io-index"
53−checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528"
54−dependencies = [
55− "num-traits",
56−]
57−
58−[[package]]
59−name = "autocfg"
60−version = "1.5.0"
61−source = "registry+https://github.com/rust-lang/crates.io-index"
62−checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
63−
64−[[package]]
65−name = "base64"
66−version = "0.21.7"
67−source = "registry+https://github.com/rust-lang/crates.io-index"
68−checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
69−
70−[[package]]
71−name = "base64"
72−version = "0.22.1"
73−source = "registry+https://github.com/rust-lang/crates.io-index"
74−checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
75−
76−[[package]]
77−name = "base64ct"
78−version = "1.8.3"
79−source = "registry+https://github.com/rust-lang/crates.io-index"
80−checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
81−
82−[[package]]
83−name = "bitflags"
84−version = "1.3.2"
85−source = "registry+https://github.com/rust-lang/crates.io-index"
86−checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
87−
88−[[package]]
89−name = "bitflags"
90−version = "2.11.1"
91−source = "registry+https://github.com/rust-lang/crates.io-index"
92−checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
93−dependencies = [
94− "serde_core",
95−]
96−
97−[[package]]
98−name = "block-buffer"
99−version = "0.10.4"
100−source = "registry+https://github.com/rust-lang/crates.io-index"
101−checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
102−dependencies = [
103− "generic-array",
104−]
105−
106−[[package]]
107−name = "bumpalo"
108−version = "3.20.2"
109−source = "registry+https://github.com/rust-lang/crates.io-index"
110−checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
111−
112−[[package]]
113−name = "byteorder"
114−version = "1.5.0"
115−source = "registry+https://github.com/rust-lang/crates.io-index"
116−checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
117−
118−[[package]]
119−name = "bytes"
120−version = "1.11.1"
121−source = "registry+https://github.com/rust-lang/crates.io-index"
122−checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
123−
124−[[package]]
125−name = "cc"
126−version = "1.2.62"
127−source = "registry+https://github.com/rust-lang/crates.io-index"
128−checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
129−dependencies = [
130− "find-msvc-tools",
131− "shlex",
132−]
133−
134−[[package]]
135−name = "cfg-if"
136−version = "1.0.4"
137−source = "registry+https://github.com/rust-lang/crates.io-index"
138−checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
139−
140−[[package]]
141−name = "chrono"
142−version = "0.4.44"
143−source = "registry+https://github.com/rust-lang/crates.io-index"
144−checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
145−dependencies = [
146− "iana-time-zone",
147− "js-sys",
148− "num-traits",
149− "serde",
150− "wasm-bindgen",
151− "windows-link",
152−]
153−
154−[[package]]
155−name = "concurrent-queue"
156−version = "2.5.0"
157−source = "registry+https://github.com/rust-lang/crates.io-index"
158−checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
159−dependencies = [
160− "crossbeam-utils",
161−]
162−
163−[[package]]
164−name = "const-oid"
165−version = "0.9.6"
166−source = "registry+https://github.com/rust-lang/crates.io-index"
167−checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
168−
169−[[package]]
170−name = "convert_case"
171−version = "0.4.0"
172−source = "registry+https://github.com/rust-lang/crates.io-index"
173−checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
174−
175−[[package]]
176−name = "core-foundation"
177−version = "0.9.4"
178−source = "registry+https://github.com/rust-lang/crates.io-index"
179−checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
180−dependencies = [
181− "core-foundation-sys",
182− "libc",
183−]
184−
185−[[package]]
186−name = "core-foundation"
187−version = "0.10.1"
188−source = "registry+https://github.com/rust-lang/crates.io-index"
189−checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
190−dependencies = [
191− "core-foundation-sys",
192− "libc",
193−]
194−
195−[[package]]
196−name = "core-foundation-sys"
197−version = "0.8.7"
198−source = "registry+https://github.com/rust-lang/crates.io-index"
199−checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
200−
201−[[package]]
202−name = "cpufeatures"
203−version = "0.2.17"
204−source = "registry+https://github.com/rust-lang/crates.io-index"
205−checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
206−dependencies = [
207− "libc",
208−]
209−
210−[[package]]
211−name = "crc"
212−version = "3.4.0"
213−source = "registry+https://github.com/rust-lang/crates.io-index"
214−checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
215−dependencies = [
216− "crc-catalog",
217−]
218−
219−[[package]]
220−name = "crc-catalog"
221−version = "2.5.0"
222−source = "registry+https://github.com/rust-lang/crates.io-index"
223−checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853"
224−
225−[[package]]
226−name = "crossbeam-queue"
227−version = "0.3.12"
228−source = "registry+https://github.com/rust-lang/crates.io-index"
229−checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
230−dependencies = [
231− "crossbeam-utils",
232−]
233−
234−[[package]]
235−name = "crossbeam-utils"
236−version = "0.8.21"
237−source = "registry+https://github.com/rust-lang/crates.io-index"
238−checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
239−
240−[[package]]
241−name = "crypto-common"
242−version = "0.1.7"
243−source = "registry+https://github.com/rust-lang/crates.io-index"
244−checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
245−dependencies = [
246− "generic-array",
247− "typenum",
248−]
249−
250−[[package]]
251−name = "darling"
252−version = "0.13.4"
253−source = "registry+https://github.com/rust-lang/crates.io-index"
254−checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
255−dependencies = [
256− "darling_core",
257− "darling_macro",
258−]
259−
260−[[package]]
261−name = "darling_core"
262−version = "0.13.4"
263−source = "registry+https://github.com/rust-lang/crates.io-index"
264−checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
265−dependencies = [
266− "fnv",
267− "ident_case",
268− "proc-macro2",
269− "quote",
270− "strsim",
271− "syn 1.0.109",
272−]
273−
274−[[package]]
275−name = "darling_macro"
276−version = "0.13.4"
277−source = "registry+https://github.com/rust-lang/crates.io-index"
278−checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
279−dependencies = [
280− "darling_core",
281− "quote",
282− "syn 1.0.109",
283−]
284−
285−[[package]]
286−name = "der"
287−version = "0.7.10"
288−source = "registry+https://github.com/rust-lang/crates.io-index"
289−checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
290−dependencies = [
291− "const-oid",
292− "pem-rfc7468",
293− "zeroize",
294−]
295−
296−[[package]]
297−name = "derive_more"
298−version = "0.99.20"
299−source = "registry+https://github.com/rust-lang/crates.io-index"
300−checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f"
301−dependencies = [
302− "convert_case",
303− "proc-macro2",
304− "quote",
305− "rustc_version",
306− "syn 2.0.117",
307−]
308−
309−[[package]]
310−name = "digest"
311−version = "0.10.7"
312−source = "registry+https://github.com/rust-lang/crates.io-index"
313−checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
314−dependencies = [
315− "block-buffer",
316− "const-oid",
317− "crypto-common",
318− "subtle",
319−]
320−
321−[[package]]
322−name = "displaydoc"
323−version = "0.2.5"
324−source = "registry+https://github.com/rust-lang/crates.io-index"
325−checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
326−dependencies = [
327− "proc-macro2",
328− "quote",
329− "syn 2.0.117",
330−]
331−
332−[[package]]
333−name = "dotenvy"
334−version = "0.15.7"
335−source = "registry+https://github.com/rust-lang/crates.io-index"
336−checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
337−
338−[[package]]
339−name = "dptree"
340−version = "0.3.0"
341−source = "registry+https://github.com/rust-lang/crates.io-index"
342−checksum = "d81175dab5ec79c30e0576df2ed2c244e1721720c302000bb321b107e82e265c"
343−dependencies = [
344− "futures",
345−]
346−
347−[[package]]
348−name = "either"
349−version = "1.15.0"
350−source = "registry+https://github.com/rust-lang/crates.io-index"
351−checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
352−dependencies = [
353− "serde",
354−]
355−
356−[[package]]
357−name = "encoding_rs"
358−version = "0.8.35"
359−source = "registry+https://github.com/rust-lang/crates.io-index"
360−checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
361−dependencies = [
362− "cfg-if",
363−]
364−
365−[[package]]
366−name = "equivalent"
367−version = "1.0.2"
368−source = "registry+https://github.com/rust-lang/crates.io-index"
369−checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
370−
371−[[package]]
372−name = "erasable"
373−version = "1.3.0"
374−source = "registry+https://github.com/rust-lang/crates.io-index"
375−checksum = "437cfb75878119ed8265685c41a115724eae43fb7cc5a0bf0e4ecc3b803af1c4"
376−dependencies = [
377− "autocfg",
378− "scopeguard",
379−]
380−
381−[[package]]
382−name = "errno"
383−version = "0.3.14"
384−source = "registry+https://github.com/rust-lang/crates.io-index"
385−checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
386−dependencies = [
387− "libc",
388− "windows-sys 0.61.2",
389−]
390−
391−[[package]]
392−name = "etcetera"
393−version = "0.8.0"
394−source = "registry+https://github.com/rust-lang/crates.io-index"
395−checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
396−dependencies = [
397− "cfg-if",
398− "home",
399− "windows-sys 0.48.0",
400−]
401−
402−[[package]]
403−name = "event-listener"
404−version = "5.4.1"
405−source = "registry+https://github.com/rust-lang/crates.io-index"
406−checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
407−dependencies = [
408− "concurrent-queue",
409− "parking",
410− "pin-project-lite",
411−]
412−
413−[[package]]
414−name = "fastrand"
415−version = "2.4.1"
416−source = "registry+https://github.com/rust-lang/crates.io-index"
417−checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
418−
419−[[package]]
420−name = "find-msvc-tools"
421−version = "0.1.9"
422−source = "registry+https://github.com/rust-lang/crates.io-index"
423−checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
424−
425−[[package]]
426−name = "flume"
427−version = "0.11.1"
428−source = "registry+https://github.com/rust-lang/crates.io-index"
429−checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
430−dependencies = [
431− "futures-core",
432− "futures-sink",
433− "spin",
434−]
435−
436−[[package]]
437−name = "fnv"
438−version = "1.0.7"
439−source = "registry+https://github.com/rust-lang/crates.io-index"
440−checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
441−
442−[[package]]
443−name = "foldhash"
444−version = "0.1.5"
445−source = "registry+https://github.com/rust-lang/crates.io-index"
446−checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
447−
448−[[package]]
449−name = "foreign-types"
450−version = "0.3.2"
451−source = "registry+https://github.com/rust-lang/crates.io-index"
452−checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
453−dependencies = [
454− "foreign-types-shared",
455−]
456−
457−[[package]]
458−name = "foreign-types-shared"
459−version = "0.1.1"
460−source = "registry+https://github.com/rust-lang/crates.io-index"
461−checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
462−
463−[[package]]
464−name = "form_urlencoded"
465−version = "1.2.2"
466−source = "registry+https://github.com/rust-lang/crates.io-index"
467−checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
468−dependencies = [
469− "percent-encoding",
470−]
471−
472−[[package]]
473−name = "futures"
474−version = "0.3.32"
475−source = "registry+https://github.com/rust-lang/crates.io-index"
476−checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
477−dependencies = [
478− "futures-channel",
479− "futures-core",
480− "futures-executor",
481− "futures-io",
482− "futures-sink",
483− "futures-task",
484− "futures-util",
485−]
486−
487−[[package]]
488−name = "futures-channel"
489−version = "0.3.32"
490−source = "registry+https://github.com/rust-lang/crates.io-index"
491−checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
492−dependencies = [
493− "futures-core",
494− "futures-sink",
495−]
496−
497−[[package]]
498−name = "futures-core"
499−version = "0.3.32"
500−source = "registry+https://github.com/rust-lang/crates.io-index"
501−checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
502−
503−[[package]]
504−name = "futures-executor"
505−version = "0.3.32"
506−source = "registry+https://github.com/rust-lang/crates.io-index"
507−checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
508−dependencies = [
509− "futures-core",
510− "futures-task",
511− "futures-util",
512−]
513−
514−[[package]]
515−name = "futures-intrusive"
516−version = "0.5.0"
517−source = "registry+https://github.com/rust-lang/crates.io-index"
518−checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f"
519−dependencies = [
520− "futures-core",
521− "lock_api",
522− "parking_lot",
523−]
524−
525−[[package]]
526−name = "futures-io"
527−version = "0.3.32"
528−source = "registry+https://github.com/rust-lang/crates.io-index"
529−checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
530−
531−[[package]]
532−name = "futures-macro"
533−version = "0.3.32"
534−source = "registry+https://github.com/rust-lang/crates.io-index"
535−checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
536−dependencies = [
537− "proc-macro2",
538− "quote",
539− "syn 2.0.117",
540−]
541−
542−[[package]]
543−name = "futures-sink"
544−version = "0.3.32"
545−source = "registry+https://github.com/rust-lang/crates.io-index"
546−checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
547−
548−[[package]]
549−name = "futures-task"
550−version = "0.3.32"
551−source = "registry+https://github.com/rust-lang/crates.io-index"
552−checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
553−
554−[[package]]
555−name = "futures-util"
556−version = "0.3.32"
557−source = "registry+https://github.com/rust-lang/crates.io-index"
558−checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
559−dependencies = [
560− "futures-channel",
561− "futures-core",
562− "futures-io",
563− "futures-macro",
564− "futures-sink",
565− "futures-task",
566− "memchr",
567− "pin-project-lite",
568− "slab",
569−]
570−
571−[[package]]
572−name = "generic-array"
573−version = "0.14.7"
574−source = "registry+https://github.com/rust-lang/crates.io-index"
575−checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
576−dependencies = [
577− "typenum",
578− "version_check",
579−]
580−
581−[[package]]
582−name = "getrandom"
583−version = "0.2.17"
584−source = "registry+https://github.com/rust-lang/crates.io-index"
585−checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
586−dependencies = [
587− "cfg-if",
588− "libc",
589− "wasi",
590−]
591−
592−[[package]]
593−name = "getrandom"
594−version = "0.4.2"
595−source = "registry+https://github.com/rust-lang/crates.io-index"
596−checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
597−dependencies = [
598− "cfg-if",
599− "libc",
600− "r-efi",
601− "wasip2",
602− "wasip3",
603−]
604−
605−[[package]]
606−name = "h2"
607−version = "0.3.27"
608−source = "registry+https://github.com/rust-lang/crates.io-index"
609−checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d"
610−dependencies = [
611− "bytes",
612− "fnv",
613− "futures-core",
614− "futures-sink",
615− "futures-util",
616− "http",
617− "indexmap",
618− "slab",
619− "tokio",
620− "tokio-util",
621− "tracing",
622−]
623−
624−[[package]]
625−name = "hashbrown"
626−version = "0.15.5"
627−source = "registry+https://github.com/rust-lang/crates.io-index"
628−checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
629−dependencies = [
630− "allocator-api2",
631− "equivalent",
632− "foldhash",
633−]
634−
635−[[package]]
636−name = "hashbrown"
637−version = "0.17.1"
638−source = "registry+https://github.com/rust-lang/crates.io-index"
639−checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
640−
641−[[package]]
642−name = "hashlink"
643−version = "0.10.0"
644−source = "registry+https://github.com/rust-lang/crates.io-index"
645−checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
646−dependencies = [
647− "hashbrown 0.15.5",
648−]
649−
650−[[package]]
651−name = "heck"
652−version = "0.4.1"
653−source = "registry+https://github.com/rust-lang/crates.io-index"
654−checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
655−
656−[[package]]
657−name = "heck"
658−version = "0.5.0"
659−source = "registry+https://github.com/rust-lang/crates.io-index"
660−checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
661−
662−[[package]]
663−name = "hex"
664−version = "0.4.3"
665−source = "registry+https://github.com/rust-lang/crates.io-index"
666−checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
667−
668−[[package]]
669−name = "hkdf"
670−version = "0.12.4"
671−source = "registry+https://github.com/rust-lang/crates.io-index"
672−checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
673−dependencies = [
674− "hmac",
675−]
676−
677−[[package]]
678−name = "hmac"
679−version = "0.12.1"
680−source = "registry+https://github.com/rust-lang/crates.io-index"
681−checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
682−dependencies = [
683− "digest",
684−]
685−
686−[[package]]
687−name = "home"
688−version = "0.5.12"
689−source = "registry+https://github.com/rust-lang/crates.io-index"
690−checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
691−dependencies = [
692− "windows-sys 0.61.2",
693−]
694−
695−[[package]]
696−name = "http"
697−version = "0.2.12"
698−source = "registry+https://github.com/rust-lang/crates.io-index"
699−checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
700−dependencies = [
701− "bytes",
702− "fnv",
703− "itoa",
704−]
705−
706−[[package]]
707−name = "http-body"
708−version = "0.4.6"
709−source = "registry+https://github.com/rust-lang/crates.io-index"
710−checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
711−dependencies = [
712− "bytes",
713− "http",
714− "pin-project-lite",
715−]
716−
717−[[package]]
718−name = "httparse"
719−version = "1.10.1"
720−source = "registry+https://github.com/rust-lang/crates.io-index"
721−checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
722−
723−[[package]]
724−name = "httpdate"
725−version = "1.0.3"
726−source = "registry+https://github.com/rust-lang/crates.io-index"
727−checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
728−
729−[[package]]
730−name = "hyper"
731−version = "0.14.32"
732−source = "registry+https://github.com/rust-lang/crates.io-index"
733−checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
734−dependencies = [
735− "bytes",
736− "futures-channel",
737− "futures-core",
738− "futures-util",
739− "h2",
740− "http",
741− "http-body",
742− "httparse",
743− "httpdate",
744− "itoa",
745− "pin-project-lite",
746− "socket2 0.5.10",
747− "tokio",
748− "tower-service",
749− "tracing",
750− "want",
751−]
752−
753−[[package]]
754−name = "hyper-tls"
755−version = "0.5.0"
756−source = "registry+https://github.com/rust-lang/crates.io-index"
757−checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
758−dependencies = [
759− "bytes",
760− "hyper",
761− "native-tls",
762− "tokio",
763− "tokio-native-tls",
764−]
765−
766−[[package]]
767−name = "iana-time-zone"
768−version = "0.1.65"
769−source = "registry+https://github.com/rust-lang/crates.io-index"
770−checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
771−dependencies = [
772− "android_system_properties",
773− "core-foundation-sys",
774− "iana-time-zone-haiku",
775− "js-sys",
776− "log",
777− "wasm-bindgen",
778− "windows-core",
779−]
780−
781−[[package]]
782−name = "iana-time-zone-haiku"
783−version = "0.1.2"
784−source = "registry+https://github.com/rust-lang/crates.io-index"
785−checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
786−dependencies = [
787− "cc",
788−]
789−
790−[[package]]
791−name = "icu_collections"
792−version = "2.2.0"
793−source = "registry+https://github.com/rust-lang/crates.io-index"
794−checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
795−dependencies = [
796− "displaydoc",
797− "potential_utf",
798− "utf8_iter",
799− "yoke",
800− "zerofrom",
801− "zerovec",
802−]
803−
804−[[package]]
805−name = "icu_locale_core"
806−version = "2.2.0"
807−source = "registry+https://github.com/rust-lang/crates.io-index"
808−checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
809−dependencies = [
810− "displaydoc",
811− "litemap",
812− "tinystr",
813− "writeable",
814− "zerovec",
815−]
816−
817−[[package]]
818−name = "icu_normalizer"
819−version = "2.2.0"
820−source = "registry+https://github.com/rust-lang/crates.io-index"
821−checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
822−dependencies = [
823− "icu_collections",
824− "icu_normalizer_data",
825− "icu_properties",
826− "icu_provider",
827− "smallvec",
828− "zerovec",
829−]
830−
831−[[package]]
832−name = "icu_normalizer_data"
833−version = "2.2.0"
834−source = "registry+https://github.com/rust-lang/crates.io-index"
835−checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
836−
837−[[package]]
838−name = "icu_properties"
839−version = "2.2.0"
840−source = "registry+https://github.com/rust-lang/crates.io-index"
841−checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
842−dependencies = [
843− "icu_collections",
844− "icu_locale_core",
845− "icu_properties_data",
846− "icu_provider",
847− "zerotrie",
848− "zerovec",
849−]
850−
851−[[package]]
852−name = "icu_properties_data"
853−version = "2.2.0"
854−source = "registry+https://github.com/rust-lang/crates.io-index"
855−checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
856−
857−[[package]]
858−name = "icu_provider"
859−version = "2.2.0"
860−source = "registry+https://github.com/rust-lang/crates.io-index"
861−checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
862−dependencies = [
863− "displaydoc",
864− "icu_locale_core",
865− "writeable",
866− "yoke",
867− "zerofrom",
868− "zerotrie",
869− "zerovec",
870−]
871−
872−[[package]]
873−name = "id-arena"
874−version = "2.3.0"
875−source = "registry+https://github.com/rust-lang/crates.io-index"
876−checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
877−
878−[[package]]
879−name = "ident_case"
880−version = "1.0.1"
881−source = "registry+https://github.com/rust-lang/crates.io-index"
882−checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
883−
884−[[package]]
885−name = "idna"
886−version = "1.1.0"
887−source = "registry+https://github.com/rust-lang/crates.io-index"
888−checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
889−dependencies = [
890− "idna_adapter",
891− "smallvec",
892− "utf8_iter",
893−]
894−
895−[[package]]
896−name = "idna_adapter"
897−version = "1.2.2"
898−source = "registry+https://github.com/rust-lang/crates.io-index"
899−checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
900−dependencies = [
901− "icu_normalizer",
902− "icu_properties",
903−]
904−
905−[[package]]
906−name = "include_dir"
907−version = "0.7.4"
908−source = "registry+https://github.com/rust-lang/crates.io-index"
909−checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd"
910−dependencies = [
911− "include_dir_macros",
912−]
913−
914−[[package]]
915−name = "include_dir_macros"
916−version = "0.7.4"
917−source = "registry+https://github.com/rust-lang/crates.io-index"
918−checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75"
919−dependencies = [
920− "proc-macro2",
921− "quote",
922−]
923−
924−[[package]]
925−name = "indexmap"
926−version = "2.14.0"
927−source = "registry+https://github.com/rust-lang/crates.io-index"
928−checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
929−dependencies = [
930− "equivalent",
931− "hashbrown 0.17.1",
932− "serde",
933− "serde_core",
934−]
935−
936−[[package]]
937−name = "ipnet"
938−version = "2.12.0"
939−source = "registry+https://github.com/rust-lang/crates.io-index"
940−checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
941−
942−[[package]]
943−name = "itertools"
944−version = "0.10.5"
945−source = "registry+https://github.com/rust-lang/crates.io-index"
946−checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
947−dependencies = [
948− "either",
949−]
950−
951−[[package]]
952−name = "itoa"
953−version = "1.0.18"
954−source = "registry+https://github.com/rust-lang/crates.io-index"
955−checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
956−
957−[[package]]
958−name = "js-sys"
959−version = "0.3.98"
960−source = "registry+https://github.com/rust-lang/crates.io-index"
961−checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
962−dependencies = [
963− "cfg-if",
964− "futures-util",
965− "once_cell",
966− "wasm-bindgen",
967−]
968−
969−[[package]]
970−name = "lazy_static"
971−version = "1.5.0"
972−source = "registry+https://github.com/rust-lang/crates.io-index"
973−checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
974−dependencies = [
975− "spin",
976−]
977−
978−[[package]]
979−name = "leb128fmt"
980−version = "0.1.0"
981−source = "registry+https://github.com/rust-lang/crates.io-index"
982−checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
983−
984−[[package]]
985−name = "libc"
986−version = "0.2.186"
987−source = "registry+https://github.com/rust-lang/crates.io-index"
988−checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
989−
990−[[package]]
991−name = "libm"
992−version = "0.2.16"
993−source = "registry+https://github.com/rust-lang/crates.io-index"
994−checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
995−
996−[[package]]
997−name = "libredox"
998−version = "0.1.16"
999−source = "registry+https://github.com/rust-lang/crates.io-index"
1000−checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
1001−dependencies = [
1002− "bitflags 2.11.1",
1003− "libc",
1004− "plain",
1005− "redox_syscall 0.7.5",
1006−]
1007−
1008−[[package]]
1009−name = "libsqlite3-sys"
1010−version = "0.30.1"
1011−source = "registry+https://github.com/rust-lang/crates.io-index"
1012−checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
1013−dependencies = [
1014− "cc",
1015− "pkg-config",
1016− "vcpkg",
1017−]
1018−
1019−[[package]]
1020−name = "linux-raw-sys"
1021−version = "0.12.1"
1022−source = "registry+https://github.com/rust-lang/crates.io-index"
1023−checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
1024−
1025−[[package]]
1026−name = "litemap"
1027−version = "0.8.2"
1028−source = "registry+https://github.com/rust-lang/crates.io-index"
1029−checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
1030−
1031−[[package]]
1032−name = "lock_api"
1033−version = "0.4.14"
1034−source = "registry+https://github.com/rust-lang/crates.io-index"
1035−checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
1036−dependencies = [
1037− "scopeguard",
1038−]
1039−
1040−[[package]]
1041−name = "log"
1042−version = "0.4.29"
1043−source = "registry+https://github.com/rust-lang/crates.io-index"
1044−checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
1045−
1046−[[package]]
1047−name = "matchers"
1048−version = "0.2.0"
1049−source = "registry+https://github.com/rust-lang/crates.io-index"
1050−checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
1051−dependencies = [
1052− "regex-automata",
1053−]
1054−
1055−[[package]]
1056−name = "md-5"
1057−version = "0.10.6"
1058−source = "registry+https://github.com/rust-lang/crates.io-index"
1059−checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
1060−dependencies = [
1061− "cfg-if",
1062− "digest",
1063−]
1064−
1065−[[package]]
1066−name = "memchr"
1067−version = "2.8.0"
1068−source = "registry+https://github.com/rust-lang/crates.io-index"
1069−checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
1070−
1071−[[package]]
1072−name = "mime"
1073−version = "0.3.17"
1074−source = "registry+https://github.com/rust-lang/crates.io-index"
1075−checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
1076−
1077−[[package]]
1078−name = "mime_guess"
1079−version = "2.0.5"
1080−source = "registry+https://github.com/rust-lang/crates.io-index"
1081−checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
1082−dependencies = [
1083− "mime",
1084− "unicase",
1085−]
1086−
1087−[[package]]
1088−name = "mio"
1089−version = "1.2.0"
1090−source = "registry+https://github.com/rust-lang/crates.io-index"
1091−checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
1092−dependencies = [
1093− "libc",
1094− "wasi",
1095− "windows-sys 0.61.2",
1096−]
1097−
1098−[[package]]
1099−name = "native-tls"
1100−version = "0.2.18"
1101−source = "registry+https://github.com/rust-lang/crates.io-index"
1102−checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2"
1103−dependencies = [
1104− "libc",
1105− "log",
1106− "openssl",
1107− "openssl-probe",
1108− "openssl-sys",
1109− "schannel",
1110− "security-framework",
1111− "security-framework-sys",
1112− "tempfile",
1113−]
1114−
1115−[[package]]
1116−name = "nu-ansi-term"
1117−version = "0.50.3"
1118−source = "registry+https://github.com/rust-lang/crates.io-index"
1119−checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
1120−dependencies = [
1121− "windows-sys 0.61.2",
1122−]
1123−
1124−[[package]]
1125−name = "num-bigint-dig"
1126−version = "0.8.6"
1127−source = "registry+https://github.com/rust-lang/crates.io-index"
1128−checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7"
1129−dependencies = [
1130− "lazy_static",
1131− "libm",
1132− "num-integer",
1133− "num-iter",
1134− "num-traits",
1135− "rand",
1136− "smallvec",
1137− "zeroize",
1138−]
1139−
1140−[[package]]
1141−name = "num-integer"
1142−version = "0.1.46"
1143−source = "registry+https://github.com/rust-lang/crates.io-index"
1144−checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
1145−dependencies = [
1146− "num-traits",
1147−]
1148−
1149−[[package]]
1150−name = "num-iter"
1151−version = "0.1.45"
1152−source = "registry+https://github.com/rust-lang/crates.io-index"
1153−checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
1154−dependencies = [
1155− "autocfg",
1156− "num-integer",
1157− "num-traits",
1158−]
1159−
1160−[[package]]
1161−name = "num-traits"
1162−version = "0.2.19"
1163−source = "registry+https://github.com/rust-lang/crates.io-index"
1164−checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
1165−dependencies = [
1166− "autocfg",
1167− "libm",
1168−]
1169−
1170−[[package]]
1171−name = "once_cell"
1172−version = "1.21.4"
1173−source = "registry+https://github.com/rust-lang/crates.io-index"
1174−checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
1175−
1176−[[package]]
1177−name = "openssl"
1178−version = "0.10.79"
1179−source = "registry+https://github.com/rust-lang/crates.io-index"
1180−checksum = "bf0b434746ee2832f4f0baf10137e1cabb18cbe6912c69e2e33263c45250f542"
1181−dependencies = [
1182− "bitflags 2.11.1",
1183− "cfg-if",
1184− "foreign-types",
1185− "libc",
1186− "openssl-macros",
1187− "openssl-sys",
1188−]
1189−
1190−[[package]]
1191−name = "openssl-macros"
1192−version = "0.1.1"
1193−source = "registry+https://github.com/rust-lang/crates.io-index"
1194−checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
1195−dependencies = [
1196− "proc-macro2",
1197− "quote",
1198− "syn 2.0.117",
1199−]
1200−
1201−[[package]]
1202−name = "openssl-probe"
1203−version = "0.2.1"
1204−source = "registry+https://github.com/rust-lang/crates.io-index"
1205−checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
1206−
1207−[[package]]
1208−name = "openssl-sys"
1209−version = "0.9.115"
1210−source = "registry+https://github.com/rust-lang/crates.io-index"
1211−checksum = "158fe5b292746440aa6e7a7e690e55aeb72d41505e2804c23c6973ad0e9c9781"
1212−dependencies = [
1213− "cc",
1214− "libc",
1215− "pkg-config",
1216− "vcpkg",
1217−]
1218−
1219−[[package]]
1220−name = "parking"
1221−version = "2.2.1"
1222−source = "registry+https://github.com/rust-lang/crates.io-index"
1223−checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
1224−
1225−[[package]]
1226−name = "parking_lot"
1227−version = "0.12.5"
1228−source = "registry+https://github.com/rust-lang/crates.io-index"
1229−checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
1230−dependencies = [
1231− "lock_api",
1232− "parking_lot_core",
1233−]
1234−
1235−[[package]]
1236−name = "parking_lot_core"
1237−version = "0.9.12"
1238−source = "registry+https://github.com/rust-lang/crates.io-index"
1239−checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
1240−dependencies = [
1241− "cfg-if",
1242− "libc",
1243− "redox_syscall 0.5.18",
1244− "smallvec",
1245− "windows-link",
1246−]
1247−
1248−[[package]]
1249−name = "pem-rfc7468"
1250−version = "0.7.0"
1251−source = "registry+https://github.com/rust-lang/crates.io-index"
1252−checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
1253−dependencies = [
1254− "base64ct",
1255−]
1256−
1257−[[package]]
1258−name = "percent-encoding"
1259−version = "2.3.2"
1260−source = "registry+https://github.com/rust-lang/crates.io-index"
1261−checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
1262−
1263−[[package]]
1264−name = "personality-traits-bot"
1265−version = "0.1.0"
1266−dependencies = [
1267− "anyhow",
1268− "chrono",
1269− "dotenvy",
1270− "once_cell",
1271− "regex",
1272− "serde",
1273− "serde_yaml",
1274− "sqlx",
1275− "teloxide",
1276− "thiserror 1.0.69",
1277− "tokio",
1278− "tracing",
1279− "tracing-subscriber",
1280− "url",
1281−]
1282−
1283−[[package]]
1284−name = "pin-project"
1285−version = "1.1.12"
1286−source = "registry+https://github.com/rust-lang/crates.io-index"
1287−checksum = "cbf0d9e68100b3a7989b4901972f265cd542e560a3a8a724e1e20322f4d06ce9"
1288−dependencies = [
1289− "pin-project-internal",
1290−]
1291−
1292−[[package]]
1293−name = "pin-project-internal"
1294−version = "1.1.12"
1295−source = "registry+https://github.com/rust-lang/crates.io-index"
1296−checksum = "a990e22f43e84855daf260dded30524ef4a9021cc7541c26540500a50b624389"
1297−dependencies = [
1298− "proc-macro2",
1299− "quote",
1300− "syn 2.0.117",
1301−]
1302−
1303−[[package]]
1304−name = "pin-project-lite"
1305−version = "0.2.17"
1306−source = "registry+https://github.com/rust-lang/crates.io-index"
1307−checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
1308−
1309−[[package]]
1310−name = "pkcs1"
1311−version = "0.7.5"
1312−source = "registry+https://github.com/rust-lang/crates.io-index"
1313−checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
1314−dependencies = [
1315− "der",
1316− "pkcs8",
1317− "spki",
1318−]
1319−
1320−[[package]]
1321−name = "pkcs8"
1322−version = "0.10.2"
1323−source = "registry+https://github.com/rust-lang/crates.io-index"
1324−checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
1325−dependencies = [
1326− "der",
1327− "spki",
1328−]
1329−
1330−[[package]]
1331−name = "pkg-config"
1332−version = "0.3.33"
1333−source = "registry+https://github.com/rust-lang/crates.io-index"
1334−checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
1335−
1336−[[package]]
1337−name = "plain"
1338−version = "0.2.3"
1339−source = "registry+https://github.com/rust-lang/crates.io-index"
1340−checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
1341−
1342−[[package]]
1343−name = "potential_utf"
1344−version = "0.1.5"
1345−source = "registry+https://github.com/rust-lang/crates.io-index"
1346−checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
1347−dependencies = [
1348− "zerovec",
1349−]
1350−
1351−[[package]]
1352−name = "ppv-lite86"
1353−version = "0.2.21"
1354−source = "registry+https://github.com/rust-lang/crates.io-index"
1355−checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
1356−dependencies = [
1357− "zerocopy",
1358−]
1359−
1360−[[package]]
1361−name = "prettyplease"
1362−version = "0.2.37"
1363−source = "registry+https://github.com/rust-lang/crates.io-index"
1364−checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
1365−dependencies = [
1366− "proc-macro2",
1367− "syn 2.0.117",
1368−]
1369−
1370−[[package]]
1371−name = "proc-macro-error"
1372−version = "1.0.4"
1373−source = "registry+https://github.com/rust-lang/crates.io-index"
1374−checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
1375−dependencies = [
1376− "proc-macro-error-attr",
1377− "proc-macro2",
1378− "quote",
1379− "syn 1.0.109",
1380− "version_check",
1381−]
1382−
1383−[[package]]
1384−name = "proc-macro-error-attr"
1385−version = "1.0.4"
1386−source = "registry+https://github.com/rust-lang/crates.io-index"
1387−checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
1388−dependencies = [
1389− "proc-macro2",
1390− "quote",
1391− "version_check",
1392−]
1393−
1394−[[package]]
1395−name = "proc-macro2"
1396−version = "1.0.106"
1397−source = "registry+https://github.com/rust-lang/crates.io-index"
1398−checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
1399−dependencies = [
1400− "unicode-ident",
1401−]
1402−
1403−[[package]]
1404−name = "quote"
1405−version = "1.0.45"
1406−source = "registry+https://github.com/rust-lang/crates.io-index"
1407−checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
1408−dependencies = [
1409− "proc-macro2",
1410−]
1411−
1412−[[package]]
1413−name = "r-efi"
1414−version = "6.0.0"
1415−source = "registry+https://github.com/rust-lang/crates.io-index"
1416−checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
1417−
1418−[[package]]
1419−name = "rand"
1420−version = "0.8.6"
1421−source = "registry+https://github.com/rust-lang/crates.io-index"
1422−checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
1423−dependencies = [
1424− "libc",
1425− "rand_chacha",
1426− "rand_core",
1427−]
1428−
1429−[[package]]
1430−name = "rand_chacha"
1431−version = "0.3.1"
1432−source = "registry+https://github.com/rust-lang/crates.io-index"
1433−checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
1434−dependencies = [
1435− "ppv-lite86",
1436− "rand_core",
1437−]
1438−
1439−[[package]]
1440−name = "rand_core"
1441−version = "0.6.4"
1442−source = "registry+https://github.com/rust-lang/crates.io-index"
1443−checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
1444−dependencies = [
1445− "getrandom 0.2.17",
1446−]
1447−
1448−[[package]]
1449−name = "rc-box"
1450−version = "1.3.0"
1451−source = "registry+https://github.com/rust-lang/crates.io-index"
1452−checksum = "897fecc9fac6febd4408f9e935e86df739b0023b625e610e0357535b9c8adad0"
1453−dependencies = [
1454− "erasable",
1455−]
1456−
1457−[[package]]
1458−name = "redox_syscall"
1459−version = "0.5.18"
1460−source = "registry+https://github.com/rust-lang/crates.io-index"
1461−checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
1462−dependencies = [
1463− "bitflags 2.11.1",
1464−]
1465−
1466−[[package]]
1467−name = "redox_syscall"
1468−version = "0.7.5"
1469−source = "registry+https://github.com/rust-lang/crates.io-index"
1470−checksum = "4666a1a60d8412eab19d94f6d13dcc9cea0a5ef4fdf6a5db306537413c661b1b"
1471−dependencies = [
1472− "bitflags 2.11.1",
1473−]
1474−
1475−[[package]]
1476−name = "regex"
1477−version = "1.12.3"
1478−source = "registry+https://github.com/rust-lang/crates.io-index"
1479−checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
1480−dependencies = [
1481− "aho-corasick",
1482− "memchr",
1483− "regex-automata",
1484− "regex-syntax",
1485−]
1486−
1487−[[package]]
1488−name = "regex-automata"
1489−version = "0.4.14"
1490−source = "registry+https://github.com/rust-lang/crates.io-index"
1491−checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
1492−dependencies = [
1493− "aho-corasick",
1494− "memchr",
1495− "regex-syntax",
1496−]
1497−
1498−[[package]]
1499−name = "regex-syntax"
1500−version = "0.8.10"
1501−source = "registry+https://github.com/rust-lang/crates.io-index"
1502−checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
1503−
1504−[[package]]
1505−name = "reqwest"
1506−version = "0.11.27"
1507−source = "registry+https://github.com/rust-lang/crates.io-index"
1508−checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
1509−dependencies = [
1510− "base64 0.21.7",
1511− "bytes",
1512− "encoding_rs",
1513− "futures-core",
1514− "futures-util",
1515− "h2",
1516− "http",
1517− "http-body",
1518− "hyper",
1519− "hyper-tls",
1520− "ipnet",
1521− "js-sys",
1522− "log",
1523− "mime",
1524− "mime_guess",
1525− "native-tls",
1526− "once_cell",
1527− "percent-encoding",
1528− "pin-project-lite",
1529− "rustls-pemfile",
1530− "serde",
1531− "serde_json",
1532− "serde_urlencoded",
1533− "sync_wrapper",
1534− "system-configuration",
1535− "tokio",
1536− "tokio-native-tls",
1537− "tokio-util",
1538− "tower-service",
1539− "url",
1540− "wasm-bindgen",
1541− "wasm-bindgen-futures",
1542− "wasm-streams",
1543− "web-sys",
1544− "winreg",
1545−]
1546−
1547−[[package]]
1548−name = "rsa"
1549−version = "0.9.10"
1550−source = "registry+https://github.com/rust-lang/crates.io-index"
1551−checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d"
1552−dependencies = [
1553− "const-oid",
1554− "digest",
1555− "num-bigint-dig",
1556− "num-integer",
1557− "num-traits",
1558− "pkcs1",
1559− "pkcs8",
1560− "rand_core",
1561− "signature",
1562− "spki",
1563− "subtle",
1564− "zeroize",
1565−]
1566−
1567−[[package]]
1568−name = "rustc_version"
1569−version = "0.4.1"
1570−source = "registry+https://github.com/rust-lang/crates.io-index"
1571−checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
1572−dependencies = [
1573− "semver",
1574−]
1575−
1576−[[package]]
1577−name = "rustix"
1578−version = "1.1.4"
1579−source = "registry+https://github.com/rust-lang/crates.io-index"
1580−checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
1581−dependencies = [
1582− "bitflags 2.11.1",
1583− "errno",
1584− "libc",
1585− "linux-raw-sys",
1586− "windows-sys 0.61.2",
1587−]
1588−
1589−[[package]]
1590−name = "rustls-pemfile"
1591−version = "1.0.4"
1592−source = "registry+https://github.com/rust-lang/crates.io-index"
1593−checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
1594−dependencies = [
1595− "base64 0.21.7",
1596−]
1597−
1598−[[package]]
1599−name = "rustversion"
1600−version = "1.0.22"
1601−source = "registry+https://github.com/rust-lang/crates.io-index"
1602−checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
1603−
1604−[[package]]
1605−name = "ryu"
1606−version = "1.0.23"
1607−source = "registry+https://github.com/rust-lang/crates.io-index"
1608−checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
1609−
1610−[[package]]
1611−name = "schannel"
1612−version = "0.1.29"
1613−source = "registry+https://github.com/rust-lang/crates.io-index"
1614−checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
1615−dependencies = [
1616− "windows-sys 0.61.2",
1617−]
1618−
1619−[[package]]
1620−name = "scopeguard"
1621−version = "1.2.0"
1622−source = "registry+https://github.com/rust-lang/crates.io-index"
1623−checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
1624−
1625−[[package]]
1626−name = "security-framework"
1627−version = "3.7.0"
1628−source = "registry+https://github.com/rust-lang/crates.io-index"
1629−checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
1630−dependencies = [
1631− "bitflags 2.11.1",
1632− "core-foundation 0.10.1",
1633− "core-foundation-sys",
1634− "libc",
1635− "security-framework-sys",
1636−]
1637−
1638−[[package]]
1639−name = "security-framework-sys"
1640−version = "2.17.0"
1641−source = "registry+https://github.com/rust-lang/crates.io-index"
1642−checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
1643−dependencies = [
1644− "core-foundation-sys",
1645− "libc",
1646−]
1647−
1648−[[package]]
1649−name = "semver"
1650−version = "1.0.28"
1651−source = "registry+https://github.com/rust-lang/crates.io-index"
1652−checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
1653−
1654−[[package]]
1655−name = "serde"
1656−version = "1.0.228"
1657−source = "registry+https://github.com/rust-lang/crates.io-index"
1658−checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
1659−dependencies = [
1660− "serde_core",
1661− "serde_derive",
1662−]
1663−
1664−[[package]]
1665−name = "serde_core"
1666−version = "1.0.228"
1667−source = "registry+https://github.com/rust-lang/crates.io-index"
1668−checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
1669−dependencies = [
1670− "serde_derive",
1671−]
1672−
1673−[[package]]
1674−name = "serde_derive"
1675−version = "1.0.228"
1676−source = "registry+https://github.com/rust-lang/crates.io-index"
1677−checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
1678−dependencies = [
1679− "proc-macro2",
1680− "quote",
1681− "syn 2.0.117",
1682−]
1683−
1684−[[package]]
1685−name = "serde_json"
1686−version = "1.0.149"
1687−source = "registry+https://github.com/rust-lang/crates.io-index"
1688−checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
1689−dependencies = [
1690− "itoa",
1691− "memchr",
1692− "serde",
1693− "serde_core",
1694− "zmij",
1695−]
1696−
1697−[[package]]
1698−name = "serde_urlencoded"
1699−version = "0.7.1"
1700−source = "registry+https://github.com/rust-lang/crates.io-index"
1701−checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
1702−dependencies = [
1703− "form_urlencoded",
1704− "itoa",
1705− "ryu",
1706− "serde",
1707−]
1708−
1709−[[package]]
1710−name = "serde_with"
1711−version = "1.14.0"
1712−source = "registry+https://github.com/rust-lang/crates.io-index"
1713−checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
1714−dependencies = [
1715− "serde",
1716− "serde_with_macros",
1717−]
1718−
1719−[[package]]
1720−name = "serde_with_macros"
1721−version = "1.5.2"
1722−source = "registry+https://github.com/rust-lang/crates.io-index"
1723−checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
1724−dependencies = [
1725− "darling",
1726− "proc-macro2",
1727− "quote",
1728− "syn 1.0.109",
1729−]
1730−
1731−[[package]]
1732−name = "serde_yaml"
1733−version = "0.9.34+deprecated"
1734−source = "registry+https://github.com/rust-lang/crates.io-index"
1735−checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
1736−dependencies = [
1737− "indexmap",
1738− "itoa",
1739− "ryu",
1740− "serde",
1741− "unsafe-libyaml",
1742−]
1743−
1744−[[package]]
1745−name = "sha1"
1746−version = "0.10.6"
1747−source = "registry+https://github.com/rust-lang/crates.io-index"
1748−checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
1749−dependencies = [
1750− "cfg-if",
1751− "cpufeatures",
1752− "digest",
1753−]
1754−
1755−[[package]]
1756−name = "sha2"
1757−version = "0.10.9"
1758−source = "registry+https://github.com/rust-lang/crates.io-index"
1759−checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
1760−dependencies = [
1761− "cfg-if",
1762− "cpufeatures",
1763− "digest",
1764−]
1765−
1766−[[package]]
1767−name = "sharded-slab"
1768−version = "0.1.7"
1769−source = "registry+https://github.com/rust-lang/crates.io-index"
1770−checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
1771−dependencies = [
1772− "lazy_static",
1773−]
1774−
1775−[[package]]
1776−name = "shlex"
1777−version = "1.3.0"
1778−source = "registry+https://github.com/rust-lang/crates.io-index"
1779−checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
1780−
1781−[[package]]
1782−name = "signal-hook-registry"
1783−version = "1.4.8"
1784−source = "registry+https://github.com/rust-lang/crates.io-index"
1785−checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
1786−dependencies = [
1787− "errno",
1788− "libc",
1789−]
1790−
1791−[[package]]
1792−name = "signature"
1793−version = "2.2.0"
1794−source = "registry+https://github.com/rust-lang/crates.io-index"
1795−checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
1796−dependencies = [
1797− "digest",
1798− "rand_core",
1799−]
1800−
1801−[[package]]
1802−name = "slab"
1803−version = "0.4.12"
1804−source = "registry+https://github.com/rust-lang/crates.io-index"
1805−checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
1806−
1807−[[package]]
1808−name = "smallvec"
1809−version = "1.15.1"
1810−source = "registry+https://github.com/rust-lang/crates.io-index"
1811−checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
1812−dependencies = [
1813− "serde",
1814−]
1815−
1816−[[package]]
1817−name = "socket2"
1818−version = "0.5.10"
1819−source = "registry+https://github.com/rust-lang/crates.io-index"
1820−checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
1821−dependencies = [
1822− "libc",
1823− "windows-sys 0.52.0",
1824−]
1825−
1826−[[package]]
1827−name = "socket2"
1828−version = "0.6.3"
1829−source = "registry+https://github.com/rust-lang/crates.io-index"
1830−checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
1831−dependencies = [
1832− "libc",
1833− "windows-sys 0.61.2",
1834−]
1835−
1836−[[package]]
1837−name = "spin"
1838−version = "0.9.8"
1839−source = "registry+https://github.com/rust-lang/crates.io-index"
1840−checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
1841−dependencies = [
1842− "lock_api",
1843−]
1844−
1845−[[package]]
1846−name = "spki"
1847−version = "0.7.3"
1848−source = "registry+https://github.com/rust-lang/crates.io-index"
1849−checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
1850−dependencies = [
1851− "base64ct",
1852− "der",
1853−]
1854−
1855−[[package]]
1856−name = "sqlx"
1857−version = "0.8.6"
1858−source = "registry+https://github.com/rust-lang/crates.io-index"
1859−checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc"
1860−dependencies = [
1861− "sqlx-core",
1862− "sqlx-macros",
1863− "sqlx-mysql",
1864− "sqlx-postgres",
1865− "sqlx-sqlite",
1866−]
1867−
1868−[[package]]
1869−name = "sqlx-core"
1870−version = "0.8.6"
1871−source = "registry+https://github.com/rust-lang/crates.io-index"
1872−checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
1873−dependencies = [
1874− "base64 0.22.1",
1875− "bytes",
1876− "chrono",
1877− "crc",
1878− "crossbeam-queue",
1879− "either",
1880− "event-listener",
1881− "futures-core",
1882− "futures-intrusive",
1883− "futures-io",
1884− "futures-util",
1885− "hashbrown 0.15.5",
1886− "hashlink",
1887− "indexmap",
1888− "log",
1889− "memchr",
1890− "once_cell",
1891− "percent-encoding",
1892− "serde",
1893− "serde_json",
1894− "sha2",
1895− "smallvec",
1896− "thiserror 2.0.18",
1897− "tokio",
1898− "tokio-stream",
1899− "tracing",
1900− "url",
1901−]
1902−
1903−[[package]]
1904−name = "sqlx-macros"
1905−version = "0.8.6"
1906−source = "registry+https://github.com/rust-lang/crates.io-index"
1907−checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d"
1908−dependencies = [
1909− "proc-macro2",
1910− "quote",
1911− "sqlx-core",
1912− "sqlx-macros-core",
1913− "syn 2.0.117",
1914−]
1915−
1916−[[package]]
1917−name = "sqlx-macros-core"
1918−version = "0.8.6"
1919−source = "registry+https://github.com/rust-lang/crates.io-index"
1920−checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b"
1921−dependencies = [
1922− "dotenvy",
1923− "either",
1924− "heck 0.5.0",
1925− "hex",
1926− "once_cell",
1927− "proc-macro2",
1928− "quote",
1929− "serde",
1930− "serde_json",
1931− "sha2",
1932− "sqlx-core",
1933− "sqlx-mysql",
1934− "sqlx-postgres",
1935− "sqlx-sqlite",
1936− "syn 2.0.117",
1937− "tokio",
1938− "url",
1939−]
1940−
1941−[[package]]
1942−name = "sqlx-mysql"
1943−version = "0.8.6"
1944−source = "registry+https://github.com/rust-lang/crates.io-index"
1945−checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
1946−dependencies = [
1947− "atoi",
1948− "base64 0.22.1",
1949− "bitflags 2.11.1",
1950− "byteorder",
1951− "bytes",
1952− "chrono",
1953− "crc",
1954− "digest",
1955− "dotenvy",
1956− "either",
1957− "futures-channel",
1958− "futures-core",
1959− "futures-io",
1960− "futures-util",
1961− "generic-array",
1962− "hex",
1963− "hkdf",
1964− "hmac",
1965− "itoa",
1966− "log",
1967− "md-5",
1968− "memchr",
1969− "once_cell",
1970− "percent-encoding",
1971− "rand",
1972− "rsa",
1973− "serde",
1974− "sha1",
1975− "sha2",
1976− "smallvec",
1977− "sqlx-core",
1978− "stringprep",
1979− "thiserror 2.0.18",
1980− "tracing",
1981− "whoami",
1982−]
1983−
1984−[[package]]
1985−name = "sqlx-postgres"
1986−version = "0.8.6"
1987−source = "registry+https://github.com/rust-lang/crates.io-index"
1988−checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
1989−dependencies = [
1990− "atoi",
1991− "base64 0.22.1",
1992− "bitflags 2.11.1",
1993− "byteorder",
1994− "chrono",
1995− "crc",
1996− "dotenvy",
1997− "etcetera",
1998− "futures-channel",
1999− "futures-core",
2000− "futures-util",
2001− "hex",
2002− "hkdf",
2003− "hmac",
2004− "home",
2005− "itoa",
2006− "log",
2007− "md-5",
2008− "memchr",
2009− "once_cell",
2010− "rand",
2011− "serde",
2012− "serde_json",
2013− "sha2",
2014− "smallvec",
2015− "sqlx-core",
2016− "stringprep",
2017− "thiserror 2.0.18",
2018− "tracing",
2019− "whoami",
2020−]
2021−
2022−[[package]]
2023−name = "sqlx-sqlite"
2024−version = "0.8.6"
2025−source = "registry+https://github.com/rust-lang/crates.io-index"
2026−checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
2027−dependencies = [
2028− "atoi",
2029− "chrono",
2030− "flume",
2031− "futures-channel",
2032− "futures-core",
2033− "futures-executor",
2034− "futures-intrusive",
2035− "futures-util",
2036− "libsqlite3-sys",
2037− "log",
2038− "percent-encoding",
2039− "serde",
2040− "serde_urlencoded",
2041− "sqlx-core",
2042− "thiserror 2.0.18",
2043− "tracing",
2044− "url",
2045−]
2046−
2047−[[package]]
2048−name = "stable_deref_trait"
2049−version = "1.2.1"
2050−source = "registry+https://github.com/rust-lang/crates.io-index"
2051−checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
2052−
2053−[[package]]
2054−name = "stringprep"
2055−version = "0.1.5"
2056−source = "registry+https://github.com/rust-lang/crates.io-index"
2057−checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1"
2058−dependencies = [
2059− "unicode-bidi",
2060− "unicode-normalization",
2061− "unicode-properties",
2062−]
2063−
2064−[[package]]
2065−name = "strsim"
2066−version = "0.10.0"
2067−source = "registry+https://github.com/rust-lang/crates.io-index"
2068−checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
2069−
2070−[[package]]
2071−name = "subtle"
2072−version = "2.6.1"
2073−source = "registry+https://github.com/rust-lang/crates.io-index"
2074−checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
2075−
2076−[[package]]
2077−name = "syn"
2078−version = "1.0.109"
2079−source = "registry+https://github.com/rust-lang/crates.io-index"
2080−checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
2081−dependencies = [
2082− "proc-macro2",
2083− "quote",
2084− "unicode-ident",
2085−]
2086−
2087−[[package]]
2088−name = "syn"
2089−version = "2.0.117"
2090−source = "registry+https://github.com/rust-lang/crates.io-index"
2091−checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
2092−dependencies = [
2093− "proc-macro2",
2094− "quote",
2095− "unicode-ident",
2096−]
2097−
2098−[[package]]
2099−name = "sync_wrapper"
2100−version = "0.1.2"
2101−source = "registry+https://github.com/rust-lang/crates.io-index"
2102−checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
2103−
2104−[[package]]
2105−name = "synstructure"
2106−version = "0.13.2"
2107−source = "registry+https://github.com/rust-lang/crates.io-index"
2108−checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
2109−dependencies = [
2110− "proc-macro2",
2111− "quote",
2112− "syn 2.0.117",
2113−]
2114−
2115−[[package]]
2116−name = "system-configuration"
2117−version = "0.5.1"
2118−source = "registry+https://github.com/rust-lang/crates.io-index"
2119−checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
2120−dependencies = [
2121− "bitflags 1.3.2",
2122− "core-foundation 0.9.4",
2123− "system-configuration-sys",
2124−]
2125−
2126−[[package]]
2127−name = "system-configuration-sys"
2128−version = "0.5.0"
2129−source = "registry+https://github.com/rust-lang/crates.io-index"
2130−checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
2131−dependencies = [
2132− "core-foundation-sys",
2133− "libc",
2134−]
2135−
2136−[[package]]
2137−name = "take_mut"
2138−version = "0.2.2"
2139−source = "registry+https://github.com/rust-lang/crates.io-index"
2140−checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
2141−
2142−[[package]]
2143−name = "takecell"
2144−version = "0.1.1"
2145−source = "registry+https://github.com/rust-lang/crates.io-index"
2146−checksum = "20f34339676cdcab560c9a82300c4c2581f68b9369aedf0fae86f2ff9565ff3e"
2147−
2148−[[package]]
2149−name = "teloxide"
2150−version = "0.13.0"
2151−source = "registry+https://github.com/rust-lang/crates.io-index"
2152−checksum = "5f79dd283eb21b90451c03fa7c7f83b9985130efb876b33bad89a2c208ccbc16"
2153−dependencies = [
2154− "aquamarine",
2155− "bytes",
2156− "derive_more",
2157− "dptree",
2158− "either",
2159− "futures",
2160− "log",
2161− "mime",
2162− "pin-project",
2163− "serde",
2164− "serde_json",
2165− "teloxide-core",
2166− "teloxide-macros",
2167− "thiserror 1.0.69",
2168− "tokio",
2169− "tokio-stream",
2170− "tokio-util",
2171− "url",
2172−]
2173−
2174−[[package]]
2175−name = "teloxide-core"
2176−version = "0.10.1"
2177−source = "registry+https://github.com/rust-lang/crates.io-index"
2178−checksum = "9e1642a7ef10e7af63b8298c8d13c0f986d4fc646d42649ff060359607f62f69"
2179−dependencies = [
2180− "bitflags 1.3.2",
2181− "bytes",
2182− "chrono",
2183− "derive_more",
2184− "either",
2185− "futures",
2186− "log",
2187− "mime",
2188− "once_cell",
2189− "pin-project",
2190− "rc-box",
2191− "reqwest",
2192− "serde",
2193− "serde_json",
2194− "serde_with",
2195− "take_mut",
2196− "takecell",
2197− "thiserror 1.0.69",
2198− "tokio",
2199− "tokio-util",
2200− "url",
2201− "uuid",
2202−]
2203−
2204−[[package]]
2205−name = "teloxide-macros"
2206−version = "0.8.0"
2207−source = "registry+https://github.com/rust-lang/crates.io-index"
2208−checksum = "7e2d33d809c3e7161a9ab18bedddf98821245014f0a78fa4d2c9430b2ec018c1"
2209−dependencies = [
2210− "heck 0.4.1",
2211− "proc-macro2",
2212− "quote",
2213− "syn 1.0.109",
2214−]
2215−
2216−[[package]]
2217−name = "tempfile"
2218−version = "3.27.0"
2219−source = "registry+https://github.com/rust-lang/crates.io-index"
2220−checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
2221−dependencies = [
2222− "fastrand",
2223− "getrandom 0.4.2",
2224− "once_cell",
2225− "rustix",
2226− "windows-sys 0.61.2",
2227−]
2228−
2229−[[package]]
2230−name = "thiserror"
2231−version = "1.0.69"
2232−source = "registry+https://github.com/rust-lang/crates.io-index"
2233−checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
2234−dependencies = [
2235− "thiserror-impl 1.0.69",
2236−]
2237−
2238−[[package]]
2239−name = "thiserror"
2240−version = "2.0.18"
2241−source = "registry+https://github.com/rust-lang/crates.io-index"
2242−checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
2243−dependencies = [
2244− "thiserror-impl 2.0.18",
2245−]
2246−
2247−[[package]]
2248−name = "thiserror-impl"
2249−version = "1.0.69"
2250−source = "registry+https://github.com/rust-lang/crates.io-index"
2251−checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
2252−dependencies = [
2253− "proc-macro2",
2254− "quote",
2255− "syn 2.0.117",
2256−]
2257−
2258−[[package]]
2259−name = "thiserror-impl"
2260−version = "2.0.18"
2261−source = "registry+https://github.com/rust-lang/crates.io-index"
2262−checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
2263−dependencies = [
2264− "proc-macro2",
2265− "quote",
2266− "syn 2.0.117",
2267−]
2268−
2269−[[package]]
2270−name = "thread_local"
2271−version = "1.1.9"
2272−source = "registry+https://github.com/rust-lang/crates.io-index"
2273−checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
2274−dependencies = [
2275− "cfg-if",
2276−]
2277−
2278−[[package]]
2279−name = "tinystr"
2280−version = "0.8.3"
2281−source = "registry+https://github.com/rust-lang/crates.io-index"
2282−checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
2283−dependencies = [
2284− "displaydoc",
2285− "zerovec",
2286−]
2287−
2288−[[package]]
2289−name = "tinyvec"
2290−version = "1.11.0"
2291−source = "registry+https://github.com/rust-lang/crates.io-index"
2292−checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
2293−dependencies = [
2294− "tinyvec_macros",
2295−]
2296−
2297−[[package]]
2298−name = "tinyvec_macros"
2299−version = "0.1.1"
2300−source = "registry+https://github.com/rust-lang/crates.io-index"
2301−checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
2302−
2303−[[package]]
2304−name = "tokio"
2305−version = "1.52.3"
2306−source = "registry+https://github.com/rust-lang/crates.io-index"
2307−checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
2308−dependencies = [
2309− "bytes",
2310− "libc",
2311− "mio",
2312− "pin-project-lite",
2313− "signal-hook-registry",
2314− "socket2 0.6.3",
2315− "tokio-macros",
2316− "windows-sys 0.61.2",
2317−]
2318−
2319−[[package]]
2320−name = "tokio-macros"
2321−version = "2.7.0"
2322−source = "registry+https://github.com/rust-lang/crates.io-index"
2323−checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
2324−dependencies = [
2325− "proc-macro2",
2326− "quote",
2327− "syn 2.0.117",
2328−]
2329−
2330−[[package]]
2331−name = "tokio-native-tls"
2332−version = "0.3.1"
2333−source = "registry+https://github.com/rust-lang/crates.io-index"
2334−checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
2335−dependencies = [
2336− "native-tls",
2337− "tokio",
2338−]
2339−
2340−[[package]]
2341−name = "tokio-stream"
2342−version = "0.1.18"
2343−source = "registry+https://github.com/rust-lang/crates.io-index"
2344−checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70"
2345−dependencies = [
2346− "futures-core",
2347− "pin-project-lite",
2348− "tokio",
2349−]
2350−
2351−[[package]]
2352−name = "tokio-util"
2353−version = "0.7.18"
2354−source = "registry+https://github.com/rust-lang/crates.io-index"
2355−checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
2356−dependencies = [
2357− "bytes",
2358− "futures-core",
2359− "futures-sink",
2360− "pin-project-lite",
2361− "tokio",
2362−]
2363−
2364−[[package]]
2365−name = "tower-service"
2366−version = "0.3.3"
2367−source = "registry+https://github.com/rust-lang/crates.io-index"
2368−checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
2369−
2370−[[package]]
2371−name = "tracing"
2372−version = "0.1.44"
2373−source = "registry+https://github.com/rust-lang/crates.io-index"
2374−checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
2375−dependencies = [
2376− "log",
2377− "pin-project-lite",
2378− "tracing-attributes",
2379− "tracing-core",
2380−]
2381−
2382−[[package]]
2383−name = "tracing-attributes"
2384−version = "0.1.31"
2385−source = "registry+https://github.com/rust-lang/crates.io-index"
2386−checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
2387−dependencies = [
2388− "proc-macro2",
2389− "quote",
2390− "syn 2.0.117",
2391−]
2392−
2393−[[package]]
2394−name = "tracing-core"
2395−version = "0.1.36"
2396−source = "registry+https://github.com/rust-lang/crates.io-index"
2397−checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
2398−dependencies = [
2399− "once_cell",
2400− "valuable",
2401−]
2402−
2403−[[package]]
2404−name = "tracing-log"
2405−version = "0.2.0"
2406−source = "registry+https://github.com/rust-lang/crates.io-index"
2407−checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
2408−dependencies = [
2409− "log",
2410− "once_cell",
2411− "tracing-core",
2412−]
2413−
2414−[[package]]
2415−name = "tracing-subscriber"
2416−version = "0.3.23"
2417−source = "registry+https://github.com/rust-lang/crates.io-index"
2418−checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
2419−dependencies = [
2420− "matchers",
2421− "nu-ansi-term",
2422− "once_cell",
2423− "regex-automata",
2424− "sharded-slab",
2425− "smallvec",
2426− "thread_local",
2427− "tracing",
2428− "tracing-core",
2429− "tracing-log",
2430−]
2431−
2432−[[package]]
2433−name = "try-lock"
2434−version = "0.2.5"
2435−source = "registry+https://github.com/rust-lang/crates.io-index"
2436−checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
2437−
2438−[[package]]
2439−name = "typenum"
2440−version = "1.20.0"
2441−source = "registry+https://github.com/rust-lang/crates.io-index"
2442−checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
2443−
2444−[[package]]
2445−name = "unicase"
2446−version = "2.9.0"
2447−source = "registry+https://github.com/rust-lang/crates.io-index"
2448−checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
2449−
2450−[[package]]
2451−name = "unicode-bidi"
2452−version = "0.3.18"
2453−source = "registry+https://github.com/rust-lang/crates.io-index"
2454−checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
2455−
2456−[[package]]
2457−name = "unicode-ident"
2458−version = "1.0.24"
2459−source = "registry+https://github.com/rust-lang/crates.io-index"
2460−checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
2461−
2462−[[package]]
2463−name = "unicode-normalization"
2464−version = "0.1.25"
2465−source = "registry+https://github.com/rust-lang/crates.io-index"
2466−checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
2467−dependencies = [
2468− "tinyvec",
2469−]
2470−
2471−[[package]]
2472−name = "unicode-properties"
2473−version = "0.1.4"
2474−source = "registry+https://github.com/rust-lang/crates.io-index"
2475−checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
2476−
2477−[[package]]
2478−name = "unicode-xid"
2479−version = "0.2.6"
2480−source = "registry+https://github.com/rust-lang/crates.io-index"
2481−checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
2482−
2483−[[package]]
2484−name = "unsafe-libyaml"
2485−version = "0.2.11"
2486−source = "registry+https://github.com/rust-lang/crates.io-index"
2487−checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
2488−
2489−[[package]]
2490−name = "url"
2491−version = "2.5.8"
2492−source = "registry+https://github.com/rust-lang/crates.io-index"
2493−checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
2494−dependencies = [
2495− "form_urlencoded",
2496− "idna",
2497− "percent-encoding",
2498− "serde",
2499− "serde_derive",
2500−]
2501−
2502−[[package]]
2503−name = "utf8_iter"
2504−version = "1.0.4"
2505−source = "registry+https://github.com/rust-lang/crates.io-index"
2506−checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
2507−
2508−[[package]]
2509−name = "uuid"
2510−version = "1.23.1"
2511−source = "registry+https://github.com/rust-lang/crates.io-index"
2512−checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
2513−dependencies = [
2514− "getrandom 0.4.2",
2515− "js-sys",
2516− "wasm-bindgen",
2517−]
2518−
2519−[[package]]
2520−name = "valuable"
2521−version = "0.1.1"
2522−source = "registry+https://github.com/rust-lang/crates.io-index"
2523−checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
2524−
2525−[[package]]
2526−name = "vcpkg"
2527−version = "0.2.15"
2528−source = "registry+https://github.com/rust-lang/crates.io-index"
2529−checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
2530−
2531−[[package]]
2532−name = "version_check"
2533−version = "0.9.5"
2534−source = "registry+https://github.com/rust-lang/crates.io-index"
2535−checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
2536−
2537−[[package]]
2538−name = "want"
2539−version = "0.3.1"
2540−source = "registry+https://github.com/rust-lang/crates.io-index"
2541−checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
2542−dependencies = [
2543− "try-lock",
2544−]
2545−
2546−[[package]]
2547−name = "wasi"
2548−version = "0.11.1+wasi-snapshot-preview1"
2549−source = "registry+https://github.com/rust-lang/crates.io-index"
2550−checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
2551−
2552−[[package]]
2553−name = "wasip2"
2554−version = "1.0.3+wasi-0.2.9"
2555−source = "registry+https://github.com/rust-lang/crates.io-index"
2556−checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
2557−dependencies = [
2558− "wit-bindgen 0.57.1",
2559−]
2560−
2561−[[package]]
2562−name = "wasip3"
2563−version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
2564−source = "registry+https://github.com/rust-lang/crates.io-index"
2565−checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
2566−dependencies = [
2567− "wit-bindgen 0.51.0",
2568−]
2569−
2570−[[package]]
2571−name = "wasite"
2572−version = "0.1.0"
2573−source = "registry+https://github.com/rust-lang/crates.io-index"
2574−checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
2575−
2576−[[package]]
2577−name = "wasm-bindgen"
2578−version = "0.2.121"
2579−source = "registry+https://github.com/rust-lang/crates.io-index"
2580−checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
2581−dependencies = [
2582− "cfg-if",
2583− "once_cell",
2584− "rustversion",
2585− "wasm-bindgen-macro",
2586− "wasm-bindgen-shared",
2587−]
2588−
2589−[[package]]
2590−name = "wasm-bindgen-futures"
2591−version = "0.4.71"
2592−source = "registry+https://github.com/rust-lang/crates.io-index"
2593−checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8"
2594−dependencies = [
2595− "js-sys",
2596− "wasm-bindgen",
2597−]
2598−
2599−[[package]]
2600−name = "wasm-bindgen-macro"
2601−version = "0.2.121"
2602−source = "registry+https://github.com/rust-lang/crates.io-index"
2603−checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
2604−dependencies = [
2605− "quote",
2606− "wasm-bindgen-macro-support",
2607−]
2608−
2609−[[package]]
2610−name = "wasm-bindgen-macro-support"
2611−version = "0.2.121"
2612−source = "registry+https://github.com/rust-lang/crates.io-index"
2613−checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
2614−dependencies = [
2615− "bumpalo",
2616− "proc-macro2",
2617− "quote",
2618− "syn 2.0.117",
2619− "wasm-bindgen-shared",
2620−]
2621−
2622−[[package]]
2623−name = "wasm-bindgen-shared"
2624−version = "0.2.121"
2625−source = "registry+https://github.com/rust-lang/crates.io-index"
2626−checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
2627−dependencies = [
2628− "unicode-ident",
2629−]
2630−
2631−[[package]]
2632−name = "wasm-encoder"
2633−version = "0.244.0"
2634−source = "registry+https://github.com/rust-lang/crates.io-index"
2635−checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
2636−dependencies = [
2637− "leb128fmt",
2638− "wasmparser",
2639−]
2640−
2641−[[package]]
2642−name = "wasm-metadata"
2643−version = "0.244.0"
2644−source = "registry+https://github.com/rust-lang/crates.io-index"
2645−checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
2646−dependencies = [
2647− "anyhow",
2648− "indexmap",
2649− "wasm-encoder",
2650− "wasmparser",
2651−]
2652−
2653−[[package]]
2654−name = "wasm-streams"
2655−version = "0.4.2"
2656−source = "registry+https://github.com/rust-lang/crates.io-index"
2657−checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
2658−dependencies = [
2659− "futures-util",
2660− "js-sys",
2661− "wasm-bindgen",
2662− "wasm-bindgen-futures",
2663− "web-sys",
2664−]
2665−
2666−[[package]]
2667−name = "wasmparser"
2668−version = "0.244.0"
2669−source = "registry+https://github.com/rust-lang/crates.io-index"
2670−checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
2671−dependencies = [
2672− "bitflags 2.11.1",
2673− "hashbrown 0.15.5",
2674− "indexmap",
2675− "semver",
2676−]
2677−
2678−[[package]]
2679−name = "web-sys"
2680−version = "0.3.98"
2681−source = "registry+https://github.com/rust-lang/crates.io-index"
2682−checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
2683−dependencies = [
2684− "js-sys",
2685− "wasm-bindgen",
2686−]
2687−
2688−[[package]]
2689−name = "whoami"
2690−version = "1.6.1"
2691−source = "registry+https://github.com/rust-lang/crates.io-index"
2692−checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d"
2693−dependencies = [
2694− "libredox",
2695− "wasite",
2696−]
2697−
2698−[[package]]
2699−name = "windows-core"
2700−version = "0.62.2"
2701−source = "registry+https://github.com/rust-lang/crates.io-index"
2702−checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
2703−dependencies = [
2704− "windows-implement",
2705− "windows-interface",
2706− "windows-link",
2707− "windows-result",
2708− "windows-strings",
2709−]
2710−
2711−[[package]]
2712−name = "windows-implement"
2713−version = "0.60.2"
2714−source = "registry+https://github.com/rust-lang/crates.io-index"
2715−checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
2716−dependencies = [
2717− "proc-macro2",
2718− "quote",
2719− "syn 2.0.117",
2720−]
2721−
2722−[[package]]
2723−name = "windows-interface"
2724−version = "0.59.3"
2725−source = "registry+https://github.com/rust-lang/crates.io-index"
2726−checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
2727−dependencies = [
2728− "proc-macro2",
2729− "quote",
2730− "syn 2.0.117",
2731−]
2732−
2733−[[package]]
2734−name = "windows-link"
2735−version = "0.2.1"
2736−source = "registry+https://github.com/rust-lang/crates.io-index"
2737−checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
2738−
2739−[[package]]
2740−name = "windows-result"
2741−version = "0.4.1"
2742−source = "registry+https://github.com/rust-lang/crates.io-index"
2743−checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
2744−dependencies = [
2745− "windows-link",
2746−]
2747−
2748−[[package]]
2749−name = "windows-strings"
2750−version = "0.5.1"
2751−source = "registry+https://github.com/rust-lang/crates.io-index"
2752−checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
2753−dependencies = [
2754− "windows-link",
2755−]
2756−
2757−[[package]]
2758−name = "windows-sys"
2759−version = "0.48.0"
2760−source = "registry+https://github.com/rust-lang/crates.io-index"
2761−checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
2762−dependencies = [
2763− "windows-targets 0.48.5",
2764−]
2765−
2766−[[package]]
2767−name = "windows-sys"
2768−version = "0.52.0"
2769−source = "registry+https://github.com/rust-lang/crates.io-index"
2770−checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
2771−dependencies = [
2772− "windows-targets 0.52.6",
2773−]
2774−
2775−[[package]]
2776−name = "windows-sys"
2777−version = "0.61.2"
2778−source = "registry+https://github.com/rust-lang/crates.io-index"
2779−checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
2780−dependencies = [
2781− "windows-link",
2782−]
2783−
2784−[[package]]
2785−name = "windows-targets"
2786−version = "0.48.5"
2787−source = "registry+https://github.com/rust-lang/crates.io-index"
2788−checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
2789−dependencies = [
2790− "windows_aarch64_gnullvm 0.48.5",
2791− "windows_aarch64_msvc 0.48.5",
2792− "windows_i686_gnu 0.48.5",
2793− "windows_i686_msvc 0.48.5",
2794− "windows_x86_64_gnu 0.48.5",
2795− "windows_x86_64_gnullvm 0.48.5",
2796− "windows_x86_64_msvc 0.48.5",
2797−]
2798−
2799−[[package]]
2800−name = "windows-targets"
2801−version = "0.52.6"
2802−source = "registry+https://github.com/rust-lang/crates.io-index"
2803−checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
2804−dependencies = [
2805− "windows_aarch64_gnullvm 0.52.6",
2806− "windows_aarch64_msvc 0.52.6",
2807− "windows_i686_gnu 0.52.6",
2808− "windows_i686_gnullvm",
2809− "windows_i686_msvc 0.52.6",
2810− "windows_x86_64_gnu 0.52.6",
2811− "windows_x86_64_gnullvm 0.52.6",
2812− "windows_x86_64_msvc 0.52.6",
2813−]
2814−
2815−[[package]]
2816−name = "windows_aarch64_gnullvm"
2817−version = "0.48.5"
2818−source = "registry+https://github.com/rust-lang/crates.io-index"
2819−checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
2820−
2821−[[package]]
2822−name = "windows_aarch64_gnullvm"
2823−version = "0.52.6"
2824−source = "registry+https://github.com/rust-lang/crates.io-index"
2825−checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
2826−
2827−[[package]]
2828−name = "windows_aarch64_msvc"
2829−version = "0.48.5"
2830−source = "registry+https://github.com/rust-lang/crates.io-index"
2831−checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
2832−
2833−[[package]]
2834−name = "windows_aarch64_msvc"
2835−version = "0.52.6"
2836−source = "registry+https://github.com/rust-lang/crates.io-index"
2837−checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
2838−
2839−[[package]]
2840−name = "windows_i686_gnu"
2841−version = "0.48.5"
2842−source = "registry+https://github.com/rust-lang/crates.io-index"
2843−checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
2844−
2845−[[package]]
2846−name = "windows_i686_gnu"
2847−version = "0.52.6"
2848−source = "registry+https://github.com/rust-lang/crates.io-index"
2849−checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
2850−
2851−[[package]]
2852−name = "windows_i686_gnullvm"
2853−version = "0.52.6"
2854−source = "registry+https://github.com/rust-lang/crates.io-index"
2855−checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
2856−
2857−[[package]]
2858−name = "windows_i686_msvc"
2859−version = "0.48.5"
2860−source = "registry+https://github.com/rust-lang/crates.io-index"
2861−checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
2862−
2863−[[package]]
2864−name = "windows_i686_msvc"
2865−version = "0.52.6"
2866−source = "registry+https://github.com/rust-lang/crates.io-index"
2867−checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
2868−
2869−[[package]]
2870−name = "windows_x86_64_gnu"
2871−version = "0.48.5"
2872−source = "registry+https://github.com/rust-lang/crates.io-index"
2873−checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
2874−
2875−[[package]]
2876−name = "windows_x86_64_gnu"
2877−version = "0.52.6"
2878−source = "registry+https://github.com/rust-lang/crates.io-index"
2879−checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
2880−
2881−[[package]]
2882−name = "windows_x86_64_gnullvm"
2883−version = "0.48.5"
2884−source = "registry+https://github.com/rust-lang/crates.io-index"
2885−checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
2886−
2887−[[package]]
2888−name = "windows_x86_64_gnullvm"
2889−version = "0.52.6"
2890−source = "registry+https://github.com/rust-lang/crates.io-index"
2891−checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
2892−
2893−[[package]]
2894−name = "windows_x86_64_msvc"
2895−version = "0.48.5"
2896−source = "registry+https://github.com/rust-lang/crates.io-index"
2897−checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
2898−
2899−[[package]]
2900−name = "windows_x86_64_msvc"
2901−version = "0.52.6"
2902−source = "registry+https://github.com/rust-lang/crates.io-index"
2903−checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
2904−
2905−[[package]]
2906−name = "winreg"
2907−version = "0.50.0"
2908−source = "registry+https://github.com/rust-lang/crates.io-index"
2909−checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
2910−dependencies = [
2911− "cfg-if",
2912− "windows-sys 0.48.0",
2913−]
2914−
2915−[[package]]
2916−name = "wit-bindgen"
2917−version = "0.51.0"
2918−source = "registry+https://github.com/rust-lang/crates.io-index"
2919−checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
2920−dependencies = [
2921− "wit-bindgen-rust-macro",
2922−]
2923−
2924−[[package]]
2925−name = "wit-bindgen"
2926−version = "0.57.1"
2927−source = "registry+https://github.com/rust-lang/crates.io-index"
2928−checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
2929−
2930−[[package]]
2931−name = "wit-bindgen-core"
2932−version = "0.51.0"
2933−source = "registry+https://github.com/rust-lang/crates.io-index"
2934−checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
2935−dependencies = [
2936− "anyhow",
2937− "heck 0.5.0",
2938− "wit-parser",
2939−]
2940−
2941−[[package]]
2942−name = "wit-bindgen-rust"
2943−version = "0.51.0"
2944−source = "registry+https://github.com/rust-lang/crates.io-index"
2945−checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
2946−dependencies = [
2947− "anyhow",
2948− "heck 0.5.0",
2949− "indexmap",
2950− "prettyplease",
2951− "syn 2.0.117",
2952− "wasm-metadata",
2953− "wit-bindgen-core",
2954− "wit-component",
2955−]
2956−
2957−[[package]]
2958−name = "wit-bindgen-rust-macro"
2959−version = "0.51.0"
2960−source = "registry+https://github.com/rust-lang/crates.io-index"
2961−checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
2962−dependencies = [
2963− "anyhow",
2964− "prettyplease",
2965− "proc-macro2",
2966− "quote",
2967− "syn 2.0.117",
2968− "wit-bindgen-core",
2969− "wit-bindgen-rust",
2970−]
2971−
2972−[[package]]
2973−name = "wit-component"
2974−version = "0.244.0"
2975−source = "registry+https://github.com/rust-lang/crates.io-index"
2976−checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
2977−dependencies = [
2978− "anyhow",
2979− "bitflags 2.11.1",
2980− "indexmap",
2981− "log",
2982− "serde",
2983− "serde_derive",
2984− "serde_json",
2985− "wasm-encoder",
2986− "wasm-metadata",
2987− "wasmparser",
2988− "wit-parser",
2989−]
2990−
2991−[[package]]
2992−name = "wit-parser"
2993−version = "0.244.0"
2994−source = "registry+https://github.com/rust-lang/crates.io-index"
2995−checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
2996−dependencies = [
2997− "anyhow",
2998− "id-arena",
2999− "indexmap",
3000− "log",
3001− "semver",
3002− "serde",
3003− "serde_derive",
3004− "serde_json",
3005− "unicode-xid",
3006− "wasmparser",
3007−]
3008−
3009−[[package]]
3010−name = "writeable"
3011−version = "0.6.3"
3012−source = "registry+https://github.com/rust-lang/crates.io-index"
3013−checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
3014−
3015−[[package]]
3016−name = "yoke"
3017−version = "0.8.2"
3018−source = "registry+https://github.com/rust-lang/crates.io-index"
3019−checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
3020−dependencies = [
3021− "stable_deref_trait",
3022− "yoke-derive",
3023− "zerofrom",
3024−]
3025−
3026−[[package]]
3027−name = "yoke-derive"
3028−version = "0.8.2"
3029−source = "registry+https://github.com/rust-lang/crates.io-index"
3030−checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
3031−dependencies = [
3032− "proc-macro2",
3033− "quote",
3034− "syn 2.0.117",
3035− "synstructure",
3036−]
3037−
3038−[[package]]
3039−name = "zerocopy"
3040−version = "0.8.48"
3041−source = "registry+https://github.com/rust-lang/crates.io-index"
3042−checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
3043−dependencies = [
3044− "zerocopy-derive",
3045−]
3046−
3047−[[package]]
3048−name = "zerocopy-derive"
3049−version = "0.8.48"
3050−source = "registry+https://github.com/rust-lang/crates.io-index"
3051−checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
3052−dependencies = [
3053− "proc-macro2",
3054− "quote",
3055− "syn 2.0.117",
3056−]
3057−
3058−[[package]]
3059−name = "zerofrom"
3060−version = "0.1.8"
3061−source = "registry+https://github.com/rust-lang/crates.io-index"
3062−checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
3063−dependencies = [
3064− "zerofrom-derive",
3065−]
3066−
3067−[[package]]
3068−name = "zerofrom-derive"
3069−version = "0.1.7"
3070−source = "registry+https://github.com/rust-lang/crates.io-index"
3071−checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
3072−dependencies = [
3073− "proc-macro2",
3074− "quote",
3075− "syn 2.0.117",
3076− "synstructure",
3077−]
3078−
3079−[[package]]
3080−name = "zeroize"
3081−version = "1.8.2"
3082−source = "registry+https://github.com/rust-lang/crates.io-index"
3083−checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
3084−
3085−[[package]]
3086−name = "zerotrie"
3087−version = "0.2.4"
3088−source = "registry+https://github.com/rust-lang/crates.io-index"
3089−checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
3090−dependencies = [
3091− "displaydoc",
3092− "yoke",
3093− "zerofrom",
3094−]
3095−
3096−[[package]]
3097−name = "zerovec"
3098−version = "0.11.6"
3099−source = "registry+https://github.com/rust-lang/crates.io-index"
3100−checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
3101−dependencies = [
3102− "yoke",
3103− "zerofrom",
3104− "zerovec-derive",
3105−]
3106−
3107−[[package]]
3108−name = "zerovec-derive"
3109−version = "0.11.3"
3110−source = "registry+https://github.com/rust-lang/crates.io-index"
3111−checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
3112−dependencies = [
3113− "proc-macro2",
3114− "quote",
3115− "syn 2.0.117",
3116−]
3117−
3118−[[package]]
3119−name = "zmij"
3120−version = "1.0.21"
3121−source = "registry+https://github.com/rust-lang/crates.io-index"
3122−checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
Cargo.tomldeleted−20
@@ -1,20 +0,0 @@
1−[package]
2−name = "personality-traits-bot"
3−version = "0.1.0"
4−edition = "2021"
5−
6−[dependencies]
7−teloxide = { version = "0.13", features = ["macros", "ctrlc_handler"] }
8−tokio = { version = "1", features = ["rt-multi-thread", "macros", "signal", "time", "sync"] }
9−serde = { version = "1", features = ["derive"] }
10−serde_yaml = "0.9"
11−sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite", "chrono", "migrate"] }
12−chrono = { version = "0.4", features = ["serde"] }
13−dotenvy = "0.15"
14−tracing = "0.1"
15−tracing-subscriber = { version = "0.3", features = ["env-filter"] }
16−anyhow = "1"
17−thiserror = "1"
18−regex = "1"
19−once_cell = "1"
20−url = "2"
README.mddeleted−74
@@ -1,74 +0,0 @@
1−# personality-traits-bot
2−
3−Telegram-бот для практикума по снижению тревожности (Rust + teloxide + SQLite).
4−
5−## Что реализовано
6−
7−- Авторизация по email (одно сообщение с корректным email сохраняет пользователя).
8−- Кнопка «Начать курс» при первом запуске и «Начать курс заново» — после старта.
9−- Сценарий курса описан в `questionnaire/abfi-1/events.yaml`. Сообщения отправляются с задержкой `delay_minutes`, которая отсчитывается от нажатия кнопки в предыдущем сообщении.
10−- Сообщения вида `day_*` сопровождаются inline-кнопкой «Начать практику», `practice_*` — кнопкой «Завершить практику» (тексты берутся прямо из yaml).
11−- Все нажатия инлайн-кнопок логируются в таблицу `button_events` (telegram_id, message_id, button_id, event_target, время).
12−- Медиа из `questionnaire/abfi-1/data/`: `.png/.jpg/.jpeg` → `sendPhoto`, `.mp4` → `sendVideo`, `.mp3/.m4a` → `sendAudio`, `.ogg` → `sendVoice`, всё прочее (включая `.pdf` и `.webp`) → `sendDocument`. Отсутствующие файлы (например, `foo.mp4`) логируются как warning и пропускаются.
13−
14−## Команды
15−
16−- `/start` — зарегистрироваться (если ещё нет) или показать главное меню.
17−- `/restart` — завершить текущую сессию и начать курс заново.
18−- `/help` — список команд.
19−
20−## Запуск
21−
22−```sh
23−# 1. Скопируйте .env.example в .env и поставьте токен бота от @BotFather:
24−cp .env.example .env
25−# отредактируйте TELOXIDE_TOKEN
26−
27−# 2. Запустите бота:
28−cargo run --release
29−```
30−
31−При первом запуске:
32−- автоматически создаётся `bot.db` (SQLite);
33−- применяются миграции из `migrations/`;
34−- бот начинает long-polling Telegram.
35−
36−## Переменные окружения
37−
38−| Переменная | Значение по умолчанию (см. `.env.example`) |
39−|-------------------|----------------------------------------------------|
40−| `TELOXIDE_TOKEN` | токен бота от @BotFather |
41−| `DATABASE_URL` | `sqlite://bot.db?mode=rwc` |
42−| `EVENTS_FILE` | `questionnaire/abfi-1/events.yaml` |
43−| `DATA_DIR` | `questionnaire/abfi-1/data` |
44−| `RUST_LOG` | `info,personality_traits_bot=debug,teloxide=info` |
45−
46−## Структура хранения
47−
48−- `users` — `telegram_id`, `email`, `username`, `first_name`, `registered_at`.
49−- `course_sessions` — одна активная сессия на пользователя; `finished_at IS NULL` ⇒ курс идёт.
50−- `scheduled_messages` — очередь отложенной отправки (фоновый шедулер раз в 10 c забирает `send_after <= now`).
51−- `button_events` — журнал всех нажатий: `message_id`, `button_id`, `action`, `event_target`, `pressed_at`.
52−
53−## Поток выполнения
54−
55−1. Пользователь пишет `/start` → бот просит email.
56−2. После сохранения email бот отправляет первое сообщение из yaml (`id: start`) с кнопкой «Начать курс».
57−3. Нажатие кнопки → создаётся сессия, в `scheduled_messages` ставится следующее событие.
58−4. Шедулер каждые 10 секунд забирает «созревшие» сообщения, отправляет их, обновляет `current_index`.
59−5. Если у отправленного события нет кнопок (например, `day_1_end`), шедулер сразу планирует следующее по порядку с его `delay_minutes`.
60−6. Если кнопка ведёт на несуществующий `event` (например, опечатка `message_1` вместо `practice_1`), используется fallback — следующее сообщение по порядку.
61−
62−## Известные нюансы yaml
63−
64−- `event: message_1` в `day_1` — опечатка, по факту это `practice_1`. Обрабатывается fallback'ом.
65−- `id: day 4` (с пробелом) парсится, но не достижим по id. Обработчик переходит к нему через «next in order».
66−- `foo.mp4` в `start` отсутствует — будет warning в логах.
67−
68−## Отладка
69−
70−Поднять уровень логирования:
71−
72−```sh
73−RUST_LOG=debug cargo run
74−```
migrations/0001_init.sqldeleted−47
@@ -1,47 +0,0 @@
1−CREATE TABLE IF NOT EXISTS users (
2− telegram_id INTEGER PRIMARY KEY,
3− email TEXT NOT NULL,
4− username TEXT,
5− first_name TEXT,
6− registered_at TEXT NOT NULL
7−);
8−
9−CREATE TABLE IF NOT EXISTS course_sessions (
10− id INTEGER PRIMARY KEY AUTOINCREMENT,
11− telegram_id INTEGER NOT NULL,
12− started_at TEXT NOT NULL,
13− finished_at TEXT,
14− current_index INTEGER NOT NULL DEFAULT 0,
15− last_action_at TEXT NOT NULL,
16− FOREIGN KEY (telegram_id) REFERENCES users(telegram_id)
17−);
18−
19−CREATE INDEX IF NOT EXISTS idx_sessions_active
20− ON course_sessions(telegram_id) WHERE finished_at IS NULL;
21−
22−CREATE TABLE IF NOT EXISTS scheduled_messages (
23− id INTEGER PRIMARY KEY AUTOINCREMENT,
24− session_id INTEGER NOT NULL,
25− telegram_id INTEGER NOT NULL,
26− message_id TEXT NOT NULL,
27− send_after TEXT NOT NULL,
28− sent_at TEXT,
29− FOREIGN KEY (session_id) REFERENCES course_sessions(id)
30−);
31−
32−CREATE INDEX IF NOT EXISTS idx_pending_scheduled
33− ON scheduled_messages(send_after) WHERE sent_at IS NULL;
34−
35−CREATE TABLE IF NOT EXISTS button_events (
36− id INTEGER PRIMARY KEY AUTOINCREMENT,
37− telegram_id INTEGER NOT NULL,
38− session_id INTEGER,
39− message_id TEXT NOT NULL,
40− button_id TEXT NOT NULL,
41− action TEXT NOT NULL,
42− event_target TEXT,
43− pressed_at TEXT NOT NULL
44−);
45−
46−CREATE INDEX IF NOT EXISTS idx_button_events_user
47− ON button_events(telegram_id, pressed_at);
ac.md → questionnaire/abfi-1/ac.mdrenamed

The content is the same.

questionnaire/abfi-1/centralkeys.yaml+14−303
@@ -1,17 +1,17 @@
11messages:
22- id: start
33 text: |
4− Добро пожаловать на практикум по снижению тревожности! Практикум основан на доказательных техниках, проверенных большим количеством исследований и показавший свою эффективность в прошлых запусках. В этом практикуме вам будет предложено:
4+ Добро пожаловать на практикум по снижению тревожности! Практикум основан на доказательных техниках, проверенных большим количеством исследований. В этом практикуме вам будет предложено:
55 - две лекции
66 - 8 заданий с подробным описанием их научной эффективности
77 - текстовые и аудиоматериалы для выполнения заданий
88 - напоминания для закрепления освоенных навыков
9−
9+ По завершении практикума вы получите денежное вознаграждение.
1010 Просьба, пожалуйста, авторизоваться по почте и указывать эту же почту при прохождении анкет — так мы сможем идентифицировать вас. Обещаем строгую конфиденциальность!
11−
12− По всем вопросам вы можете обращаться к @vv_penner. Приятного вам путешествия в мир осознанности!
11+ По всем вопросам вы можете обращаться к @vv_penner. Приятного вам путешествия в мир осознанности
1312 file:
14− - 1.2.png
13+ -
14+ - foo.mp4
1515 buttons:
1616 - id: 1
1717 text: Начать курс
@@ -21,26 +21,22 @@ messages:
2121- id: day_1
2222 text: |
2323 Состояния тревоги, хронического стресса и эмоционального выгорания оказывают значительное негативное воздействие на психическое и физическое здоровье, нарушая нашу способность адекватной эмоциональной регуляции и снижая качество жизни. Эти состояния характеризуются активацией автономных когнитивных процессов, направленных на постоянное планирование, анализ и самоконтроль, что приводит к отстранению от настоящего момента и утрате переживания его положительных аспектов.
24−
2524 Научные исследования подтверждают, что хронический стресс является ключевым фактором, способствующим развитию синдрома эмоционального выгорания, который рассматривается как комплексное состояние физического, когнитивного и эмоционального истощения организма. Это истощение развивается под влиянием как внешних (например, неблагоприятные условия рабочей среды), так и внутренних (например, перфекционизм, особенности личности) факторов. Последствия выгорания не ограничиваются сферой психического здоровья; они включают повышение риска развития сердечно-сосудистых заболеваний и ускоренное биологическое старение организма.
26−
2725 В качестве эффективного научно обоснованного вмешательства для преодоления данных состояний рекомендуется практика осознанности (mindfulness). Она направлена на десинхронизацию автоматических когнитивных циклов и восстановление внимания к настоящему моменту. Регулярная практика помогает вернуть контроль над вниманием, улучшить эмоциональную регуляцию и восстановить способность переживать положительные эмоции.
28−
29− Сегодня мы предлагаем вам практику "Ешьте изюм осознанно"
3026 file:
31− - 2.2.png
27+ - 2.webp
3228 buttons:
3329 - id: 1
3430 text: Начать практику
3531 action: start_course
36− event: practice_1
32+ event: message_1
3733 delay_minutes: 0
3834- id: practice_1
3935 text: |
4036 Техника “Ешьте изюм осознанно”
4137 Вам понадобится несколько изюминок (или чего угодно!) для этой техники. Сядьте удобно там, где есть хорошее освещение и вас не будут беспокоить. Затем медленно настройте себя на прохождение практики
4238 file:
43− - Ешьте изюм осознанно.2.pdf
39+ - Ешьте изюм осознанно.pdf
4440 buttons:
4541 - id: 1
4642 text: Завершить практику
@@ -49,18 +45,14 @@ messages:
4945 delay_minutes: 0
5046- id: day_1_end
5147 text: |
52− Поздравляем вас с прохождением первой практики! Как вы оцениваете этот опыт? Что вы ощущали? Чем этот опыт отличается от обычного опыта употребления пищи?
48+ Поздравляем вас с прохождением первой практики! Как вы оцениваете этот опыт? Что вы ощущали? Чем этот опыт отличается от обычного опыта еды?
5349 Для закрепления навыка предлагаем вам проделывать это в течение нескольких ближайших дней. До встречи завтра!
5450 delay_minutes: 10
5551 - id: day_2
5652 text: |
57− Осознанность — это научно обоснованный подход к улучшению психического здоровья, основанный на внимании к настоящему моменту без оценки. Исследования показывают, что практики осознанности способствуют снижению тревожности и депрессии, улучшению эмоциональной регуляции и повышению устойчивости к стрессу.
58−
59− Научно доказано, что осознанность работает как через сложные нейрокогнитивные механизмы (усиление саморегуляции, переработку эмоций), так и через прямое воздействие на биологические маркеры стресса и настроения. Регулярная практика способствует повышению общего благополучия и качества жизни за счет освоения новых, более конструктивных навыков реагирования.
60−
61− Именно поэтому сегодня мы предлагаем вам расширить практику, о которой рассказывали вчера!
53+ Осознанность — это научно обоснованный подход к улучшению психического здоровья, основанный на внимании к настоящему моменту без оценки. Исследования показывают, что практики осознанности способствуют снижению тревожности и депрессии, улучшению эмоциональной регуляции и повышению устойчивости к стрессу. Научно доказано, что осознанность работает как через сложные нейрокогнитивные механизмы (усиление саморегуляции, переработку эмоций), так и через прямое воздействие на биологические маркеры стресса и настроения. Регулярная практика способствует повышению общего благополучия и качества жизни за счет освоения новых, более конструктивных навыков реагирования. Именно поэтому сегодня мы предлагаем вам повторить практику, о которой рассказывали вчера!
6254 file:
63− - 2.3.png
55+ - 4.png
6456 buttons:
6557 - id: 1
6658 text: Начать практику
@@ -69,9 +61,9 @@ messages:
6961 delay_minutes: 1140
7062- id: practice_2
7163 text: |
72− Выберите одно повседневное действие, которое выполняете каждый день, и решите, что на этой неделе, насколько сможете, привнесете в каждый его элемент частичку намеренной и мягкой осознанности, как вы это делали с изюмом. Лучше это делать с одним и тем же действием каждый день в течение всей недели.
64+ Выберите одно повседневное действие, которое выполняете каждый день, и решите, что на этой неделе, насколько сможете, привнесете в каждый его элемент свежее качество намеренной и мягкой осознанности, как вы это делали с изюмом. Лучше это делать с одним и тем же действием каждый день в течение всей недели.
7365 file:
74− - 2.4.png
66+ - 5.png
7567 buttons:
7668 - id: 1
7769 text: Завершить практику
@@ -80,286 +72,5 @@ messages:
8072 delay_minutes: 0
8173- id: day_2_end
8274 text: |
83− Как вы себя чувствуете после практики? Осознайте свои ощущения, проанализируйте их, закрепите этот опыт повторением практики. До встречи завтра!
75+ Как вы себя чувствуете после практики? Осознайте свои ощущения, проанализируйте их, закрепите этот опыт повторением практики. До встречи послезавтра!
8476 delay_minutes: 10
85−- id: day_3
86− text: |
87− Доброго вам дня!
88− Как вы себя чувствуете после наших первых практик?
89−
90− Предлагаем вам сегодня повторить любую из пройденных практик. Продолжаем развивать навык осознанности – у вас обязательно получится!
91− delay_minutes: 1140
92−- id: day_4
93− text: |
94− Доброго вам дня!
95− Работа на "автопилоте" часто сопровождается захватом сознания потоком мыслей — будь то планирование, воспоминания или мечты. Этот бесконечный цикл самокопания (руминации) является значимым фактором риска развития тревожных расстройств и депрессии.
96−
97− Ключевым механизмом, с помощью которого осознанность помогает выйти из этого состояния, является развитие децентрации (decentering). Это метакогнитивный процесс, при котором человек учится воспринимать свои мысли и эмоции не как абсолютную реальность, с которой необходимо идентифицироваться, а как временные психические события, проходящие через сознание.
98−
99− Вместо того чтобы сливаться с негативной мыслью (например, "Я неудачник"), практика осознанности учит замечать её: "Я замечаю, что у меня возникает мысль о неудаче". Это создает пространство между наблюдателем и мыслью, позволяя выйти из поглощающего потока руминации.
100−
101− Таким образом, осознанность не пытается подавить мысли силой воли, а меняет наше отношение к ним. Это позволяет прервать автоматические циклы, вернуться в настоящее и восстановить контакт с реальностью через прямое переживание — видение, слышание, ощущение.
102−
103− Сегодня мы предлагаем практику “Другой способ познания”
104− file:
105− - 2.5.png
106− buttons:
107− - id: 1
108− text: Начать практику
109− action: start_course
110− event: practice_2
111− delay_minutes: 1140
112−- id: practice_3
113− text: |
114− Функциональная МРТ и статистические исследования выявили, что практика осознанности приводит к:
115− – Снижению связи между медиальной префронтальной корой и миндалевидным телом, что уменьшает эмоциональную реактивность на триггеры.
116− – Усилению активности передней поясной коры, отвечающей за контроль внимания и поведения.
117−
118− Это нейропластическое изменение позволяет нам дистанцироваться от когнитивных содержаний. Вместо автоматической идентификации с мыслью («Я неудачник») формируется мета-когнитивная позиция («Я наблюдаю мысль о том, что я неудачник»).
119− Рандомизированные контролируемые испытания демонстрируют, что обучение навыку децентрации мыслей снижает частоту рецидивов депрессии на 43–50% по сравнению со стандартной терапией, особенно у пациентов с тремя и более предыдущими эпизодами.
120−
121− Успешной практики!
122− file:
123− - 2.6.png
124− buttons:
125− - id: 1
126− text: Завершить практику
127− action: start_course
128− event: day_4_end
129− delay_minutes: 0
130−- id: day_4_end
131− text: |
132− Поздравляем с прохождением третьей практики!
133−
134− Что вы заметили, когда подключались к ощущениям в своем теле? Что больше всего поразило вас в различии между двумя способами познания – думать о своем теле или поместить свое внимание внутрь телесных ощущений?
135−
136− До встречи завтра!
137− delay_minutes: 0
138−- id: day_5
139− text: |
140− Доброго дня!
141− Практики осознанности переключают мозг с режима «анализ и решение проблем» на режим «непосредственного опыта». Нейробиологически это означает снижение активности зон, отвечающих за постоянный мысленный шум и руминацию, и активацию областей, обрабатывающих прямые сенсорные ощущения. В результате «громкий» критический ум уступает место более тихому, интуитивному состоянию мета-осведомленности, позволяющему наблюдать за мыслями и чувствами без автоматической реакции.
142− Для закрепления этого навыка мы предлагаем вам упражнение «Встреча на улице».
143− Успешной практики!
144− file:
145− - 2.7.png
146− buttons:
147− - id: 1
148− text: Начать практику
149− action: start_course
150− event: practice_4
151− delay_minutes: 1140
152−- id: practice_4
153− text: |
154− Данная техника - практическая тренировка переключения внимания в реальной среде: при столкновении с внешними событиями или людьми вы сознательно останавливаете автоматический внутренний диалог и переводите фокус на непосредственные ощущения (звуки, свет, тактильные чувства). Такая практика укрепляет способность мозга быстро выходить из режима «думания» в режим «бытия», снижая эмоциональную реактивность и повышая устойчивость к стрессу.
155− file:
156− - 2.8.png
157− buttons:
158− - id: 1
159− text: Завершить практику
160− action: start_course
161− event: day_5_end
162− delay_minutes: 0
163−- id: day_5_end
164− text: |
165− Поздравляем с прохождением четвертой практики!
166−
167− Научная психология утверждает, что мысли не являются отражением объективной реальности, а представляют собой временные ментальные события, возникающие в сознании. Эмоциональные реакции человека определяются не самим событием, а интерпретацией, которую он этому событию придает. Например, одна и та же ситуация (друг не ответил на приветствие) может вызвать у человека в плохом настроении мысли "Я никому не нужен", ведущие к грусти, а у человека в хорошем настроении — нейтральную мысль "Возможно, он меня не увидел", не вызывающую негативных эмоций.
168− Этот процесс создает замкнутый круг: наше настроение влияет на интерпретацию событий, а последующие эмоции укрепляют исходное настроение.
169−
170− Практики осознанности помогает разорвать этот порочный круг. Они обучают децентрации — способности наблюдать за своими мыслями и чувствами как за проходящими событиями, а не идентифицировать себя с ними, тем самым помогая разорвать порочный круг.
171−
172− До встречи завтра!
173− delay_minutes: 0
174−- id: day_6
175− text: |
176− Доброго вам дня!
177− Как вы себя чувствуете после предложенных нами практик?
178−
179− Предлагаем вам сегодня повторить любую из пройденных практик. Продолжаем развивать навык осознанности – у вас обязательно получится!
180− delay_minutes: 1140
181−- id: day_7
182− text: |
183− Доброго дня!
184−
185− Научные исследования подтверждают, что блуждание ума в прошлое и будущее — это не метафора, а обозначение конкретного когнитивного процесса, известного как "ментальное путешествие во времени" (mental time travel). Этот процесс лежит в основе эпизодической памяти и планирования будущего.
186− Он активируется как при воспоминании прошлых событий, так и при построении симуляций будущего . Именно такая фоновая работа и приводит к тому, что мы "теряемся" в сожалениях или тревогах, уходя из настоящего момента.
187−
188− Практики осознанности действуют как противоположный механизм. Они направляет внимание на прямые сенсорные ощущения (дыхание, звуки, прикосновения), активируя сенсорные и проприоцептивные области мозга. Это позволяет вернуться к переживанию реальности "здесь и сейчас", где и происходит жизнь.
189−
190− Сегодня мы предлагаем вам трехминутную медитативную передышку.
191− file:
192− - 2.9.png
193− buttons:
194− - id: 1
195− text: Начать практику
196− action: start_course
197− event: practice_5
198− delay_minutes: 1140
199−- id: practice_5
200− text: |
201− «Трехминутная медитативная передышка» представляет собой краткосрочную интервенцию на основе осознанности, разработанную для оперативного переключения когнитивного режима с автоматического «режима выполнения» на адаптивный «режим бытия». С точки зрения нейробиологии, эта практика действует как «когнитивный переключатель», прерывая автоматические петли руминации и эмоциональной реактивности, которые поддерживаются гиперактивностью сети пассивного режима работы мозга и миндалевидного тела.
202− file:
203− - 2.10.png
204− buttons:
205− - id: 1
206− text: Завершить практику
207− action: start_course
208− event: day_7_end
209− delay_minutes: 0
210−- id: day_7_end
211− text: |
212− Поздравляем с прохождением пятой практики!
213− Что вы сделали после того, как заметили, что ваши мысли блуждают?
214−
215− Не ругайте себя за это. В случае обнаружения отклонения внимания от объекта медитации (феномен блуждания ума), критически важно исключить самокритику и негативную эмоциональную оценку данного события, так как подобные реакции активируют дополнительные стрессовые контуры и усиливают когнитивную нагрузку. Вместо этого следует применить стратегию мягкого, безоценочного возвращения фокуса внимания к исходному объекту концентрации. Именно это и представляет собой фундаментальный элемент тренировки мета-когнитивного контроля и нейропластичности.
216− До встречи завтра!
217− delay_minutes: 0
218−- id: day_8
219− text: |
220− Как ваше самочувствие сегодня?
221− Практика отслеживания негативных эмоций работает через механизм мета-когнитивной осведомленности. Исследования показывают, что вербализация и фиксация эмоций (т.н. «аффективная маркировка») снижают активность миндалевидного тела и помогают префронтальной коре лучше регулировать эмоциональный ответ.
222−
223− Сегодня мы предлагаем опробовать одну из таких практик – “Календарь неприятных переживаний”.
224− file:
225− - 2.11.png
226− buttons:
227− - id: 1
228− text: Начать практику
229− action: start_course
230− event: practice_6
231− delay_minutes: 1140
232−- id: practice_6
233− text: |
234− Хотите по-новому взглянуть на неприятные переживания?
235− Попробуйте разложить их на части: заметьте чувство, мысли, телесные ощущения — и отдельно от всего этого — свою реакцию на них. Осознанность учит видеть дискомфорт без оценки, как наблюдатель. Это даёт пространство: вы перестаете сливаться с эмоцией и учитесь встречать трудное не борясь, а присутствуя.
236− Хорошей вам практики!
237− file:
238− - 2.12.png
239− - СЮДА ДОК
240− buttons:
241− - id: 1
242− text: Завершить практику
243− action: start_course
244− event: day_8_end
245− delay_minutes: 0
246−- id: day_8_end
247− text: |
248− Как вы себя чувствуете после практики?
249− Исследования подтверждают, что негативные настроения поддерживаются двумя ключевыми когнитивными процессами:
250−
251− - Руминация — повторяющийся поток мыслей об анализе своего состояния; не решает проблему, а синергетически усиливает негативные эмоции и углубляет депрессивное состояние, искажая восприятие стресса.
252−
253− - Слияние — идентификация мыслей с реальностью; мысль «Я слаб» воспринимается не как ментальное событие, а как объективная истина, что автоматически усиливает страдание.
254−
255− Практики осознанности разрывают этот цикл: они снижают руминацию и развивают децентрирование — способность наблюдать за мыслями как за проходящими событиями, а не сливаться с ними.
256−
257− До встречи завтра!
258− delay_minutes: 0
259−- id: day_9
260− text: |
261− Доброго вам дня!
262− Как вы себя чувствуете после предложенных нами практик?
263−
264− Предлагаем вам сегодня повторить любую из пройденных практик. Исследования показывают, что поведенческая активация способствует закреплению новых навыков - продолжайте в том же духе!
265− delay_minutes: 1140
266−- id: day_10
267− text: |
268− Доброго дня! Сегодня мы хотели бы поговорить о таком феномене, как аверсия.
269−
270− В психологии "аверсия" к внутреннему опыту — это склонность испытывать сильное отторжение к негативным эмоциям, мыслям и телесным ощущениям, что приводит к попыткам их избежать, подавить или устранить. Этот механизм является ключевым в поддержании состояний тревоги, депрессии и других эмоциональных расстройств.
271−
272− Научные исследования показывают, что стратегии избегания, основанные на аверсии, являются малоадаптивными. Хотя они могут временно снизить уровень дистресса, в долгосрочной перспективе они только усугубляют страдания. Попытки избежать неприятных переживаний (например, переключение внимания, подавление, отвлечение) препятствуют привыканию — естественному процессу, при котором интенсивность эмоций снижается при их спокойном переживании.
273−
274− Таким образом, аверсия создает порочный круг: исходное неприятное чувство вызывает желание избавиться от него, а сама попытка избегания поддерживает и усиливает это чувство, не давая ему естественным образом пройти 13.
275−
276− Практики осознанности предлагают противоположный путь — экспозиционную стратегию, основанную на принятии и внимательном наблюдении за переживаниями без сопротивления.
277−
278− Сегодня мы предлагаем вам практику “Контрольный список негативных мыслей”
279− file:
280− - 2.13.png
281− - СЮДА ДОК
282− buttons:
283− - id: 1
284− text: Начать практику
285− action: start_course
286− event: practice_7
287− delay_minutes: 1140
288−- id: practice_7
289− text: |
290− Вместо того, чтобы избегать, мы попробуем направить внимание на дискомфорт с любопытством. Такой подход способствует когнитивной переработке и долгосрочному снижению страданий. Следовательно, главная цель практики — не избавиться от неприятных состояний, а изменить к ним свое отношение, став "экспертом" в механизмах своей аверсии.
291−
292− Желаем успехов!
293− file:
294− - СЮДА ДОК
295− buttons:
296− - id: 1
297− text: Завершить практику
298− action: start_course
299− event: day_10_end
300− delay_minutes: 0
301−- id: day_10_end
302− text: |
303− Как вы себя чувствуете после практики?
304−
305− Когда мы сможем относиться к негативным мыслям и депрессивным чувствам как к тому, чем они на самом деле являются, - симптомами, а не истиной, - нам не нужно будет воспринимать их как относящиеся к себе, и мы с меньшей вероятностью будем реагировать на них с аверсией.
306−
307− До встречи завтра!
308− delay_minutes: 0
309−- id: day_11
310− text: |
311− Доброго вам дня! Как вы сегодня? Хотим рассказать вам о том, что является альтернативой аверсии – о практику осознанного исследования неприятных переживаний.
312−
313− Практика осознанного исследования неприятных переживаний – это терапевтический подход, основанный на механизмах экспозиции и эмоциональной регуляции. В отличие от аверсии, этот метод предполагает внимательное наблюдение за неприятными ощущениями, эмоциями и мыслями в настоящем моменте без попытки их подавить. Такой процесс помогает выявить индивидуальные паттерны реакции на стресс — например, мышечное напряжение, учащенное дыхание или автоматические негативные мысли.
314−
315− Исследования показывают, что осознанное внимание к аверсивным переживаниям снижает избегание и повышает толерантность к дистрессу, что особенно важно при тревожных расстройствах. Нейробиологические данные также свидетельствуют о том, что mindfulness-практики изменяют механизмы эмоциональной регуляции: снижается активность миндалины, связанной со страхом и тревогой, и усиливается работа областей мозга, отвечающих за осознанное восприятие и контроль эмоций.
316−
317− Сегодня предлагаем вам практику, которая поможет развить осознанное отношение к своим переживаниям – медитация на осознанность дыхания, тела, звуков и безусловное осознание
318− file:
319− - 2.14.png
320− buttons:
321− - id: 1
322− text: Начать практику
323− action: start_course
324− event: practice_8
325− delay_minutes: 1140
326−- id: practice_8
327− text: |
328− Осознанное исследование не устраняет неприятные переживания, а меняет отношение к ним. Развитие метакогнитивной осознанности создает пространство между переживанием и реакцией, что способствует снижению эмоциональной реактивности и улучшению психологической адаптации
329− Желаем успехов!
330− file:
331− - СЮДА ДОК
332− buttons:
333− - id: 1
334− text: Завершить практику
335− action: start_course
336− event: day_11_end
337− delay_minutes: 0
338−- id: day_11_end
339− text: |
340− Как вам практика?
341−
342− Осознанное исследование не борется с аверсией, а трансформирует к ней отношение. Фиксация наблюдений и метка "Это аверсия" развивает метакогнитивную осознанность, создавая пространство для выбора более адаптивной реакции, что в конечном итоге приводит к снижению эмоциональной реактивности и улучшению психического здоровья.
343−
344− До встречи завтра!
345− delay_minutes: 0
346−- id: day_12
347− text: |
348− Доброго вам дня!
349− Как вы себя чувствуете после предложенных нами практик?
350−
351− Предлагаем вам сегодня повторить любую из пройденных практик. Вера в достижение цели - залог успеха!
352− delay_minutes: 1140
353−- id: day_13
354− text: |
355− Доброго вам дня!
356− СЮДА ССЫЛКУ НА ОПРОС Сегодня мы предлагаем пройти промежуточное тестирование - оно поможет вам отследить свой прогресс по завершении курса. Пожалуйста, авторизуйтесь по той же почтой, что была указана в данном боте.
357− buttons:
358− - id: 1
359− text: Завершить прохождение опроса,
360− action: start_course
361− event: day_13_end
362− delay_minutes: 1140
363−- id: day_13_end
364− text: |
365− Благодарим за прохождение опроса! До встречи завтра!
questionnaire/abfi-1/data/1.2.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.1.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.10.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.11.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.12.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.13.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.14.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.2.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.3.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.4.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.5.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.6.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.7.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.8.pngdeleted

Binary file not shown.

questionnaire/abfi-1/data/2.9.pngdeleted

Binary file not shown.

src/config.rsdeleted−25
@@ -1,25 +0,0 @@
1−use std::path::PathBuf;
2−
3−use anyhow::{Context, Result};
4−
5−#[derive(Debug, Clone)]
6−pub struct Config {
7− pub database_url: String,
8− pub events_file: PathBuf,
9− pub data_dir: PathBuf,
10−}
11−
12−impl Config {
13− pub fn from_env() -> Result<Self> {
14− Ok(Self {
15− database_url: std::env::var("DATABASE_URL")
16− .context("DATABASE_URL must be set (see .env.example)")?,
17− events_file: PathBuf::from(
18− std::env::var("EVENTS_FILE").context("EVENTS_FILE must be set")?,
19− ),
20− data_dir: PathBuf::from(
21− std::env::var("DATA_DIR").context("DATA_DIR must be set")?,
22− ),
23− })
24− }
25−}
src/db.rsdeleted−239
@@ -1,239 +0,0 @@
1−use std::str::FromStr;
2−
3−use anyhow::{Context, Result};
4−use chrono::{DateTime, Utc};
5−use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
6−use sqlx::SqlitePool;
7−
8−pub type Pool = SqlitePool;
9−
10−pub async fn connect(url: &str) -> Result<Pool> {
11− let opts = SqliteConnectOptions::from_str(url)?.create_if_missing(true);
12− let pool = SqlitePoolOptions::new()
13− .max_connections(5)
14− .connect_with(opts)
15− .await?;
16− sqlx::migrate!("./migrations")
17− .run(&pool)
18− .await
19− .context("run migrations")?;
20− Ok(pool)
21−}
22−
23−#[derive(Debug)]
24−#[allow(dead_code)]
25−pub struct User {
26− pub telegram_id: i64,
27− pub email: String,
28−}
29−
30−pub async fn get_user(pool: &Pool, tg_id: i64) -> Result<Option<User>> {
31− let row: Option<(i64, String)> =
32− sqlx::query_as("SELECT telegram_id, email FROM users WHERE telegram_id = ?")
33− .bind(tg_id)
34− .fetch_optional(pool)
35− .await?;
36− Ok(row.map(|(telegram_id, email)| User { telegram_id, email }))
37−}
38−
39−pub async fn upsert_user(
40− pool: &Pool,
41− tg_id: i64,
42− email: &str,
43− username: Option<&str>,
44− first_name: Option<&str>,
45−) -> Result<()> {
46− sqlx::query(
47− "INSERT INTO users (telegram_id, email, username, first_name, registered_at) \
48− VALUES (?, ?, ?, ?, ?) \
49− ON CONFLICT(telegram_id) DO UPDATE SET \
50− email = excluded.email, \
51− username = excluded.username, \
52− first_name = excluded.first_name",
53− )
54− .bind(tg_id)
55− .bind(email)
56− .bind(username)
57− .bind(first_name)
58− .bind(Utc::now().to_rfc3339())
59− .execute(pool)
60− .await?;
61− Ok(())
62−}
63−
64−#[derive(Debug, Clone)]
65−#[allow(dead_code)]
66−pub struct Session {
67− pub id: i64,
68− pub telegram_id: i64,
69− pub current_index: i64,
70−}
71−
72−pub async fn active_session(pool: &Pool, tg_id: i64) -> Result<Option<Session>> {
73− let row: Option<(i64, i64, i64)> = sqlx::query_as(
74− "SELECT id, telegram_id, current_index FROM course_sessions \
75− WHERE telegram_id = ? AND finished_at IS NULL \
76− ORDER BY id DESC LIMIT 1",
77− )
78− .bind(tg_id)
79− .fetch_optional(pool)
80− .await?;
81− Ok(row.map(|(id, telegram_id, current_index)| Session {
82− id,
83− telegram_id,
84− current_index,
85− }))
86−}
87−
88−pub async fn start_session(pool: &Pool, tg_id: i64) -> Result<Session> {
89− let now = Utc::now().to_rfc3339();
90− let id = sqlx::query(
91− "INSERT INTO course_sessions (telegram_id, started_at, current_index, last_action_at) \
92− VALUES (?, ?, ?, ?)",
93− )
94− .bind(tg_id)
95− .bind(&now)
96− .bind(0_i64)
97− .bind(&now)
98− .execute(pool)
99− .await?
100− .last_insert_rowid();
101− Ok(Session {
102− id,
103− telegram_id: tg_id,
104− current_index: 0,
105− })
106−}
107−
108−pub async fn finish_all_active(pool: &Pool, tg_id: i64) -> Result<()> {
109− let now = Utc::now().to_rfc3339();
110− sqlx::query(
111− "UPDATE scheduled_messages SET sent_at = ? \
112− WHERE sent_at IS NULL AND session_id IN \
113− (SELECT id FROM course_sessions WHERE telegram_id = ? AND finished_at IS NULL)",
114− )
115− .bind(&now)
116− .bind(tg_id)
117− .execute(pool)
118− .await?;
119− sqlx::query(
120− "UPDATE course_sessions SET finished_at = ? \
121− WHERE telegram_id = ? AND finished_at IS NULL",
122− )
123− .bind(&now)
124− .bind(tg_id)
125− .execute(pool)
126− .await?;
127− Ok(())
128−}
129−
130−pub async fn finish_session(pool: &Pool, session_id: i64) -> Result<()> {
131− let now = Utc::now().to_rfc3339();
132− sqlx::query("UPDATE scheduled_messages SET sent_at = ? WHERE session_id = ? AND sent_at IS NULL")
133− .bind(&now)
134− .bind(session_id)
135− .execute(pool)
136− .await?;
137− sqlx::query("UPDATE course_sessions SET finished_at = ? WHERE id = ?")
138− .bind(&now)
139− .bind(session_id)
140− .execute(pool)
141− .await?;
142− Ok(())
143−}
144−
145−pub async fn update_session_index(pool: &Pool, session_id: i64, index: i64) -> Result<()> {
146− sqlx::query("UPDATE course_sessions SET current_index = ?, last_action_at = ? WHERE id = ?")
147− .bind(index)
148− .bind(Utc::now().to_rfc3339())
149− .bind(session_id)
150− .execute(pool)
151− .await?;
152− Ok(())
153−}
154−
155−pub async fn record_button(
156− pool: &Pool,
157− tg_id: i64,
158− session_id: Option<i64>,
159− message_id: &str,
160− button_id: &str,
161− action: &str,
162− event_target: Option<&str>,
163−) -> Result<()> {
164− sqlx::query(
165− "INSERT INTO button_events \
166− (telegram_id, session_id, message_id, button_id, action, event_target, pressed_at) \
167− VALUES (?, ?, ?, ?, ?, ?, ?)",
168− )
169− .bind(tg_id)
170− .bind(session_id)
171− .bind(message_id)
172− .bind(button_id)
173− .bind(action)
174− .bind(event_target)
175− .bind(Utc::now().to_rfc3339())
176− .execute(pool)
177− .await?;
178− Ok(())
179−}
180−
181−pub async fn schedule(
182− pool: &Pool,
183− session_id: i64,
184− tg_id: i64,
185− message_id: &str,
186− send_after: DateTime<Utc>,
187−) -> Result<i64> {
188− let id = sqlx::query(
189− "INSERT INTO scheduled_messages (session_id, telegram_id, message_id, send_after) \
190− VALUES (?, ?, ?, ?)",
191− )
192− .bind(session_id)
193− .bind(tg_id)
194− .bind(message_id)
195− .bind(send_after.to_rfc3339())
196− .execute(pool)
197− .await?
198− .last_insert_rowid();
199− Ok(id)
200−}
201−
202−#[derive(Debug)]
203−pub struct ScheduledMessage {
204− pub id: i64,
205− pub session_id: i64,
206− pub telegram_id: i64,
207− pub message_id: String,
208−}
209−
210−pub async fn due_messages(pool: &Pool, now: DateTime<Utc>) -> Result<Vec<ScheduledMessage>> {
211− let rows: Vec<(i64, i64, i64, String)> = sqlx::query_as(
212− "SELECT id, session_id, telegram_id, message_id FROM scheduled_messages \
213− WHERE sent_at IS NULL AND send_after <= ? \
214− ORDER BY send_after ASC LIMIT 50",
215− )
216− .bind(now.to_rfc3339())
217− .fetch_all(pool)
218− .await?;
219− Ok(rows
220− .into_iter()
221− .map(
222− |(id, session_id, telegram_id, message_id)| ScheduledMessage {
223− id,
224− session_id,
225− telegram_id,
226− message_id,
227− },
228− )
229− .collect())
230−}
231−
232−pub async fn mark_sent(pool: &Pool, id: i64) -> Result<()> {
233− sqlx::query("UPDATE scheduled_messages SET sent_at = ? WHERE id = ?")
234− .bind(Utc::now().to_rfc3339())
235− .bind(id)
236− .execute(pool)
237− .await?;
238− Ok(())
239−}
src/events.rsdeleted−161
@@ -1,161 +0,0 @@
1−use std::collections::HashMap;
2−use std::path::{Path, PathBuf};
3−
4−use anyhow::{Context, Result};
5−use serde::Deserialize;
6−
7−#[derive(Debug, Deserialize)]
8−struct RawFile {
9− messages: Vec<RawEvent>,
10−}
11−
12−#[derive(Debug, Deserialize)]
13−struct RawEvent {
14− id: String,
15− #[serde(default)]
16− text: String,
17− #[serde(default)]
18− file: Vec<Option<String>>,
19− #[serde(default)]
20− buttons: Vec<RawButton>,
21− #[serde(default)]
22− delay_minutes: i64,
23−}
24−
25−#[derive(Debug, Deserialize)]
26−struct RawButton {
27− #[serde(default)]
28− id: serde_yaml::Value,
29− text: String,
30− #[serde(default)]
31− action: String,
32− #[serde(default)]
33− event: String,
34−}
35−
36−#[derive(Debug, Clone)]
37−pub struct Event {
38− pub id: String,
39− pub text: String,
40− pub files: Vec<String>,
41− pub buttons: Vec<Button>,
42− pub delay_minutes: i64,
43−}
44−
45−#[derive(Debug, Clone)]
46−pub struct Button {
47− pub id: String,
48− pub text: String,
49− pub action: String,
50− pub event: String,
51−}
52−
53−#[derive(Debug)]
54−pub struct Course {
55− pub events: Vec<Event>,
56− by_id: HashMap<String, usize>,
57− data_dir: PathBuf,
58−}
59−
60−impl Course {
61− pub fn load(yaml_path: &Path, data_dir: &Path) -> Result<Self> {
62− let content = std::fs::read_to_string(yaml_path)
63− .with_context(|| format!("read {}", yaml_path.display()))?;
64− let raw: RawFile = serde_yaml::from_str(&content)
65− .with_context(|| format!("parse {}", yaml_path.display()))?;
66−
67− let mut events = Vec::with_capacity(raw.messages.len());
68− let mut by_id = HashMap::new();
69− for (idx, e) in raw.messages.into_iter().enumerate() {
70− let id = e.id.trim().to_string();
71− let files: Vec<String> = e
72− .file
73− .into_iter()
74− .flatten()
75− .map(|f| f.trim().to_string())
76− .filter(|f| !f.is_empty())
77− .collect();
78− let buttons: Vec<Button> = e
79− .buttons
80− .into_iter()
81− .enumerate()
82− .map(|(i, b)| Button {
83− id: button_id_to_string(&b.id, i),
84− text: b.text,
85− action: b.action,
86− event: b.event.trim().to_string(),
87− })
88− .collect();
89−
90− if by_id.insert(id.clone(), idx).is_some() {
91− tracing::warn!("duplicate event id in yaml: {}", id);
92− }
93− events.push(Event {
94− id,
95− text: e.text,
96− files,
97− buttons,
98− delay_minutes: e.delay_minutes,
99− });
100− }
101− Ok(Self {
102− events,
103− by_id,
104− data_dir: data_dir.to_path_buf(),
105− })
106− }
107−
108− pub fn first(&self) -> Option<&Event> {
109− self.events.first()
110− }
111−
112− pub fn at(&self, idx: usize) -> Option<&Event> {
113− self.events.get(idx)
114− }
115−
116− pub fn index_of(&self, id: &str) -> Option<usize> {
117− self.by_id.get(id.trim()).copied()
118− }
119−
120− pub fn next_after_button(&self, current_idx: usize, button_event: &str) -> Option<usize> {
121− let target = button_event.trim();
122− if !target.is_empty() {
123− if let Some(&idx) = self.by_id.get(target) {
124− return Some(idx);
125− }
126− tracing::warn!(
127− "button.event '{}' not found in yaml, falling back to next in order",
128− target
129− );
130− }
131− self.next_in_order(current_idx)
132− }
133−
134− pub fn next_in_order(&self, current_idx: usize) -> Option<usize> {
135− let next = current_idx + 1;
136− if next < self.events.len() {
137− Some(next)
138− } else {
139− None
140− }
141− }
142−
143− pub fn resolve_file(&self, name: &str) -> Option<PathBuf> {
144− let p = self.data_dir.join(name);
145− if p.exists() {
146− Some(p)
147− } else {
148− tracing::warn!("attached file not found: {}", p.display());
149− None
150− }
151− }
152−}
153−
154−fn button_id_to_string(v: &serde_yaml::Value, fallback: usize) -> String {
155− match v {
156− serde_yaml::Value::String(s) => s.clone(),
157− serde_yaml::Value::Number(n) => n.to_string(),
158− serde_yaml::Value::Bool(b) => b.to_string(),
159− _ => fallback.to_string(),
160− }
161−}
src/handlers.rsdeleted−390
@@ -1,390 +0,0 @@
1−use std::sync::Arc;
2−
3−use anyhow::Result;
4−use chrono::Utc;
5−use once_cell::sync::Lazy;
6−use regex::Regex;
7−use teloxide::prelude::*;
8−use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup, MaybeInaccessibleMessage};
9−
10−use crate::db::{self, Pool};
11−use crate::events::Course;
12−use crate::media;
13−
14−static EMAIL_RE: Lazy<Regex> = Lazy::new(|| {
15− Regex::new(r"(?i)^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$").unwrap()
16−});
17−
18−pub async fn on_message(
19− bot: Bot,
20− msg: Message,
21− pool: Pool,
22− course: Arc<Course>,
23−) -> Result<(), teloxide::RequestError> {
24− if let Err(e) = on_message_inner(&bot, &msg, &pool, &course).await {
25− tracing::error!("message handler error: {:?}", e);
26− if let Some(user) = msg.from.as_ref() {
27− let _ = bot
28− .send_message(
29− ChatId(user.id.0 as i64),
30− "Что-то пошло не так. Попробуйте /start.",
31− )
32− .await;
33− }
34− }
35− Ok(())
36−}
37−
38−async fn on_message_inner(bot: &Bot, msg: &Message, pool: &Pool, course: &Course) -> Result<()> {
39− let Some(user) = msg.from.as_ref() else {
40− return Ok(());
41− };
42− let tg_id = user.id.0 as i64;
43− let chat = msg.chat.id;
44− let text = msg.text().unwrap_or("").trim();
45− let username = user.username.as_deref();
46− let first_name = Some(user.first_name.as_str());
47−
48− match text {
49− "/start" => handle_start(bot, chat, tg_id, pool, course).await,
50− "/restart" => handle_restart(bot, chat, tg_id, pool, course).await,
51− "/help" => {
52− bot.send_message(
53− chat,
54− "Команды:\n\
55− /start — начать или продолжить курс\n\
56− /restart — начать курс заново",
57− )
58− .await?;
59− Ok(())
60− }
61− _ => {
62− if db::get_user(pool, tg_id).await?.is_none() {
63− handle_email_input(bot, chat, tg_id, username, first_name, text, pool, course).await
64− } else {
65− bot.send_message(
66− chat,
67− "Пожалуйста, используйте кнопки. Команды: /start, /restart, /help.",
68− )
69− .await?;
70− Ok(())
71− }
72− }
73− }
74−}
75−
76−async fn handle_email_input(
77− bot: &Bot,
78− chat: ChatId,
79− tg_id: i64,
80− username: Option<&str>,
81− first_name: Option<&str>,
82− text: &str,
83− pool: &Pool,
84− course: &Course,
85−) -> Result<()> {
86− if EMAIL_RE.is_match(text) {
87− db::upsert_user(pool, tg_id, text, username, first_name).await?;
88− bot.send_message(
89− chat,
90− format!(
91− "Email сохранён: {}\n\
92− Пожалуйста, указывайте этот же email при заполнении анкет.",
93− text
94− ),
95− )
96− .await?;
97− send_intro(bot, chat, course, false).await?;
98− } else {
99− bot.send_message(
100− chat,
101− "Похоже, это не email. Пожалуйста, отправьте корректный email одним сообщением \
102− (например, name@example.com).",
103− )
104− .await?;
105− }
106− Ok(())
107−}
108−
109−async fn handle_start(
110− bot: &Bot,
111− chat: ChatId,
112− tg_id: i64,
113− pool: &Pool,
114− course: &Course,
115−) -> Result<()> {
116− if db::get_user(pool, tg_id).await?.is_none() {
117− bot.send_message(
118− chat,
119− "Здравствуйте! Чтобы зарегистрироваться, пожалуйста, отправьте ваш email \
120− одним сообщением. Этот же email нужно будет указывать при заполнении анкет.",
121− )
122− .await?;
123− return Ok(());
124− }
125− let has_session = db::active_session(pool, tg_id).await?.is_some();
126− send_intro(bot, chat, course, has_session).await?;
127− Ok(())
128−}
129−
130−async fn handle_restart(
131− bot: &Bot,
132− chat: ChatId,
133− tg_id: i64,
134− pool: &Pool,
135− course: &Course,
136−) -> Result<()> {
137− if db::get_user(pool, tg_id).await?.is_none() {
138− return handle_start(bot, chat, tg_id, pool, course).await;
139− }
140− send_intro(bot, chat, course, true).await?;
141− Ok(())
142−}
143−
144−async fn send_intro(bot: &Bot, chat: ChatId, course: &Course, restart_mode: bool) -> Result<()> {
145− let Some(intro) = course.first() else {
146− bot.send_message(chat, "Курс пуст. Свяжитесь с администратором.")
147− .await?;
148− return Ok(());
149− };
150−
151− let files: Vec<_> = intro
152− .files
153− .iter()
154− .filter_map(|f| course.resolve_file(f))
155− .collect();
156−
157− let (button_text, callback_data) = if restart_mode {
158− ("Начать курс заново".to_string(), "crs:restart".to_string())
159− } else {
160− let label = intro
161− .buttons
162− .first()
163− .map(|b| b.text.clone())
164− .unwrap_or_else(|| "Начать курс".to_string());
165− (label, "crs:start".to_string())
166− };
167−
168− let kb = InlineKeyboardMarkup::new(vec![vec![InlineKeyboardButton::callback(
169− button_text,
170− callback_data,
171− )]]);
172−
173− let text = if intro.text.trim().is_empty() {
174− "Добро пожаловать!"
175− } else {
176− intro.text.as_str()
177− };
178− media::send_event_message(bot, chat, &files, text, Some(kb)).await;
179− Ok(())
180−}
181−
182−pub async fn on_callback(
183− bot: Bot,
184− q: CallbackQuery,
185− pool: Pool,
186− course: Arc<Course>,
187−) -> Result<(), teloxide::RequestError> {
188− if let Err(e) = on_callback_inner(&bot, &q, &pool, &course).await {
189− tracing::error!("callback handler error: {:?}", e);
190− }
191− let _ = bot.answer_callback_query(q.id.clone()).await;
192− Ok(())
193−}
194−
195−async fn on_callback_inner(
196− bot: &Bot,
197− q: &CallbackQuery,
198− pool: &Pool,
199− course: &Course,
200−) -> Result<()> {
201− let tg_id = q.from.id.0 as i64;
202− let chat = ChatId(tg_id);
203− let data = q.data.clone().unwrap_or_default();
204−
205− if let Some(msg) = q.message.as_ref() {
206− let (cid, mid) = match msg {
207− MaybeInaccessibleMessage::Regular(m) => (m.chat.id, m.id),
208− MaybeInaccessibleMessage::Inaccessible(im) => (im.chat.id, im.message_id),
209− };
210− let _ = bot.edit_message_reply_markup(cid, mid).await;
211− }
212−
213− match data.as_str() {
214− "crs:start" => handle_course_start(bot, chat, tg_id, pool, course, false).await,
215− "crs:restart" => handle_course_start(bot, chat, tg_id, pool, course, true).await,
216− d if d.starts_with("btn:") => handle_event_button(bot, chat, tg_id, pool, course, d).await,
217− _ => {
218− tracing::warn!("unknown callback data: {}", data);
219− Ok(())
220− }
221− }
222−}
223−
224−async fn handle_course_start(
225− bot: &Bot,
226− chat: ChatId,
227− tg_id: i64,
228− pool: &Pool,
229− course: &Course,
230− restart: bool,
231−) -> Result<()> {
232− if db::get_user(pool, tg_id).await?.is_none() {
233− bot.send_message(chat, "Пожалуйста, сначала отправьте ваш email одним сообщением.")
234− .await?;
235− return Ok(());
236− }
237−
238− db::finish_all_active(pool, tg_id).await?;
239− let session = db::start_session(pool, tg_id).await?;
240−
241− let intro = course
242− .first()
243− .ok_or_else(|| anyhow::anyhow!("course has no events"))?;
244− let button = intro.buttons.first();
245− let target = button.map(|b| b.event.as_str()).unwrap_or("");
246−
247− db::record_button(
248− pool,
249− tg_id,
250− Some(session.id),
251− &intro.id,
252− button.map(|b| b.id.as_str()).unwrap_or("0"),
253− if restart { "restart_course" } else { "start_course" },
254− if target.is_empty() { None } else { Some(target) },
255− )
256− .await?;
257−
258− if let Some(next_idx) = course.next_after_button(0, target) {
259− schedule_next(pool, &session, course, next_idx, Utc::now()).await?;
260− if restart {
261− bot.send_message(chat, "Курс начат заново. Скоро вы получите первое сообщение.")
262− .await?;
263− } else {
264− bot.send_message(chat, "Курс начат. Скоро вы получите первое сообщение.")
265− .await?;
266− }
267− } else {
268− db::finish_session(pool, session.id).await?;
269− bot.send_message(chat, "В курсе нет следующих сообщений после стартового.")
270− .await?;
271− }
272− Ok(())
273−}
274−
275−async fn handle_event_button(
276− bot: &Bot,
277− chat: ChatId,
278− tg_id: i64,
279− pool: &Pool,
280− course: &Course,
281− data: &str,
282−) -> Result<()> {
283− let parts: Vec<&str> = data.splitn(3, ':').collect();
284− if parts.len() != 3 {
285− return Ok(());
286− }
287− let event_idx: usize = parts[1].parse().unwrap_or(usize::MAX);
288− let btn_idx: usize = parts[2].parse().unwrap_or(usize::MAX);
289−
290− let Some(session) = db::active_session(pool, tg_id).await? else {
291− bot.send_message(chat, "Нет активного курса. Нажмите /start, чтобы начать.")
292− .await?;
293− return Ok(());
294− };
295−
296− let Some(event) = course.at(event_idx) else {
297− tracing::warn!("callback references unknown event idx {}", event_idx);
298− return Ok(());
299− };
300− let Some(button) = event.buttons.get(btn_idx) else {
301− tracing::warn!(
302− "callback references unknown button idx {} on event {}",
303− btn_idx,
304− event.id
305− );
306− return Ok(());
307− };
308−
309− let target = button.event.as_str();
310− db::record_button(
311− pool,
312− tg_id,
313− Some(session.id),
314− &event.id,
315− &button.id,
316− &button.action,
317− if target.is_empty() { None } else { Some(target) },
318− )
319− .await?;
320−
321− let Some(next_idx) = course.next_after_button(event_idx, target) else {
322− db::finish_session(pool, session.id).await?;
323− bot.send_message(chat, "Поздравляем, вы прошли весь практикум!")
324− .await?;
325− return Ok(());
326− };
327−
328− schedule_next(pool, &session, course, next_idx, Utc::now()).await?;
329− Ok(())
330−}
331−
332−async fn schedule_next(
333− pool: &Pool,
334− session: &db::Session,
335− course: &Course,
336− next_idx: usize,
337− trigger_at: chrono::DateTime<Utc>,
338−) -> Result<()> {
339− let next = course
340− .at(next_idx)
341− .ok_or_else(|| anyhow::anyhow!("invalid next_idx {}", next_idx))?;
342− let send_after = trigger_at + chrono::Duration::minutes(next.delay_minutes.max(0));
343− db::schedule(pool, session.id, session.telegram_id, &next.id, send_after).await?;
344− tracing::info!(
345− "scheduled '{}' (idx {}) for user {} at {} (delay {} min)",
346− next.id,
347− next_idx,
348− session.telegram_id,
349− send_after,
350− next.delay_minutes
351− );
352− Ok(())
353−}
354−
355−pub async fn send_event_with_keyboard(
356− bot: &Bot,
357− chat: ChatId,
358− course: &Course,
359− event_idx: usize,
360−) -> Result<()> {
361− let event = course
362− .at(event_idx)
363− .ok_or_else(|| anyhow::anyhow!("event idx {} not found", event_idx))?;
364−
365− let files: Vec<_> = event
366− .files
367− .iter()
368− .filter_map(|f| course.resolve_file(f))
369− .collect();
370−
371− let rows: Vec<Vec<InlineKeyboardButton>> = event
372− .buttons
373− .iter()
374− .enumerate()
375− .map(|(i, b)| {
376− vec![InlineKeyboardButton::callback(
377− b.text.clone(),
378− format!("btn:{}:{}", event_idx, i),
379− )]
380− })
381− .collect();
382−
383− let keyboard = if rows.is_empty() {
384− None
385− } else {
386− Some(InlineKeyboardMarkup::new(rows))
387− };
388− media::send_event_message(bot, chat, &files, &event.text, keyboard).await;
389− Ok(())
390−}
src/main.rsdeleted−52
@@ -1,52 +0,0 @@
1−mod config;
2−mod db;
3−mod events;
4−mod handlers;
5−mod media;
6−mod scheduler;
7−
8−use std::sync::Arc;
9−
10−use teloxide::prelude::*;
11−use tracing_subscriber::EnvFilter;
12−
13−#[tokio::main]
14−async fn main() -> anyhow::Result<()> {
15− let _ = dotenvy::dotenv();
16− tracing_subscriber::fmt()
17− .with_env_filter(
18− EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
19− )
20− .init();
21−
22− let cfg = config::Config::from_env()?;
23− tracing::info!("loading events from {}", cfg.events_file.display());
24− let course = Arc::new(events::Course::load(&cfg.events_file, &cfg.data_dir)?);
25− tracing::info!("loaded {} events", course.events.len());
26−
27− let pool = db::connect(&cfg.database_url).await?;
28− tracing::info!("database ready at {}", cfg.database_url);
29−
30− let bot = Bot::from_env();
31−
32− let sched_bot = bot.clone();
33− let sched_pool = pool.clone();
34− let sched_course = course.clone();
35− tokio::spawn(async move {
36− scheduler::run(sched_bot, sched_pool, sched_course).await;
37− });
38−
39− let handler = dptree::entry()
40− .branch(Update::filter_message().endpoint(handlers::on_message))
41− .branch(Update::filter_callback_query().endpoint(handlers::on_callback));
42−
43− Dispatcher::builder(bot, handler)
44− .dependencies(dptree::deps![pool, course])
45− .default_handler(|_| async {})
46− .enable_ctrlc_handler()
47− .build()
48− .dispatch()
49− .await;
50−
51− Ok(())
52−}
src/media.rsdeleted−157
@@ -1,157 +0,0 @@
1−use std::path::{Path, PathBuf};
2−
3−use teloxide::prelude::*;
4−use teloxide::types::{InlineKeyboardMarkup, InputFile};
5−
6−const CAPTION_LIMIT: usize = 1024;
7−
8−pub async fn send_event_message(
9− bot: &Bot,
10− chat: ChatId,
11− files: &[PathBuf],
12− text: &str,
13− keyboard: Option<InlineKeyboardMarkup>,
14−) {
15− if files.is_empty() {
16− send_text(bot, chat, text, keyboard).await;
17− return;
18− }
19−
20− let fits_in_caption = text.chars().count() <= CAPTION_LIMIT;
21− if files.len() == 1 && fits_in_caption {
22− match send_one_with_caption(bot, chat, &files[0], text, keyboard.clone()).await {
23− Ok(()) => return,
24− Err(e) => tracing::warn!(
25− "failed to send {} with caption: {}; falling back to separate messages",
26− files[0].display(),
27− e
28− ),
29− }
30− }
31−
32− for path in files {
33− send_one(bot, chat, path).await;
34− }
35− send_text(bot, chat, text, keyboard).await;
36−}
37−
38−async fn send_text(bot: &Bot, chat: ChatId, text: &str, keyboard: Option<InlineKeyboardMarkup>) {
39− let text = if text.trim().is_empty() {
40− "(пустое сообщение)"
41− } else {
42− text
43− };
44− let result = match keyboard {
45− Some(kb) => bot.send_message(chat, text).reply_markup(kb).await.map(|_| ()),
46− None => bot.send_message(chat, text).await.map(|_| ()),
47− };
48− if let Err(e) = result {
49− tracing::error!("failed to send text to {}: {}", chat, e);
50− }
51−}
52−
53−async fn send_one_with_caption(
54− bot: &Bot,
55− chat: ChatId,
56− path: &Path,
57− caption: &str,
58− keyboard: Option<InlineKeyboardMarkup>,
59−) -> Result<(), teloxide::RequestError> {
60− let ext = path
61− .extension()
62− .and_then(|e| e.to_str())
63− .unwrap_or("")
64− .to_ascii_lowercase();
65−
66− match ext.as_str() {
67− "jpg" | "jpeg" | "png" | "webp" => {
68− let req = bot
69− .send_photo(chat, InputFile::file(path))
70− .caption(caption);
71− match keyboard {
72− Some(kb) => req.reply_markup(kb).await?,
73− None => req.await?,
74− };
75− }
76− "mp4" => {
77− let req = bot
78− .send_video(chat, InputFile::file(path))
79− .caption(caption);
80− match keyboard {
81− Some(kb) => req.reply_markup(kb).await?,
82− None => req.await?,
83− };
84− }
85− "mp3" | "m4a" => {
86− let req = bot
87− .send_audio(chat, InputFile::file(path))
88− .caption(caption);
89− match keyboard {
90− Some(kb) => req.reply_markup(kb).await?,
91− None => req.await?,
92− };
93− }
94− "ogg" => {
95− let req = bot
96− .send_voice(chat, InputFile::file(path))
97− .caption(caption);
98− match keyboard {
99− Some(kb) => req.reply_markup(kb).await?,
100− None => req.await?,
101− };
102− }
103− _ => {
104− let req = bot
105− .send_document(chat, InputFile::file(path))
106− .caption(caption);
107− match keyboard {
108− Some(kb) => req.reply_markup(kb).await?,
109− None => req.await?,
110− };
111− }
112− }
113− Ok(())
114−}
115−
116−async fn send_one(bot: &Bot, chat: ChatId, path: &Path) {
117− let ext = path
118− .extension()
119− .and_then(|e| e.to_str())
120− .unwrap_or("")
121− .to_ascii_lowercase();
122−
123− let result = match ext.as_str() {
124− "jpg" | "jpeg" | "png" | "webp" => bot
125− .send_photo(chat, InputFile::file(path))
126− .await
127− .map(|_| ()),
128− "mp4" => bot
129− .send_video(chat, InputFile::file(path))
130− .await
131− .map(|_| ()),
132− "mp3" | "m4a" => bot
133− .send_audio(chat, InputFile::file(path))
134− .await
135− .map(|_| ()),
136− "ogg" => bot
137− .send_voice(chat, InputFile::file(path))
138− .await
139− .map(|_| ()),
140− _ => bot
141− .send_document(chat, InputFile::file(path))
142− .await
143− .map(|_| ()),
144− };
145−
146− if let Err(e) = result {
147− tracing::warn!(
148− "failed to send {} as {}: {}; retrying as document",
149− path.display(),
150− ext,
151− e
152− );
153− if let Err(e2) = bot.send_document(chat, InputFile::file(path)).await {
154− tracing::error!("failed to send {} as document: {}", path.display(), e2);
155− }
156− }
157−}
src/scheduler.rsdeleted−85
@@ -1,85 +0,0 @@
1−use std::sync::Arc;
2−use std::time::Duration;
3−
4−use anyhow::Result;
5−use chrono::Utc;
6−use teloxide::prelude::*;
7−use tokio::time::sleep;
8−
9−use crate::db::{self, Pool};
10−use crate::events::Course;
11−use crate::handlers;
12−
13−const TICK_INTERVAL: Duration = Duration::from_secs(10);
14−
15−pub async fn run(bot: Bot, pool: Pool, course: Arc<Course>) {
16− tracing::info!("scheduler started, tick every {:?}", TICK_INTERVAL);
17− loop {
18− if let Err(e) = tick(&bot, &pool, &course).await {
19− tracing::error!("scheduler tick error: {:?}", e);
20− }
21− sleep(TICK_INTERVAL).await;
22− }
23−}
24−
25−async fn tick(bot: &Bot, pool: &Pool, course: &Course) -> Result<()> {
26− let due = db::due_messages(pool, Utc::now()).await?;
27− for sm in due {
28− if let Err(e) = deliver(bot, pool, course, &sm).await {
29− tracing::error!(
30− "failed to deliver message id={} user={}: {:?}",
31− sm.id,
32− sm.telegram_id,
33− e
34− );
35− }
36− }
37− Ok(())
38−}
39−
40−async fn deliver(
41− bot: &Bot,
42− pool: &Pool,
43− course: &Course,
44− sm: &db::ScheduledMessage,
45−) -> Result<()> {
46− let Some(idx) = course.index_of(&sm.message_id) else {
47− tracing::warn!(
48− "scheduled message id '{}' not found in current yaml; skipping",
49− sm.message_id
50− );
51− db::mark_sent(pool, sm.id).await?;
52− return Ok(());
53− };
54−
55− let chat = ChatId(sm.telegram_id);
56− handlers::send_event_with_keyboard(bot, chat, course, idx).await?;
57− db::mark_sent(pool, sm.id).await?;
58− db::update_session_index(pool, sm.session_id, idx as i64).await?;
59−
60− let event = course.at(idx).expect("idx valid: just looked it up");
61− if event.buttons.is_empty() {
62− match course.next_in_order(idx) {
63− Some(next_idx) => {
64− let next = course.at(next_idx).expect("idx valid");
65− let send_after = Utc::now() + chrono::Duration::minutes(next.delay_minutes.max(0));
66− db::schedule(pool, sm.session_id, sm.telegram_id, &next.id, send_after).await?;
67− tracing::info!(
68− "auto-scheduled '{}' (idx {}) for user {} at {} (delay {} min)",
69− next.id,
70− next_idx,
71− sm.telegram_id,
72− send_after,
73− next.delay_minutes
74− );
75− }
76− None => {
77− db::finish_session(pool, sm.session_id).await?;
78− let _ = bot
79− .send_message(chat, "Поздравляем, вы прошли весь практикум!")
80− .await;
81− }
82− }
83− }
84− Ok(())
85−}
tests/parse_events.rsdeleted−33
@@ -1,33 +0,0 @@
1−use std::path::PathBuf;
2−
3−#[path = "../src/events.rs"]
4−mod events;
5−
6−#[test]
7−fn loads_real_yaml() {
8− let yaml = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
9− .join("questionnaire/abfi-1/events.yaml");
10− let data = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
11− .join("questionnaire/abfi-1/data");
12− let course = events::Course::load(&yaml, &data).expect("yaml must parse");
13− assert!(!course.events.is_empty(), "course must have events");
14−
15− let start = course.first().expect("has first event");
16− assert_eq!(start.id, "start");
17− assert!(
18− !start.buttons.is_empty(),
19− "start event must have a button to begin"
20− );
21−
22− let day1 = course.index_of("day_1").expect("day_1 present");
23− assert!(day1 > 0);
24−
25− let practice1 = course.index_of("practice_1").expect("practice_1 present");
26− let after_day1 = course
27− .next_after_button(day1, "message_1")
28− .expect("fallback should resolve next-in-order even for typo");
29− assert_eq!(
30− after_day1, practice1,
31− "typo 'message_1' must fall back to next-in-order = practice_1"
32− );
33−}