Added support for multiple languages
This commit is contained in:
parent
aded63f9d5
commit
c5855fced7
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "MySQL",
|
|
||||||
"query": "INSERT INTO master_pass VALUES (?, ?, ?)",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 3
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "1fc824ca1ca447a990c3e68ee4f2a15b8e5bc260641057d914bb7ff871b51aa3"
|
|
||||||
}
|
|
12
.sqlx/query-71661faf7bde5ba94a5090dde7fb3ee72e9b2860692e30333f2213188188fdb6.json
generated
Normal file
12
.sqlx/query-71661faf7bde5ba94a5090dde7fb3ee72e9b2860692e30333f2213188188fdb6.json
generated
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "MySQL",
|
||||||
|
"query": "UPDATE master_pass SET locale = ? WHERE user_id = ?",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 2
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "71661faf7bde5ba94a5090dde7fb3ee72e9b2860692e30333f2213188188fdb6"
|
||||||
|
}
|
12
.sqlx/query-ff36e44aa2d064634d3ad183ce503cd30555d1d745cf5ab486c0d17e8e9a026f.json
generated
Normal file
12
.sqlx/query-ff36e44aa2d064634d3ad183ce503cd30555d1d745cf5ab486c0d17e8e9a026f.json
generated
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "MySQL",
|
||||||
|
"query": "INSERT INTO master_pass VALUES (?, ?, ?, ?)",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 4
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "ff36e44aa2d064634d3ad183ce503cd30555d1d745cf5ab486c0d17e8e9a026f"
|
||||||
|
}
|
304
Cargo.lock
generated
304
Cargo.lock
generated
@ -42,24 +42,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.2"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "allocator-api2"
|
name = "allocator-api2"
|
||||||
version = "0.2.16"
|
version = "0.2.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.80"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aquamarine"
|
name = "aquamarine"
|
||||||
@ -89,27 +89,17 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "atomic-write-file"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a8204db279bf648d64fe845bd8840f78b39c8132ed4d6a4194c3b10d4b4cfb0b"
|
|
||||||
dependencies = [
|
|
||||||
"nix",
|
|
||||||
"rand",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.69"
|
version = "0.3.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
"addr2line",
|
||||||
"cc",
|
"cc",
|
||||||
@ -146,9 +136,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.4.2"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@ -164,9 +154,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.15.3"
|
version = "3.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b"
|
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
@ -176,15 +166,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.5.0"
|
version = "1.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.90"
|
version = "1.0.94"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
|
checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@ -192,12 +182,6 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg_aliases"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chacha20"
|
name = "chacha20"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
@ -224,9 +208,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.35"
|
version = "0.4.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
|
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
@ -281,9 +265,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc"
|
name = "crc"
|
||||||
version = "3.0.1"
|
version = "3.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
|
checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc-catalog",
|
"crc-catalog",
|
||||||
]
|
]
|
||||||
@ -325,7 +309,7 @@ name = "cryptography"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.5.0",
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
"entity",
|
"entity",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@ -375,9 +359,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "der"
|
name = "der"
|
||||||
version = "0.7.8"
|
version = "0.7.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
|
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-oid",
|
"const-oid",
|
||||||
"pem-rfc7468",
|
"pem-rfc7468",
|
||||||
@ -426,18 +410,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.10.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.33"
|
version = "0.8.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
|
checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
@ -509,9 +493,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.0.1"
|
version = "2.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "finl_unicode"
|
name = "finl_unicode"
|
||||||
@ -612,7 +596,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.52",
|
"syn 2.0.59",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -657,9 +641,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.12"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
@ -674,9 +658,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.24"
|
version = "0.3.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
|
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
@ -854,9 +838,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.5"
|
version = "2.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@ -908,9 +892,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.10"
|
version = "1.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
@ -987,9 +971,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.1"
|
version = "2.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime"
|
name = "mime"
|
||||||
@ -1039,18 +1023,6 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91"
|
checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nix"
|
|
||||||
version = "0.28.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.4.2",
|
|
||||||
"cfg-if",
|
|
||||||
"cfg_aliases",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.3"
|
version = "7.1.3"
|
||||||
@ -1180,6 +1152,7 @@ dependencies = [
|
|||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
"sha2",
|
"sha2",
|
||||||
"teloxide",
|
"teloxide",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -1246,14 +1219,14 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.52",
|
"syn 2.0.59",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.13"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-utils"
|
name = "pin-utils"
|
||||||
@ -1341,18 +1314,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.78"
|
version = "1.0.80"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.35"
|
version = "1.0.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@ -1407,9 +1380,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.10.3"
|
version = "1.10.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -1430,15 +1403,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.24"
|
version = "0.11.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
|
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -1530,11 +1503,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.31"
|
version = "0.38.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
|
checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.5.0",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
@ -1638,14 +1611,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.52",
|
"syn 2.0.59",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.114"
|
version = "1.0.116"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
|
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@ -1676,6 +1649,19 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_yaml"
|
||||||
|
version = "0.9.34+deprecated"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"unsafe-libyaml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.10.6"
|
version = "0.10.6"
|
||||||
@ -1728,9 +1714,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.13.1"
|
version = "1.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
@ -1780,9 +1766,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx"
|
name = "sqlx"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf"
|
checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"sqlx-macros",
|
"sqlx-macros",
|
||||||
@ -1793,9 +1779,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-core"
|
name = "sqlx-core"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
|
checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"atoi",
|
"atoi",
|
||||||
@ -1803,7 +1789,6 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"crc",
|
"crc",
|
||||||
"crossbeam-queue",
|
"crossbeam-queue",
|
||||||
"dotenvy",
|
|
||||||
"either",
|
"either",
|
||||||
"event-listener",
|
"event-listener",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
@ -1836,9 +1821,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-macros"
|
name = "sqlx-macros"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5"
|
checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1849,11 +1834,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-macros-core"
|
name = "sqlx-macros-core"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841"
|
checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-write-file",
|
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"either",
|
"either",
|
||||||
"heck",
|
"heck",
|
||||||
@ -1874,13 +1858,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-mysql"
|
name = "sqlx-mysql"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
|
checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.5.0",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"crc",
|
"crc",
|
||||||
@ -1916,13 +1900,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-postgres"
|
name = "sqlx-postgres"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
|
checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.5.0",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"crc",
|
"crc",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
@ -1943,7 +1927,6 @@ dependencies = [
|
|||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha1",
|
|
||||||
"sha2",
|
"sha2",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
@ -1955,9 +1938,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-sqlite"
|
name = "sqlx-sqlite"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490"
|
checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"flume",
|
"flume",
|
||||||
@ -2011,9 +1994,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.52"
|
version = "2.0.59"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2152,22 +2135,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.57"
|
version = "1.0.58"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
|
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.57"
|
version = "1.0.58"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.52",
|
"syn 2.0.59",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2187,9 +2170,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.36.0"
|
version = "1.37.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
|
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -2211,7 +2194,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.52",
|
"syn 2.0.59",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2226,9 +2209,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-stream"
|
name = "tokio-stream"
|
||||||
version = "0.1.14"
|
version = "0.1.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
|
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@ -2275,7 +2258,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.52",
|
"syn 2.0.59",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2357,6 +2340,12 @@ dependencies = [
|
|||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsafe-libyaml"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@ -2383,9 +2372,9 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.7.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
|
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
@ -2450,7 +2439,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.52",
|
"syn 2.0.59",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2484,7 +2473,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.52",
|
"syn 2.0.59",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@ -2526,9 +2515,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "whoami"
|
name = "whoami"
|
||||||
version = "1.5.0"
|
version = "1.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fec781d48b41f8163426ed18e8fc2864c12937df9ce54c88ede7bd47270893e"
|
checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"wasite",
|
"wasite",
|
||||||
@ -2580,7 +2569,7 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.52.4",
|
"windows-targets 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2600,17 +2589,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.4"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm 0.52.4",
|
"windows_aarch64_gnullvm 0.52.5",
|
||||||
"windows_aarch64_msvc 0.52.4",
|
"windows_aarch64_msvc 0.52.5",
|
||||||
"windows_i686_gnu 0.52.4",
|
"windows_i686_gnu 0.52.5",
|
||||||
"windows_i686_msvc 0.52.4",
|
"windows_i686_gnullvm",
|
||||||
"windows_x86_64_gnu 0.52.4",
|
"windows_i686_msvc 0.52.5",
|
||||||
"windows_x86_64_gnullvm 0.52.4",
|
"windows_x86_64_gnu 0.52.5",
|
||||||
"windows_x86_64_msvc 0.52.4",
|
"windows_x86_64_gnullvm 0.52.5",
|
||||||
|
"windows_x86_64_msvc 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2621,9 +2611,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.4"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
@ -2633,9 +2623,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.4"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
@ -2645,9 +2635,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.4"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
@ -2657,9 +2653,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.4"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
@ -2669,9 +2665,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.4"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
@ -2681,9 +2677,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.4"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
@ -2693,9 +2689,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.4"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
@ -2724,7 +2720,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.52",
|
"syn 2.0.59",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -36,6 +36,7 @@ parking_lot = "0.12"
|
|||||||
pretty_env_logger = "0.5"
|
pretty_env_logger = "0.5"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
serde_yaml = "0.9"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
teloxide = { version = "0.12", features = [
|
teloxide = { version = "0.12", features = [
|
||||||
"macros",
|
"macros",
|
||||||
|
3
entity/migrations/0002_locales.down.sql
Normal file
3
entity/migrations/0002_locales.down.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- Add down migration script here
|
||||||
|
ALTER TABLE master_pass
|
||||||
|
DROP COLUMN locale;
|
3
entity/migrations/0002_locales.up.sql
Normal file
3
entity/migrations/0002_locales.up.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- Add up migration script here
|
||||||
|
ALTER TABLE master_pass
|
||||||
|
ADD COLUMN locale SMALLINT UNSIGNED NOT NULL DEFAULT 1;
|
@ -2,6 +2,7 @@
|
|||||||
#![allow(clippy::missing_errors_doc)]
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
|
||||||
pub mod account;
|
pub mod account;
|
||||||
|
pub mod locale;
|
||||||
pub mod master_pass;
|
pub mod master_pass;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
|
||||||
|
50
entity/src/locale.rs
Normal file
50
entity/src/locale.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use sqlx::{mysql::MySqlQueryResult as QueryResult, query, query_as};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
#[allow(clippy::module_name_repetitions)]
|
||||||
|
pub enum LocaleType {
|
||||||
|
#[default]
|
||||||
|
Eng = 1,
|
||||||
|
Ru = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for LocaleType {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
1 => Ok(Self::Eng),
|
||||||
|
2 => Ok(Self::Ru),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LocaleType> for u8 {
|
||||||
|
fn from(value: LocaleType) -> Self {
|
||||||
|
value as Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocaleType {
|
||||||
|
pub async fn get_from_db(user_id: u64, db: &Pool) -> crate::Result<Option<Self>> {
|
||||||
|
let result: Option<(u8,)> = query_as("SELECT locale FROM master_pass WHERE user_id = ?")
|
||||||
|
.bind(user_id)
|
||||||
|
.fetch_optional(db)
|
||||||
|
.await?;
|
||||||
|
Ok(result.and_then(|val| val.0.try_into().ok()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update(self, user_id: u64, db: &Pool) -> crate::Result<bool> {
|
||||||
|
let result: QueryResult = query!(
|
||||||
|
"UPDATE master_pass SET locale = ? WHERE user_id = ?",
|
||||||
|
u8::from(self),
|
||||||
|
user_id
|
||||||
|
)
|
||||||
|
.execute(db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(result.rows_affected() == 1)
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use super::Pool;
|
use crate::{locale::LocaleType, Pool};
|
||||||
use sqlx::{prelude::FromRow, query, query_as, Executor, MySql};
|
use sqlx::{prelude::FromRow, query, query_as, Executor, MySql};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, FromRow, Eq)]
|
#[derive(Clone, Debug, PartialEq, FromRow, Eq)]
|
||||||
@ -11,12 +11,14 @@ pub struct MasterPass {
|
|||||||
impl MasterPass {
|
impl MasterPass {
|
||||||
// Inserts the master password into DB
|
// Inserts the master password into DB
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn insert(&self, pool: &Pool) -> crate::Result<()> {
|
pub async fn insert(&self, pool: &Pool, locale: LocaleType) -> crate::Result<()> {
|
||||||
|
let locale: u8 = locale.into();
|
||||||
query!(
|
query!(
|
||||||
"INSERT INTO master_pass VALUES (?, ?, ?)",
|
"INSERT INTO master_pass VALUES (?, ?, ?, ?)",
|
||||||
self.user_id,
|
self.user_id,
|
||||||
self.salt,
|
self.salt,
|
||||||
self.password_hash
|
self.password_hash,
|
||||||
|
locale
|
||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await
|
.await
|
||||||
@ -26,7 +28,7 @@ impl MasterPass {
|
|||||||
/// Gets the master password from the database
|
/// Gets the master password from the database
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn get(user_id: u64, pool: &Pool) -> crate::Result<Option<Self>> {
|
pub async fn get(user_id: u64, pool: &Pool) -> crate::Result<Option<Self>> {
|
||||||
query_as("SELECT * FROM master_pass WHERE user_id = ?")
|
query_as("SELECT user_id, salt, password_hash FROM master_pass WHERE user_id = ?")
|
||||||
.bind(user_id)
|
.bind(user_id)
|
||||||
.fetch_optional(pool)
|
.fetch_optional(pool)
|
||||||
.await
|
.await
|
||||||
|
83
locales/eng.yaml
Normal file
83
locales/eng.yaml
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
master_password_is_not_set: "Master password is not set. Use /cancel to cancel the current action and /set_master_pass to set it"
|
||||||
|
hide_button: "Hide"
|
||||||
|
change_name_button: "Change name"
|
||||||
|
change_login_button: "Change login"
|
||||||
|
change_password_button: "Change password"
|
||||||
|
delete_account_button: "Delete account"
|
||||||
|
couldnt_get_user_info_send_again: "Couldn't get user information. Send the message again"
|
||||||
|
unknown_command_use_help: "Unknown command. Use /help to get info on existing commands"
|
||||||
|
help_command: |
|
||||||
|
These commands are supported:
|
||||||
|
|
||||||
|
/start — displays the welcome message
|
||||||
|
/help — displays this text
|
||||||
|
/set_master_pass — sets the master password
|
||||||
|
/menu — gives you a menu to manage your accounts
|
||||||
|
/add_account — adds the account
|
||||||
|
/get_account — gets the account
|
||||||
|
/get_accounts — gets a list of accounts
|
||||||
|
/delete — deletes the account
|
||||||
|
/delete_all — deletes all the accounts and the master password
|
||||||
|
/export — exports all the accounts in a json file
|
||||||
|
/import — loads the accounts from a json file
|
||||||
|
/gen_password — generates 10 secure passwords
|
||||||
|
/cancel — cancels the current action
|
||||||
|
/change_language - allows you to change the language
|
||||||
|
no_file_send: "Expected you to send a file"
|
||||||
|
file_too_large: "File is larger that 200 MiB. Please split it into multiple files"
|
||||||
|
couldnt_get_file_name: "Couldn't get file name. Please try again"
|
||||||
|
following_accounts_have_problems: "Following accounts have problems:"
|
||||||
|
duplicate_names: "Duplicate names"
|
||||||
|
accounts_already_in_db: "Accounts with these names already exist in the database"
|
||||||
|
invalid_fields: "Accounts have invalid names"
|
||||||
|
fix_that_and_send_again: "Fix those errors and send the file again"
|
||||||
|
error_downloading_file: "Error downloading the file"
|
||||||
|
error_getting_account_names: "Error getting existing account names"
|
||||||
|
error_parsing_json_file: "Error parsing the json file"
|
||||||
|
successfully_canceled: "Successfully canceled"
|
||||||
|
invalid_password: "The password is invalid. Change it and send it again"
|
||||||
|
couldnt_get_message_text: "Couldn't get the text of the message. Send the message again"
|
||||||
|
invalid_file_name: "Invalid file name. The program expected you to send a file with .json extension"
|
||||||
|
account_already_exists: "Account with that names already exists"
|
||||||
|
master_password_too_weak: "Master password is too weak"
|
||||||
|
no_lowercase: "It doesn't have any lowercase characters"
|
||||||
|
no_uppercase: "It doesn't have any uppercase characters"
|
||||||
|
no_numbers: "It doesn't have any numbers"
|
||||||
|
master_pass_too_short: "It is shorter than 8 characters"
|
||||||
|
change_master_password_and_send_again: "Change the master password and send it again"
|
||||||
|
wrong_master_password: "Wrong master password. Try again"
|
||||||
|
invalid_login: "Invalid login. Change it and send it again"
|
||||||
|
start_command: "Hi! This bot can be used to store the passwords securely. Use /help command to get the list of commands"
|
||||||
|
master_password_dont_match: "Master password didn't match. Use the command again"
|
||||||
|
success: "Success"
|
||||||
|
send_master_password_again: "Send the master password again"
|
||||||
|
master_password_is_set: "Master password has already been set"
|
||||||
|
send_new_master_password: "Send new master password"
|
||||||
|
no_accounts_found: "No accounts found"
|
||||||
|
choose_account: "Choose the account"
|
||||||
|
couldnt_create_following_accounts: "Couldn't create the following accounts"
|
||||||
|
send_master_password: "Send the master password"
|
||||||
|
something_went_wrong: "Something went wrong. Try again later"
|
||||||
|
nothing_to_cancel: "Nothing to cancel"
|
||||||
|
send_account_name: "Send account name"
|
||||||
|
send_login: "Send login"
|
||||||
|
error_deleting_message: "Error deleting the message"
|
||||||
|
account_not_found: "Account wasn't found"
|
||||||
|
send_new_name: "Send new name"
|
||||||
|
send_new_login: "Send new login"
|
||||||
|
send_new_password: "Send new password"
|
||||||
|
success_choose_account_to_view: "Success. Chose an account to view"
|
||||||
|
send_json_file: "Send the json file to import"
|
||||||
|
send_master_pass_to_delete_everything: "Send master password to delete EVERY ACCOUNT. THIS ACTION CANNOT BE UNDONE"
|
||||||
|
everything_was_deleted: "Every account was deleted"
|
||||||
|
send_password: "Send password"
|
||||||
|
send_master_pass_to_delete_account: "Send the master password to delete the account"
|
||||||
|
no_special_characters: "No special characters in the master password"
|
||||||
|
invalid_name: "Invalid name"
|
||||||
|
word_name: "Name"
|
||||||
|
word_login: "Login"
|
||||||
|
word_password: "Password"
|
||||||
|
decrypt_button: "Decrypt"
|
||||||
|
delete_message_button: "Delete message"
|
||||||
|
menu_button: "Back to the menu"
|
||||||
|
choose_language: "Choose the language"
|
83
locales/ru.yaml
Normal file
83
locales/ru.yaml
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
master_password_is_not_set: "Мастер-пароль не установлен. Используйте /cancel, чтобы отменить текущее действие, и /set_master_pass, чтобы установить его"
|
||||||
|
hide_button: "Скрыть"
|
||||||
|
change_name_button: "Изменить имя"
|
||||||
|
change_login_button: "Изменить логин"
|
||||||
|
change_password_button: "Изменить пароль"
|
||||||
|
delete_account_button: "Удалить аккаунт"
|
||||||
|
couldnt_get_user_info_send_again: "Не удалось получить информацию о пользователе. Отправьте сообщение еще раз"
|
||||||
|
unknown_command_use_help: "Неизвестная команда. Используйте /help, чтобы получить информацию о существующих командах"
|
||||||
|
help_command: |
|
||||||
|
Поддерживаются следующие команды:
|
||||||
|
|
||||||
|
/start — отображает приветственное сообщение
|
||||||
|
/help — отображает этот текст
|
||||||
|
/set_master_pass — устанавливает мастер-пароль
|
||||||
|
/menu — предоставляет меню для управления вашими аккаунтами
|
||||||
|
/add_account — добавляет аккаунт
|
||||||
|
/get_account — получает аккаунт
|
||||||
|
/get_accounts — получает список аккаунтов
|
||||||
|
/delete — удаляет аккаунт
|
||||||
|
/delete_all — удаляет все аккаунты и мастер-пароль
|
||||||
|
/export — экспортирует все аккаунты в файл json
|
||||||
|
/import — загружает аккаунты из файла json
|
||||||
|
/gen_password — генерирует 10 сложных паролей
|
||||||
|
/cancel — отменяет текущее действие
|
||||||
|
/change_language - позволяет изменить язык
|
||||||
|
no_file_send: "Ожидалось, что вы отправите файл"
|
||||||
|
file_too_large: "Файл больше 200 MiB. Пожалуйста, разделите его на несколько файлов"
|
||||||
|
couldnt_get_file_name: "Не удалось получить имя файла. Пожалуйста, попробуйте еще раз"
|
||||||
|
following_accounts_have_problems: "У следующих аккаунтов есть проблемы:"
|
||||||
|
duplicate_names: "Дублирующиеся имена"
|
||||||
|
accounts_already_in_db: "Аккаунты с такими именами уже существуют в базе данных"
|
||||||
|
invalid_fields: "Аккаунты имеют недопустимые имена"
|
||||||
|
fix_that_and_send_again: "Исправьте эти ошибки и отправьте файл снова"
|
||||||
|
error_downloading_file: "Ошибка загрузки файла"
|
||||||
|
error_getting_account_names: "Ошибка получения существующих имен аккаунтов"
|
||||||
|
error_parsing_json_file: "Ошибка разбора файла json"
|
||||||
|
successfully_canceled: "Успешная отменена"
|
||||||
|
invalid_password: "Неверный пароль. Измените его и отправьте снова"
|
||||||
|
couldnt_get_message_text: "Не удалось получить текст сообщения. Отправьте сообщение еще раз"
|
||||||
|
invalid_file_name: "Недопустимое имя файла. Программа ожидала, что вы отправите файл с расширением .json"
|
||||||
|
account_already_exists: "Аккаунт с таким именем уже существует"
|
||||||
|
master_password_too_weak: "Мастер-пароль слишком слабый"
|
||||||
|
no_lowercase: "Отсутствуют строчные буквы"
|
||||||
|
no_uppercase: "Отсутствуют заглавные буквы"
|
||||||
|
no_numbers: "Отсутствуют цифры"
|
||||||
|
master_pass_too_short: "Меньше 8 символов"
|
||||||
|
change_master_password_and_send_again: "Измените мастер-пароль и отправьте его снова"
|
||||||
|
wrong_master_password: "Неверный мастер-пароль. Попробуйте снова"
|
||||||
|
invalid_login: "Недопустимый логин. Измените его и отправьте снова"
|
||||||
|
start_command: "Привет! Этот бот может использоваться для безопасного хранения паролей. Используйте команду /help, чтобы получить список команд"
|
||||||
|
master_password_dont_match: "Мастер-пароли не совпадают. Используйте команду снова"
|
||||||
|
success: "Успешно"
|
||||||
|
send_master_password_again: "Отправьте мастер-пароль снова"
|
||||||
|
master_password_is_set: "Мастер-пароль уже установлен"
|
||||||
|
send_new_master_password: "Отправьте новый мастер-пароль"
|
||||||
|
no_accounts_found: "Аккаунты не найдены"
|
||||||
|
choose_account: "Выберите аккаунт"
|
||||||
|
couldnt_create_following_accounts: "Не удалось создать следующие аккаунты"
|
||||||
|
send_master_password: "Отправьте мастер-пароль"
|
||||||
|
something_went_wrong: "Что-то пошло не так. Попробуйте еще раз позже"
|
||||||
|
nothing_to_cancel: "Нечего отменять"
|
||||||
|
send_account_name: "Отправьте имя аккаунта"
|
||||||
|
send_login: "Отправьте логин"
|
||||||
|
error_deleting_message: "Ошибка удаления сообщения"
|
||||||
|
account_not_found: "Аккаунт не найден"
|
||||||
|
send_new_name: "Отправьте новое имя"
|
||||||
|
send_new_login: "Отправьте новый логин"
|
||||||
|
send_new_password: "Отправьте новый пароль"
|
||||||
|
success_choose_account_to_view: "Успешно. Выберите аккаунт для просмотра"
|
||||||
|
send_json_file: "Отправьте файл json для импорта"
|
||||||
|
send_master_pass_to_delete_everything: "Отправьте мастер-пароль, чтобы удалить ВСЕ АККАУНТЫ. ЭТО ДЕЙСТВИЕ НЕЛЬЗЯ ОТМЕНИТЬ"
|
||||||
|
everything_was_deleted: "Все аккаунты были удалены"
|
||||||
|
send_password: "Отправьте пароль"
|
||||||
|
send_master_pass_to_delete_account: "Отправьте мастер-пароль, чтобы удалить аккаунт"
|
||||||
|
no_special_characters: "Нет специальных символов в мастер-пароле"
|
||||||
|
invalid_name: "Недопустимое имя"
|
||||||
|
word_name: "Имя"
|
||||||
|
word_login: "Логин"
|
||||||
|
word_password: "Пароль"
|
||||||
|
decrypt_button: "Дешифровать"
|
||||||
|
delete_message_button: "Удалить сообщение"
|
||||||
|
menu_button: "Назад в меню"
|
||||||
|
choose_language: "Выберете язык"
|
@ -1,22 +1,31 @@
|
|||||||
//! This module consists of endpoints to handle callbacks
|
//! This module consists of endpoints to handle callbacks
|
||||||
|
|
||||||
crate::export_handlers!(decrypt, delete, delete_message, get, get_menu, alter);
|
crate::export_handlers!(
|
||||||
|
decrypt,
|
||||||
|
delete,
|
||||||
|
delete_message,
|
||||||
|
get,
|
||||||
|
get_menu,
|
||||||
|
alter,
|
||||||
|
change_locale
|
||||||
|
);
|
||||||
|
|
||||||
use crate::errors::InvalidCommand;
|
use crate::{errors::InvalidCommand, locales::LocaleTypeExt};
|
||||||
use base64::{engine::general_purpose::STANDARD_NO_PAD as B64_ENGINE, Engine as _};
|
use base64::{engine::general_purpose::STANDARD_NO_PAD as B64_ENGINE, Engine as _};
|
||||||
|
use entity::locale::LocaleType;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use teloxide::types::CallbackQuery;
|
use teloxide::types::CallbackQuery;
|
||||||
|
|
||||||
type NameHash = Vec<u8>;
|
type NameHash = Vec<u8>;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum AlterableField {
|
pub enum AlterableField {
|
||||||
Name,
|
Name,
|
||||||
Login,
|
Login,
|
||||||
Pass,
|
Pass,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub enum CallbackCommand {
|
pub enum CallbackCommand {
|
||||||
DeleteMessage,
|
DeleteMessage,
|
||||||
Get(NameHash),
|
Get(NameHash),
|
||||||
@ -25,12 +34,13 @@ pub enum CallbackCommand {
|
|||||||
Hide(NameHash),
|
Hide(NameHash),
|
||||||
Alter(NameHash, AlterableField),
|
Alter(NameHash, AlterableField),
|
||||||
DeleteAccount { name: NameHash, is_command: bool },
|
DeleteAccount { name: NameHash, is_command: bool },
|
||||||
|
ChangeLocale(LocaleType),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallbackCommand {
|
impl CallbackCommand {
|
||||||
pub fn from_query(q: CallbackQuery) -> Option<Self> {
|
pub fn from_query(q: CallbackQuery) -> Option<Self> {
|
||||||
q.message.as_ref()?;
|
q.message?;
|
||||||
q.data.and_then(|data| data.parse().ok())
|
q.data?.parse().inspect_err(|err| log::error!("{err}")).ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,13 +55,19 @@ impl FromStr for CallbackCommand {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut substrings = s.split(' ');
|
let mut substrings = s.split(' ');
|
||||||
let (Some(command), Some(name), None) =
|
let (Some(command), Some(param), None) =
|
||||||
(substrings.next(), substrings.next(), substrings.next())
|
(substrings.next(), substrings.next(), substrings.next())
|
||||||
else {
|
else {
|
||||||
return Err(InvalidCommand::InvalidParams);
|
return Err(InvalidCommand::InvalidParams);
|
||||||
};
|
};
|
||||||
|
|
||||||
let name_hash = B64_ENGINE.decode(name)?;
|
if command == "change_locale" {
|
||||||
|
let locale =
|
||||||
|
LocaleType::from_language_code(param).ok_or(InvalidCommand::UnknownLocale)?;
|
||||||
|
return Ok(Self::ChangeLocale(locale));
|
||||||
|
}
|
||||||
|
|
||||||
|
let name_hash = B64_ENGINE.decode(param)?;
|
||||||
if name_hash.len() != 32 {
|
if name_hash.len() != 32 {
|
||||||
return Err(InvalidCommand::InvalidOutputLength);
|
return Err(InvalidCommand::InvalidOutputLength);
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ async fn get_master_pass(
|
|||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
mut ids: MessageIds,
|
mut ids: MessageIds,
|
||||||
|
locale: LocaleRef,
|
||||||
name: String,
|
name: String,
|
||||||
field: AlterableField,
|
field: AlterableField,
|
||||||
field_value: String,
|
field_value: String,
|
||||||
@ -57,7 +58,7 @@ async fn get_master_pass(
|
|||||||
|
|
||||||
ids.alter_message(
|
ids.alter_message(
|
||||||
&bot,
|
&bot,
|
||||||
"Success. Choose the account to view",
|
locale.success_choose_account_to_view.as_ref(),
|
||||||
menu_markup("get", user_id, &db).await?,
|
menu_markup("get", user_id, &db).await?,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@ -66,7 +67,7 @@ async fn get_master_pass(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
handler!(get_field(name:String, field:AlterableField, field_value:String), "Send the master password", State::GetMasterPass, get_master_pass);
|
handler!(get_field(name:String, field:AlterableField, field_value:String),send_master_password, State::GetMasterPass, get_master_pass);
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn alter(
|
pub async fn alter(
|
||||||
@ -74,6 +75,7 @@ pub async fn alter(
|
|||||||
q: CallbackQuery,
|
q: CallbackQuery,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
|
locale: LocaleRef,
|
||||||
(hash, field): (super::NameHash, AlterableField),
|
(hash, field): (super::NameHash, AlterableField),
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let user_id = q.from.id.0;
|
let user_id = q.from.id.0;
|
||||||
@ -81,7 +83,7 @@ pub async fn alter(
|
|||||||
|
|
||||||
let Some(name) = Account::get_name_by_hash(user_id, &hash, &db).await? else {
|
let Some(name) = Account::get_name_by_hash(user_id, &hash, &db).await? else {
|
||||||
bot.send_message(ids.0, "Account wasn't found")
|
bot.send_message(ids.0, "Account wasn't found")
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
bot.answer_callback_query(q.id).await?;
|
bot.answer_callback_query(q.id).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -90,15 +92,15 @@ pub async fn alter(
|
|||||||
let text = match field {
|
let text = match field {
|
||||||
Name => {
|
Name => {
|
||||||
change_state!(dialogue, ids, (name, field), State::GetNewName, get_field);
|
change_state!(dialogue, ids, (name, field), State::GetNewName, get_field);
|
||||||
"Send new account name"
|
locale.send_new_name.as_ref()
|
||||||
}
|
}
|
||||||
Login => {
|
Login => {
|
||||||
change_state!(dialogue, ids, (name, field), State::GetLogin, get_field);
|
change_state!(dialogue, ids, (name, field), State::GetLogin, get_field);
|
||||||
"Send new account login"
|
locale.send_new_login.as_ref()
|
||||||
}
|
}
|
||||||
Pass => {
|
Pass => {
|
||||||
change_state!(dialogue, ids, (name, field), State::GetPassword, get_field);
|
change_state!(dialogue, ids, (name, field), State::GetPassword, get_field);
|
||||||
"Send new account password"
|
locale.send_new_password.as_ref()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
42
src/callbacks/change_locale.rs
Normal file
42
src/callbacks/change_locale.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use crate::{locales::LocaleTypeExt, prelude::*};
|
||||||
|
use entity::locale::LocaleType;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub async fn change_locale(
|
||||||
|
bot: Throttle<Bot>,
|
||||||
|
q: CallbackQuery,
|
||||||
|
db: Pool,
|
||||||
|
mut locale: LocaleRef,
|
||||||
|
new_locale: LocaleType,
|
||||||
|
) -> crate::Result<()> {
|
||||||
|
let mut ids: MessageIds = q.message.as_ref().unwrap().into();
|
||||||
|
let user_id = q.from.id.0;
|
||||||
|
|
||||||
|
let is_successful = new_locale
|
||||||
|
.update(user_id, &db)
|
||||||
|
.await
|
||||||
|
.inspect_err(|err| log::error!("{err}"))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if !is_successful {
|
||||||
|
ids.alter_message(
|
||||||
|
&bot,
|
||||||
|
locale.something_went_wrong.as_ref(),
|
||||||
|
deletion_markup(locale),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
locale = new_locale.get_locale();
|
||||||
|
ids.alter_message(
|
||||||
|
&bot,
|
||||||
|
locale.choose_language.as_ref(),
|
||||||
|
language_markup(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -3,12 +3,14 @@ use teloxide::types::ParseMode;
|
|||||||
use tokio::task::spawn_blocking;
|
use tokio::task::spawn_blocking;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn get_master_pass(
|
async fn get_master_pass(
|
||||||
bot: Throttle<Bot>,
|
bot: Throttle<Bot>,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
mut ids: MessageIds,
|
mut ids: MessageIds,
|
||||||
|
locale: LocaleRef,
|
||||||
name: String,
|
name: String,
|
||||||
master_pass: String,
|
master_pass: String,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
@ -17,8 +19,8 @@ async fn get_master_pass(
|
|||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
||||||
|
|
||||||
let Some(account) = Account::get(user_id, &name, &db).await? else {
|
let Some(account) = Account::get(user_id, &name, &db).await? else {
|
||||||
bot.send_message(msg.chat.id, "Account not found")
|
bot.send_message(msg.chat.id, locale.no_accounts_found.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
@ -26,15 +28,12 @@ async fn get_master_pass(
|
|||||||
let account =
|
let account =
|
||||||
spawn_blocking(move || DecryptedAccount::from_account(account, &master_pass)).await??;
|
spawn_blocking(move || DecryptedAccount::from_account(account, &master_pass)).await??;
|
||||||
|
|
||||||
let text = format!(
|
let text = locale.show_account(&account.name, &account.login, &account.password);
|
||||||
"Name:\n`{name}`\nLogin:\n`{}`\nPassword:\n`{}`",
|
|
||||||
account.login, account.password
|
|
||||||
);
|
|
||||||
|
|
||||||
ids.alter_message(
|
ids.alter_message(
|
||||||
&bot,
|
&bot,
|
||||||
text,
|
text,
|
||||||
account_markup(&name, false),
|
account_markup(&name, false, locale),
|
||||||
ParseMode::MarkdownV2,
|
ParseMode::MarkdownV2,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@ -47,20 +46,21 @@ pub async fn decrypt(
|
|||||||
q: CallbackQuery,
|
q: CallbackQuery,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
|
locale: LocaleRef,
|
||||||
hash: super::NameHash,
|
hash: super::NameHash,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let mut ids: MessageIds = q.message.as_ref().unwrap().into();
|
let mut ids: MessageIds = q.message.as_ref().unwrap().into();
|
||||||
let user_id = q.from.id.0;
|
let user_id = q.from.id.0;
|
||||||
|
|
||||||
let Some(name) = Account::get_name_by_hash(user_id, &hash, &db).await? else {
|
let Some(name) = Account::get_name_by_hash(user_id, &hash, &db).await? else {
|
||||||
bot.send_message(ids.0, "Account wasn't found")
|
bot.send_message(ids.0, locale.no_accounts_found.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
bot.answer_callback_query(q.id).await?;
|
bot.answer_callback_query(q.id).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
ids.alter_message(&bot, "Send master password", None, None)
|
ids.alter_message(&bot, locale.send_master_password.as_ref(), None, None)
|
||||||
.await?;
|
.await?;
|
||||||
bot.answer_callback_query(q.id).await?;
|
bot.answer_callback_query(q.id).await?;
|
||||||
|
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
use crate::{change_state, prelude::*};
|
use crate::{change_state, prelude::*};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn get_master_pass(
|
async fn get_master_pass(
|
||||||
bot: Throttle<Bot>,
|
bot: Throttle<Bot>,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
mut ids: MessageIds,
|
mut ids: MessageIds,
|
||||||
|
locale: LocaleRef,
|
||||||
name: String,
|
name: String,
|
||||||
_: String,
|
_: String,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
@ -15,12 +17,7 @@ async fn get_master_pass(
|
|||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
||||||
Account::delete(user_id, &name, &db).await?;
|
Account::delete(user_id, &name, &db).await?;
|
||||||
|
|
||||||
ids.alter_message(
|
ids.alter_message(&bot, locale.success.as_ref(), deletion_markup(locale), None)
|
||||||
&bot,
|
|
||||||
"The account is successfully deleted",
|
|
||||||
deletion_markup(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -32,26 +29,26 @@ pub async fn delete(
|
|||||||
q: CallbackQuery,
|
q: CallbackQuery,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
|
locale: LocaleRef,
|
||||||
(hash, is_command): (super::NameHash, bool),
|
(hash, is_command): (super::NameHash, bool),
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
const TEXT: &str = "Send master password. \
|
let text = locale.send_master_pass_to_delete_account.as_ref();
|
||||||
Once you send the master password the account is unrecoverable";
|
|
||||||
|
|
||||||
let mut ids: MessageIds = q.message.as_ref().unwrap().into();
|
let mut ids: MessageIds = q.message.as_ref().unwrap().into();
|
||||||
let user_id = q.from.id.0;
|
let user_id = q.from.id.0;
|
||||||
|
|
||||||
let Some(name) = Account::get_name_by_hash(user_id, &hash, &db).await? else {
|
let Some(name) = Account::get_name_by_hash(user_id, &hash, &db).await? else {
|
||||||
bot.send_message(ids.0, "Account wasn't found")
|
bot.send_message(ids.0, locale.no_accounts_found.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
bot.answer_callback_query(q.id).await?;
|
bot.answer_callback_query(q.id).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_command {
|
if is_command {
|
||||||
ids.alter_message(&bot, TEXT, None, None).await?;
|
ids.alter_message(&bot, text, None, None).await?;
|
||||||
} else {
|
} else {
|
||||||
let msg = bot.send_message(ids.0, TEXT).await?;
|
let msg = bot.send_message(ids.0, text).await?;
|
||||||
ids = MessageIds::from(&msg);
|
ids = MessageIds::from(&msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,11 +2,15 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Deletes the message from the callback
|
/// Deletes the message from the callback
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn delete_message(bot: Throttle<Bot>, q: CallbackQuery) -> crate::Result<()> {
|
pub async fn delete_message(
|
||||||
|
bot: Throttle<Bot>,
|
||||||
|
q: CallbackQuery,
|
||||||
|
locale: LocaleRef,
|
||||||
|
) -> crate::Result<()> {
|
||||||
if let Some(msg) = q.message {
|
if let Some(msg) = q.message {
|
||||||
if bot.delete_message(msg.chat.id, msg.id).await.is_err() {
|
if bot.delete_message(msg.chat.id, msg.id).await.is_err() {
|
||||||
bot.send_message(msg.chat.id, "Error deleting the message")
|
bot.send_message(msg.chat.id, locale.error_deleting_message.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,25 +6,26 @@ pub async fn get(
|
|||||||
bot: Throttle<Bot>,
|
bot: Throttle<Bot>,
|
||||||
q: CallbackQuery,
|
q: CallbackQuery,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
hash: super::NameHash,
|
hash: super::NameHash,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let user_id = q.from.id.0;
|
let user_id = q.from.id.0;
|
||||||
let mut ids: MessageIds = q.message.as_ref().unwrap().into();
|
let mut ids: MessageIds = q.message.as_ref().unwrap().into();
|
||||||
|
|
||||||
let Some(name) = Account::get_name_by_hash(user_id, &hash, &db).await? else {
|
let Some(name) = Account::get_name_by_hash(user_id, &hash, &db).await? else {
|
||||||
bot.send_message(ids.0, "Account wasn't found")
|
bot.send_message(ids.0, locale.account_not_found.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
bot.answer_callback_query(q.id).await?;
|
bot.answer_callback_query(q.id).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let text = format!("Name:\n`{name}`\nLogin:\n\\*\\*\\*\nPassword:\n\\*\\*\\*");
|
let text = locale.show_hidden_account(&name);
|
||||||
|
|
||||||
ids.alter_message(
|
ids.alter_message(
|
||||||
&bot,
|
&bot,
|
||||||
text,
|
text,
|
||||||
account_markup(&name, true),
|
account_markup(&name, true, locale),
|
||||||
ParseMode::MarkdownV2,
|
ParseMode::MarkdownV2,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -1,18 +1,28 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn get_menu(bot: Throttle<Bot>, q: CallbackQuery, db: Pool) -> crate::Result<()> {
|
pub async fn get_menu(
|
||||||
|
bot: Throttle<Bot>,
|
||||||
|
q: CallbackQuery,
|
||||||
|
db: Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
|
) -> crate::Result<()> {
|
||||||
let user_id = q.from.id.0;
|
let user_id = q.from.id.0;
|
||||||
let mut ids: MessageIds = q.message.as_ref().unwrap().into();
|
let mut ids: MessageIds = q.message.as_ref().unwrap().into();
|
||||||
|
|
||||||
let markup = menu_markup("get", user_id, &db).await?;
|
let markup = menu_markup("get", user_id, &db).await?;
|
||||||
if markup.inline_keyboard.is_empty() {
|
if markup.inline_keyboard.is_empty() {
|
||||||
ids.alter_message(&bot, "You don't have any accounts", deletion_markup(), None)
|
ids.alter_message(
|
||||||
|
&bot,
|
||||||
|
locale.no_accounts_found.as_ref(),
|
||||||
|
deletion_markup(locale),
|
||||||
|
None,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
ids.alter_message(&bot, "Choose your account", markup, None)
|
ids.alter_message(&bot, locale.choose_account.as_ref(), markup, None)
|
||||||
.await?;
|
.await?;
|
||||||
bot.answer_callback_query(q.id).await?;
|
bot.answer_callback_query(q.id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -13,41 +13,27 @@ crate::export_handlers!(
|
|||||||
import,
|
import,
|
||||||
menu,
|
menu,
|
||||||
set_master_pass,
|
set_master_pass,
|
||||||
start
|
start,
|
||||||
|
change_language
|
||||||
);
|
);
|
||||||
|
|
||||||
use teloxide::macros::BotCommands;
|
use teloxide::macros::BotCommands;
|
||||||
|
|
||||||
#[derive(BotCommands, Clone, Copy)]
|
#[derive(BotCommands, Clone, Copy)]
|
||||||
#[command(
|
#[command(rename_rule = "snake_case")]
|
||||||
rename_rule = "snake_case",
|
|
||||||
description = "These commands are supported:"
|
|
||||||
)]
|
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
#[command(description = "displays the welcome message")]
|
|
||||||
Start,
|
Start,
|
||||||
#[command(description = "displays this text")]
|
|
||||||
Help,
|
Help,
|
||||||
#[command(description = "sets the master password")]
|
|
||||||
SetMasterPass,
|
SetMasterPass,
|
||||||
#[command(description = "gives you a menu to manage your accounts")]
|
|
||||||
Menu,
|
Menu,
|
||||||
#[command(description = "adds the account")]
|
|
||||||
AddAccount,
|
AddAccount,
|
||||||
#[command(description = "gets the account")]
|
|
||||||
GetAccount,
|
GetAccount,
|
||||||
#[command(description = "gets a list of accounts")]
|
|
||||||
GetAccounts,
|
GetAccounts,
|
||||||
#[command(description = "deletes the account")]
|
|
||||||
Delete,
|
Delete,
|
||||||
#[command(description = "deletes all the accounts and the master password")]
|
|
||||||
DeleteAll,
|
DeleteAll,
|
||||||
#[command(description = "exports all the accounts in a json file")]
|
|
||||||
Export,
|
Export,
|
||||||
#[command(description = "loads the accounts from a json file")]
|
|
||||||
Import,
|
Import,
|
||||||
#[command(description = "generates 10 secure passwords")]
|
|
||||||
GenPassword,
|
GenPassword,
|
||||||
#[command(description = "cancels the current action")]
|
|
||||||
Cancel,
|
Cancel,
|
||||||
|
ChangeLanguage,
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ async fn get_master_pass(
|
|||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
mut ids: MessageIds,
|
mut ids: MessageIds,
|
||||||
|
locale: LocaleRef,
|
||||||
name: String,
|
name: String,
|
||||||
login: String,
|
login: String,
|
||||||
password: String,
|
password: String,
|
||||||
@ -30,26 +31,26 @@ async fn get_master_pass(
|
|||||||
.await?;
|
.await?;
|
||||||
account.insert(&db).await?;
|
account.insert(&db).await?;
|
||||||
|
|
||||||
ids.alter_message(&bot, "Success", deletion_markup(), None)
|
ids.alter_message(&bot, locale.success.as_ref(), deletion_markup(locale), None)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
handler!(
|
handler!(
|
||||||
get_password(name:String, login: String, password: String),
|
get_password(name:String, login: String, password: String),
|
||||||
"Send master password",
|
send_master_password,
|
||||||
State::GetMasterPass,
|
State::GetMasterPass,
|
||||||
get_master_pass
|
get_master_pass
|
||||||
);
|
);
|
||||||
handler!(get_login(name: String, login: String),
|
handler!(get_login(name: String, login: String),
|
||||||
"Send password",
|
send_password,
|
||||||
State::GetPassword,
|
State::GetPassword,
|
||||||
get_password
|
get_password
|
||||||
);
|
);
|
||||||
handler!(get_account_name(name: String), "Send login", State::GetLogin, get_login);
|
handler!(get_account_name(name: String), send_login, State::GetLogin, get_login);
|
||||||
first_handler!(
|
first_handler!(
|
||||||
add_account,
|
add_account,
|
||||||
"Send account name",
|
send_account_name,
|
||||||
State::GetNewName,
|
State::GetNewName,
|
||||||
get_account_name
|
get_account_name
|
||||||
);
|
);
|
||||||
|
@ -2,9 +2,9 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Handles /cancel command when there's no active state
|
/// Handles /cancel command when there's no active state
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn cancel(bot: Throttle<Bot>, msg: Message) -> crate::Result<()> {
|
pub async fn cancel(bot: Throttle<Bot>, msg: Message, locale: LocaleRef) -> crate::Result<()> {
|
||||||
bot.send_message(msg.chat.id, "Nothing to cancel")
|
bot.send_message(msg.chat.id, locale.nothing_to_cancel.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
13
src/commands/change_language.rs
Normal file
13
src/commands/change_language.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub async fn change_language(
|
||||||
|
bot: Throttle<Bot>,
|
||||||
|
msg: Message,
|
||||||
|
locale: LocaleRef,
|
||||||
|
) -> crate::Result<()> {
|
||||||
|
bot.send_message(msg.chat.id, locale.choose_language.as_ref())
|
||||||
|
.reply_markup(language_markup())
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -1,19 +1,24 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn delete(bot: Throttle<Bot>, msg: Message, db: Pool) -> crate::Result<()> {
|
pub async fn delete(
|
||||||
|
bot: Throttle<Bot>,
|
||||||
|
msg: Message,
|
||||||
|
db: Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
|
) -> crate::Result<()> {
|
||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
||||||
|
|
||||||
let markup = menu_markup("delete1", user_id, &db).await?;
|
let markup = menu_markup("delete1", user_id, &db).await?;
|
||||||
|
|
||||||
if markup.inline_keyboard.is_empty() {
|
if markup.inline_keyboard.is_empty() {
|
||||||
bot.send_message(msg.chat.id, "You don't have any accounts")
|
bot.send_message(msg.chat.id, locale.no_accounts_found.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.send_message(msg.chat.id, "Choose the account to delete")
|
bot.send_message(msg.chat.id, locale.choose_account.as_ref())
|
||||||
.reply_markup(markup)
|
.reply_markup(markup)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -10,6 +10,7 @@ async fn get_master_pass(
|
|||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
mut ids: MessageIds,
|
mut ids: MessageIds,
|
||||||
|
locale: LocaleRef,
|
||||||
_: String,
|
_: String,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
dialogue.exit().await?;
|
dialogue.exit().await?;
|
||||||
@ -23,22 +24,22 @@ async fn get_master_pass(
|
|||||||
let text = match result {
|
let text = match result {
|
||||||
(Ok(()), Ok(())) => {
|
(Ok(()), Ok(())) => {
|
||||||
txn.commit().await?;
|
txn.commit().await?;
|
||||||
"Everything was deleted"
|
locale.everything_was_deleted.as_ref()
|
||||||
}
|
}
|
||||||
(Err(err), _) | (_, Err(err)) => {
|
(Err(err), _) | (_, Err(err)) => {
|
||||||
error!("{}", crate::Error::from(err));
|
error!("{}", crate::Error::from(err));
|
||||||
txn.rollback().await?;
|
txn.rollback().await?;
|
||||||
"Something went wrong. Try again later"
|
locale.something_went_wrong.as_ref()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ids.alter_message(&bot, text, deletion_markup(), None)
|
ids.alter_message(&bot, text, deletion_markup(locale), None)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
first_handler!(
|
first_handler!(
|
||||||
delete_all,
|
delete_all,
|
||||||
"Send master password to delete EVERYTHING.\nTHIS ACTION IS IRREVERSIBLE",
|
send_master_pass_to_delete_everything,
|
||||||
State::GetMasterPass,
|
State::GetMasterPass,
|
||||||
get_master_pass
|
get_master_pass
|
||||||
);
|
);
|
||||||
|
@ -25,6 +25,7 @@ async fn get_master_pass(
|
|||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
ids: MessageIds,
|
ids: MessageIds,
|
||||||
|
locale: LocaleRef,
|
||||||
master_pass: String,
|
master_pass: String,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
dialogue.exit().await?;
|
dialogue.exit().await?;
|
||||||
@ -51,14 +52,14 @@ async fn get_master_pass(
|
|||||||
let file = InputFile::memory(json).file_name("accounts.json");
|
let file = InputFile::memory(json).file_name("accounts.json");
|
||||||
|
|
||||||
bot.send_document(msg.chat.id, file)
|
bot.send_document(msg.chat.id, file)
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
first_handler!(
|
first_handler!(
|
||||||
export,
|
export,
|
||||||
"Send the master password to export your accounts",
|
send_master_password,
|
||||||
State::GetMasterPass,
|
State::GetMasterPass,
|
||||||
get_master_pass
|
get_master_pass
|
||||||
);
|
);
|
||||||
|
@ -15,7 +15,11 @@ const BUFFER_LENGTH: usize =
|
|||||||
|
|
||||||
/// Handles /`gen_password` command by generating 10 copyable passwords and sending them to the user
|
/// Handles /`gen_password` command by generating 10 copyable passwords and sending them to the user
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn gen_password(bot: Throttle<Bot>, msg: Message) -> crate::Result<()> {
|
pub async fn gen_password(
|
||||||
|
bot: Throttle<Bot>,
|
||||||
|
msg: Message,
|
||||||
|
locale: LocaleRef,
|
||||||
|
) -> crate::Result<()> {
|
||||||
let mut message: ArrayString<BUFFER_LENGTH> = MESSAGE_HEADER.try_into().unwrap();
|
let mut message: ArrayString<BUFFER_LENGTH> = MESSAGE_HEADER.try_into().unwrap();
|
||||||
let passwords: PasswordArray = spawn_blocking(generate_passwords).await?;
|
let passwords: PasswordArray = spawn_blocking(generate_passwords).await?;
|
||||||
for password in passwords {
|
for password in passwords {
|
||||||
@ -23,7 +27,7 @@ pub async fn gen_password(bot: Throttle<Bot>, msg: Message) -> crate::Result<()>
|
|||||||
}
|
}
|
||||||
bot.send_message(msg.chat.id, message.as_str())
|
bot.send_message(msg.chat.id, message.as_str())
|
||||||
.parse_mode(ParseMode::MarkdownV2)
|
.parse_mode(ParseMode::MarkdownV2)
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,24 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn get_account(bot: Throttle<Bot>, msg: Message, db: Pool) -> crate::Result<()> {
|
pub async fn get_account(
|
||||||
|
bot: Throttle<Bot>,
|
||||||
|
msg: Message,
|
||||||
|
db: Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
|
) -> crate::Result<()> {
|
||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
||||||
|
|
||||||
let markup = menu_markup("decrypt", user_id, &db).await?;
|
let markup = menu_markup("decrypt", user_id, &db).await?;
|
||||||
|
|
||||||
if markup.inline_keyboard.is_empty() {
|
if markup.inline_keyboard.is_empty() {
|
||||||
bot.send_message(msg.chat.id, "You don't have any accounts")
|
bot.send_message(msg.chat.id, locale.no_accounts_found.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.send_message(msg.chat.id, "Choose the account to get")
|
bot.send_message(msg.chat.id, locale.choose_account.as_ref())
|
||||||
.reply_markup(markup)
|
.reply_markup(markup)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -4,26 +4,32 @@ use teloxide::types::ParseMode;
|
|||||||
|
|
||||||
/// Handles /`get_accounts` command by sending the list of copyable account names to the user
|
/// Handles /`get_accounts` command by sending the list of copyable account names to the user
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn get_accounts(bot: Throttle<Bot>, msg: Message, db: Pool) -> crate::Result<()> {
|
pub async fn get_accounts(
|
||||||
|
bot: Throttle<Bot>,
|
||||||
|
msg: Message,
|
||||||
|
db: Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
|
) -> crate::Result<()> {
|
||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
||||||
let mut account_names = Account::get_names(user_id, &db);
|
let mut account_names = Account::get_names(user_id, &db);
|
||||||
|
|
||||||
let mut text = if let Some(name) = account_names.try_next().await? {
|
let Some(mut text) = account_names.try_next().await? else {
|
||||||
format!("Accounts:\n`{name}`")
|
bot.send_message(msg.chat.id, locale.no_accounts_found.as_ref())
|
||||||
} else {
|
.reply_markup(deletion_markup(locale))
|
||||||
bot.send_message(msg.chat.id, "No accounts found")
|
|
||||||
.reply_markup(deletion_markup())
|
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
text.insert(0, '`');
|
||||||
|
text.push('`');
|
||||||
|
|
||||||
while let Some(name) = account_names.try_next().await? {
|
while let Some(name) = account_names.try_next().await? {
|
||||||
write!(text, "\n`{name}`")?;
|
write!(text, "\n`{name}`")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.send_message(msg.chat.id, text)
|
bot.send_message(msg.chat.id, text)
|
||||||
.parse_mode(ParseMode::MarkdownV2)
|
.parse_mode(ParseMode::MarkdownV2)
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use teloxide::utils::command::BotCommands;
|
|
||||||
|
|
||||||
/// Handles the help command by sending the passwords descryptions
|
/// Handles the help command by sending the passwords descryptions
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn help(bot: Throttle<Bot>, msg: Message) -> crate::Result<()> {
|
pub async fn help(bot: Throttle<Bot>, msg: Message, locale: LocaleRef) -> crate::Result<()> {
|
||||||
bot.send_message(msg.chat.id, Command::descriptions().to_string())
|
bot.send_message(msg.chat.id, locale.help_command.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -27,12 +27,14 @@ async fn encrypt_account(
|
|||||||
|
|
||||||
/// Gets the master password, encryptes and adds the accounts to the DB
|
/// Gets the master password, encryptes and adds the accounts to the DB
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn get_master_pass(
|
async fn get_master_pass(
|
||||||
bot: Throttle<Bot>,
|
bot: Throttle<Bot>,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
mut ids: MessageIds,
|
mut ids: MessageIds,
|
||||||
|
locale: LocaleRef,
|
||||||
user: User,
|
user: User,
|
||||||
master_pass: String,
|
master_pass: String,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
@ -53,22 +55,18 @@ async fn get_master_pass(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let text = if failed.is_empty() {
|
let text = if failed.is_empty() {
|
||||||
"Success".to_owned()
|
locale.success.as_ref().to_owned()
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"Failed to create the following accounts:\n{}",
|
"{}:\n{}",
|
||||||
|
locale.couldnt_create_following_accounts,
|
||||||
failed.into_iter().format("\n")
|
failed.into_iter().format("\n")
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
ids.alter_message(&bot, text, deletion_markup(), None)
|
ids.alter_message(&bot, text, deletion_markup(locale), None)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
handler!(get_user(user: User), "Send master password", State::GetMasterPass, get_master_pass);
|
handler!(get_user(user: User),send_master_password, State::GetMasterPass, get_master_pass);
|
||||||
first_handler!(
|
first_handler!(import, send_json_file, State::GetUser, get_user);
|
||||||
import,
|
|
||||||
"Send a json document with the same format as created by /export",
|
|
||||||
State::GetUser,
|
|
||||||
get_user
|
|
||||||
);
|
|
||||||
|
@ -1,19 +1,24 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn menu(bot: Throttle<Bot>, msg: Message, db: Pool) -> crate::Result<()> {
|
pub async fn menu(
|
||||||
|
bot: Throttle<Bot>,
|
||||||
|
msg: Message,
|
||||||
|
db: Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
|
) -> crate::Result<()> {
|
||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
||||||
|
|
||||||
let markup = menu_markup("get", user_id, &db).await?;
|
let markup = menu_markup("get", user_id, &db).await?;
|
||||||
|
|
||||||
if markup.inline_keyboard.is_empty() {
|
if markup.inline_keyboard.is_empty() {
|
||||||
bot.send_message(msg.chat.id, "You don't have any accounts")
|
bot.send_message(msg.chat.id, locale.no_accounts_found.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.send_message(msg.chat.id, "Choose your account")
|
bot.send_message(msg.chat.id, locale.choose_account.as_ref())
|
||||||
.reply_markup(markup)
|
.reply_markup(markup)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,25 +1,29 @@
|
|||||||
use crate::{change_state, prelude::*};
|
use crate::{change_state, locales::LocaleTypeExt, prelude::*};
|
||||||
use cryptography::hashing::HashedBytes;
|
use cryptography::hashing::HashedBytes;
|
||||||
|
use entity::locale::LocaleType;
|
||||||
use tokio::task::spawn_blocking;
|
use tokio::task::spawn_blocking;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn get_master_pass2(
|
async fn get_master_pass2(
|
||||||
bot: Throttle<Bot>,
|
bot: Throttle<Bot>,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
mut ids: MessageIds,
|
mut ids: MessageIds,
|
||||||
|
locale: LocaleRef,
|
||||||
hash: HashedBytes<[u8; 64], [u8; 64]>,
|
hash: HashedBytes<[u8; 64], [u8; 64]>,
|
||||||
master_pass: String,
|
master_pass: String,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
dialogue.exit().await?;
|
dialogue.exit().await?;
|
||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let from = msg.from().ok_or(NoUserInfo)?;
|
||||||
|
let user_id = from.id.0;
|
||||||
|
|
||||||
if !hash.verify(master_pass.as_bytes()) {
|
if !hash.verify(master_pass.as_bytes()) {
|
||||||
ids.alter_message(
|
ids.alter_message(
|
||||||
&bot,
|
&bot,
|
||||||
"The passwords didn't match. Use the command again",
|
locale.master_password_dont_match.as_ref(),
|
||||||
deletion_markup(),
|
deletion_markup(locale),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@ -32,9 +36,14 @@ async fn get_master_pass2(
|
|||||||
password_hash: hash.hash.to_vec(),
|
password_hash: hash.hash.to_vec(),
|
||||||
salt: hash.salt.to_vec(),
|
salt: hash.salt.to_vec(),
|
||||||
};
|
};
|
||||||
model.insert(&db).await?;
|
let locale_type = from
|
||||||
|
.language_code
|
||||||
|
.as_deref()
|
||||||
|
.and_then(LocaleType::from_language_code)
|
||||||
|
.unwrap_or_default();
|
||||||
|
model.insert(&db, locale_type).await?;
|
||||||
|
|
||||||
ids.alter_message(&bot, "Success", deletion_markup(), None)
|
ids.alter_message(&bot, locale.success.as_ref(), deletion_markup(locale), None)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -47,11 +56,13 @@ async fn get_master_pass(
|
|||||||
_: Pool,
|
_: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
mut ids: MessageIds,
|
mut ids: MessageIds,
|
||||||
|
locale: LocaleRef,
|
||||||
master_pass: String,
|
master_pass: String,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let hash = spawn_blocking(move || HashedBytes::new(master_pass.as_bytes())).await?;
|
let hash = spawn_blocking(move || HashedBytes::new(master_pass.as_bytes())).await?;
|
||||||
|
|
||||||
ids.alter_message(&bot, "Send it again", None, None).await?;
|
ids.alter_message(&bot, locale.send_master_password_again.as_ref(), None, None)
|
||||||
|
.await?;
|
||||||
|
|
||||||
change_state!(
|
change_state!(
|
||||||
dialogue,
|
dialogue,
|
||||||
@ -71,16 +82,17 @@ pub async fn set_master_pass(
|
|||||||
msg: Message,
|
msg: Message,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
||||||
if MasterPass::exists(user_id, &db).await? {
|
if MasterPass::exists(user_id, &db).await? {
|
||||||
bot.send_message(msg.chat.id, "Master password already exists")
|
bot.send_message(msg.chat.id, locale.master_password_is_set.as_ref())
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let previous = bot
|
let previous = bot
|
||||||
.send_message(msg.chat.id, "Send new master password")
|
.send_message(msg.chat.id, locale.send_new_master_password.as_ref())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
change_state!(
|
change_state!(
|
||||||
|
@ -2,12 +2,8 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Handles /start command by sending the greeting message
|
/// Handles /start command by sending the greeting message
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn start(bot: Throttle<Bot>, msg: Message) -> crate::Result<()> {
|
pub async fn start(bot: Throttle<Bot>, msg: Message, locale: LocaleRef) -> crate::Result<()> {
|
||||||
bot.send_message(
|
bot.send_message(msg.chat.id, locale.start_command.as_ref())
|
||||||
msg.chat.id,
|
|
||||||
"Hi! This bot can be used to store the passwords securely. \
|
|
||||||
Use /help command to get the list of commands",
|
|
||||||
)
|
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,9 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
/// Handles the messages which weren't matched by any commands or states
|
/// Handles the messages which weren't matched by any commands or states
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn default(bot: Throttle<Bot>, msg: Message) -> crate::Result<()> {
|
pub async fn default(bot: Throttle<Bot>, msg: Message, locale: LocaleRef) -> crate::Result<()> {
|
||||||
bot.send_message(
|
bot.send_message(msg.chat.id, locale.unknown_command_use_help.as_ref())
|
||||||
msg.chat.id,
|
.reply_markup(deletion_markup(locale))
|
||||||
"Unknown command. Use /help command to get the list of commands",
|
|
||||||
)
|
|
||||||
.reply_markup(deletion_markup())
|
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,6 @@ pub enum InvalidCommand {
|
|||||||
InvalidOutputLength,
|
InvalidOutputLength,
|
||||||
#[error("Error decoding the values: {0}")]
|
#[error("Error decoding the values: {0}")]
|
||||||
NameDecodingError(#[from] base64::DecodeError),
|
NameDecodingError(#[from] base64::DecodeError),
|
||||||
|
#[error("Unknown locale passed into callback")]
|
||||||
|
UnknownLocale,
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,14 @@ async fn notify_about_no_user_info(
|
|||||||
bot: Throttle<Bot>,
|
bot: Throttle<Bot>,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
state: State,
|
state: State,
|
||||||
|
locale: LocaleRef,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
const TEXT: &str = "Invalid message. Couldn't get the user information. Send the message again";
|
let text = locale.couldnt_get_user_info_send_again.as_ref();
|
||||||
|
|
||||||
match state {
|
match state {
|
||||||
State::Start => {
|
State::Start => {
|
||||||
bot.send_message(msg.chat.id, TEXT)
|
bot.send_message(msg.chat.id, text)
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
State::GetNewName(handler)
|
State::GetNewName(handler)
|
||||||
@ -30,14 +31,14 @@ async fn notify_about_no_user_info(
|
|||||||
let mut handler = handler.lock().await;
|
let mut handler = handler.lock().await;
|
||||||
handler
|
handler
|
||||||
.previous
|
.previous
|
||||||
.alter_message(&bot, TEXT, None, None)
|
.alter_message(&bot, text, None, None)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
State::GetUser(handler) => {
|
State::GetUser(handler) => {
|
||||||
let mut handler = handler.lock().await;
|
let mut handler = handler.lock().await;
|
||||||
handler
|
handler
|
||||||
.previous
|
.previous
|
||||||
.alter_message(&bot, TEXT, None, None)
|
.alter_message(&bot, text, None, None)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
166
src/locales.rs
Normal file
166
src/locales.rs
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use anyhow::Result;
|
||||||
|
use entity::locale::LocaleType;
|
||||||
|
use log::error;
|
||||||
|
use std::future::Future;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
static LOCALES: OnceLock<LocaleStore> = OnceLock::new();
|
||||||
|
|
||||||
|
pub struct LocaleStore {
|
||||||
|
eng: Locale,
|
||||||
|
ru: Locale,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocaleStore {
|
||||||
|
pub fn init() -> Result<()> {
|
||||||
|
let ru = serde_yaml::from_slice(include_bytes!("../locales/ru.yaml"))?;
|
||||||
|
let eng = serde_yaml::from_slice(include_bytes!("../locales/eng.yaml"))?;
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
LOCALES.set(Self { eng, ru }).is_ok(),
|
||||||
|
"Locales are already intialized"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
pub struct Locale {
|
||||||
|
pub master_password_is_not_set: Box<str>,
|
||||||
|
pub hide_button: Box<str>,
|
||||||
|
pub change_name_button: Box<str>,
|
||||||
|
pub change_login_button: Box<str>,
|
||||||
|
pub change_password_button: Box<str>,
|
||||||
|
pub delete_account_button: Box<str>,
|
||||||
|
pub couldnt_get_user_info_send_again: Box<str>,
|
||||||
|
pub unknown_command_use_help: Box<str>,
|
||||||
|
pub help_command: Box<str>,
|
||||||
|
pub no_file_send: Box<str>,
|
||||||
|
pub file_too_large: Box<str>,
|
||||||
|
pub couldnt_get_file_name: Box<str>,
|
||||||
|
pub following_accounts_have_problems: Box<str>,
|
||||||
|
pub duplicate_names: Box<str>,
|
||||||
|
pub accounts_already_in_db: Box<str>,
|
||||||
|
pub invalid_fields: Box<str>,
|
||||||
|
pub fix_that_and_send_again: Box<str>,
|
||||||
|
pub error_downloading_file: Box<str>,
|
||||||
|
pub error_getting_account_names: Box<str>,
|
||||||
|
pub error_parsing_json_file: Box<str>,
|
||||||
|
pub successfully_canceled: Box<str>,
|
||||||
|
pub invalid_password: Box<str>,
|
||||||
|
pub couldnt_get_message_text: Box<str>,
|
||||||
|
pub invalid_file_name: Box<str>,
|
||||||
|
pub account_already_exists: Box<str>,
|
||||||
|
pub master_password_too_weak: Box<str>,
|
||||||
|
pub no_lowercase: Box<str>,
|
||||||
|
pub no_uppercase: Box<str>,
|
||||||
|
pub no_numbers: Box<str>,
|
||||||
|
pub master_pass_too_short: Box<str>,
|
||||||
|
pub change_master_password_and_send_again: Box<str>,
|
||||||
|
pub wrong_master_password: Box<str>,
|
||||||
|
pub invalid_login: Box<str>,
|
||||||
|
pub start_command: Box<str>,
|
||||||
|
pub master_password_dont_match: Box<str>,
|
||||||
|
pub success: Box<str>,
|
||||||
|
pub send_master_password_again: Box<str>,
|
||||||
|
pub master_password_is_set: Box<str>,
|
||||||
|
pub send_new_master_password: Box<str>,
|
||||||
|
pub no_accounts_found: Box<str>,
|
||||||
|
pub choose_account: Box<str>,
|
||||||
|
pub couldnt_create_following_accounts: Box<str>,
|
||||||
|
pub send_master_password: Box<str>,
|
||||||
|
pub something_went_wrong: Box<str>,
|
||||||
|
pub nothing_to_cancel: Box<str>,
|
||||||
|
pub send_account_name: Box<str>,
|
||||||
|
pub send_login: Box<str>,
|
||||||
|
pub error_deleting_message: Box<str>,
|
||||||
|
pub account_not_found: Box<str>,
|
||||||
|
pub send_new_name: Box<str>,
|
||||||
|
pub send_new_login: Box<str>,
|
||||||
|
pub send_new_password: Box<str>,
|
||||||
|
pub success_choose_account_to_view: Box<str>,
|
||||||
|
pub send_json_file: Box<str>,
|
||||||
|
pub send_master_pass_to_delete_everything: Box<str>,
|
||||||
|
pub everything_was_deleted: Box<str>,
|
||||||
|
pub send_password: Box<str>,
|
||||||
|
pub send_master_pass_to_delete_account: Box<str>,
|
||||||
|
pub no_special_characters: Box<str>,
|
||||||
|
pub invalid_name: Box<str>,
|
||||||
|
pub decrypt_button: Box<str>,
|
||||||
|
pub delete_message_button: Box<str>,
|
||||||
|
pub menu_button: Box<str>,
|
||||||
|
pub choose_language: Box<str>,
|
||||||
|
word_name: Box<str>,
|
||||||
|
word_login: Box<str>,
|
||||||
|
word_password: Box<str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Locale {
|
||||||
|
pub async fn from_update(update: Update, db: Pool) -> &'static Self {
|
||||||
|
let locale_type = LocaleType::locale_for_update(&update, &db).await;
|
||||||
|
locale_type.get_locale()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show_account(&self, name: &str, login: &str, password: &str) -> String {
|
||||||
|
format!(
|
||||||
|
"{}:\n`{name}`\n{}:\n`{login}`\n{}:\n`{password}`",
|
||||||
|
self.word_name, self.word_login, self.word_password
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show_hidden_account(&self, name: &str) -> String {
|
||||||
|
format!(
|
||||||
|
"{}:\n`{name}`\n{}:\n\\*\\*\\*\n{}:\n\\*\\*\\*",
|
||||||
|
self.word_name, self.word_login, self.word_password
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type LocaleRef = &'static Locale;
|
||||||
|
|
||||||
|
pub trait LocaleTypeExt: Sized {
|
||||||
|
fn locale_for_update(update: &Update, db: &Pool) -> impl Future<Output = Self> + Send;
|
||||||
|
|
||||||
|
fn from_language_code(code: &str) -> Option<Self>;
|
||||||
|
|
||||||
|
fn get_locale(self) -> &'static Locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocaleTypeExt for LocaleType {
|
||||||
|
async fn locale_for_update(update: &Update, db: &Pool) -> Self {
|
||||||
|
let Some(from) = update.user() else {
|
||||||
|
return Self::default();
|
||||||
|
};
|
||||||
|
|
||||||
|
match Self::get_from_db(from.id.0, db).await {
|
||||||
|
Ok(Some(locale)) => return locale,
|
||||||
|
Ok(None) => (),
|
||||||
|
Err(err) => error!("{err}"),
|
||||||
|
}
|
||||||
|
|
||||||
|
from.language_code
|
||||||
|
.as_deref()
|
||||||
|
.and_then(Self::from_language_code)
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_language_code(code: &str) -> Option<Self> {
|
||||||
|
match code {
|
||||||
|
"ru" => Some(Self::Ru),
|
||||||
|
"en" => Some(Self::Eng),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_locale(self) -> &'static Locale {
|
||||||
|
let Some(store) = LOCALES.get() else {
|
||||||
|
panic!("Locales are not initialized")
|
||||||
|
};
|
||||||
|
match self {
|
||||||
|
Self::Eng => &store.eng,
|
||||||
|
Self::Ru => &store.ru,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ macro_rules! change_state {
|
|||||||
($dialogue: expr, $previous: expr, ($($param: ident),*), $next_state: expr, $next_func: ident) => {{
|
($dialogue: expr, $previous: expr, ($($param: ident),*), $next_state: expr, $next_func: ident) => {{
|
||||||
$dialogue
|
$dialogue
|
||||||
.update($next_state(Handler::new(
|
.update($next_state(Handler::new(
|
||||||
move |bot, msg, db, dialogue, ids, param| Box::pin($next_func(bot, msg, db, dialogue, ids, $($param,)* param)),
|
move |bot, msg, db, dialogue, locale, ids, param| Box::pin($next_func(bot, msg, db, dialogue, locale, ids, $($param,)* param)),
|
||||||
$previous,
|
$previous,
|
||||||
)))
|
)))
|
||||||
.await?;
|
.await?;
|
||||||
@ -12,14 +12,17 @@ macro_rules! change_state {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! first_handler {
|
macro_rules! first_handler {
|
||||||
($function_name: ident, $message: expr, $next_state: expr, $next_func: ident) => {
|
($function_name: ident, $message: ident, $next_state: expr, $next_func: ident) => {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn $function_name(
|
pub async fn $function_name(
|
||||||
bot: Throttle<Bot>,
|
bot: Throttle<Bot>,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
|
locale: LocaleRef,
|
||||||
) -> $crate::Result<()> {
|
) -> $crate::Result<()> {
|
||||||
let previous = bot.send_message(msg.chat.id, $message).await?;
|
let previous = bot
|
||||||
|
.send_message(msg.chat.id, locale.$message.as_ref())
|
||||||
|
.await?;
|
||||||
|
|
||||||
$crate::change_state!(dialogue, &previous, (), $next_state, $next_func);
|
$crate::change_state!(dialogue, &previous, (), $next_state, $next_func);
|
||||||
|
|
||||||
@ -30,7 +33,7 @@ macro_rules! first_handler {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! handler {
|
macro_rules! handler {
|
||||||
($function_name: ident ($($param: ident: $type: ty),*), $message: literal, $next_state: expr, $next_func: ident) => {
|
($function_name: ident ($($param: ident: $type: ty),*), $message: ident, $next_state: expr, $next_func: ident) => {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn $function_name(
|
async fn $function_name(
|
||||||
@ -39,9 +42,10 @@ macro_rules! handler {
|
|||||||
_: Pool,
|
_: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
mut ids: MessageIds,
|
mut ids: MessageIds,
|
||||||
|
locale: LocaleRef,
|
||||||
$($param: $type),*
|
$($param: $type),*
|
||||||
) -> $crate::Result<()> {
|
) -> $crate::Result<()> {
|
||||||
ids.alter_message(&bot, $message, None, None).await?;
|
ids.alter_message(&bot, locale.$message.as_ref(), None, None).await?;
|
||||||
|
|
||||||
$crate::change_state!(dialogue, ids, ($($param),*), $next_state, $next_func);
|
$crate::change_state!(dialogue, ids, ($($param),*), $next_state, $next_func);
|
||||||
|
|
||||||
@ -52,13 +56,14 @@ macro_rules! handler {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! simple_state_handler {
|
macro_rules! simple_state_handler {
|
||||||
($function_name: ident, $check: ident, $no_text_message: literal) => {
|
($function_name: ident, $check: ident) => {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn $function_name(
|
pub async fn $function_name(
|
||||||
bot: Throttle<Bot>,
|
bot: Throttle<Bot>,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
|
locale: LocaleRef,
|
||||||
next: PackagedHandler<String>,
|
next: PackagedHandler<String>,
|
||||||
) -> $crate::Result<()> {
|
) -> $crate::Result<()> {
|
||||||
super::generic::generic(
|
super::generic::generic(
|
||||||
@ -66,8 +71,8 @@ macro_rules! simple_state_handler {
|
|||||||
msg,
|
msg,
|
||||||
db,
|
db,
|
||||||
dialogue,
|
dialogue,
|
||||||
|msg, db, param| Box::pin($check(msg, db, param)),
|
|msg, db, locale, param| Box::pin($check(msg, db, locale, param)),
|
||||||
$no_text_message,
|
locale,
|
||||||
next,
|
next,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
10
src/main.rs
10
src/main.rs
@ -4,6 +4,7 @@ mod default;
|
|||||||
mod delete_mesage_handler;
|
mod delete_mesage_handler;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod filter_user_info;
|
mod filter_user_info;
|
||||||
|
mod locales;
|
||||||
mod macros;
|
mod macros;
|
||||||
mod markups;
|
mod markups;
|
||||||
mod master_password_check;
|
mod master_password_check;
|
||||||
@ -42,7 +43,8 @@ fn get_dispatcher(
|
|||||||
.branch(case![Command::Delete].endpoint(commands::delete))
|
.branch(case![Command::Delete].endpoint(commands::delete))
|
||||||
.branch(case![Command::DeleteAll].endpoint(commands::delete_all))
|
.branch(case![Command::DeleteAll].endpoint(commands::delete_all))
|
||||||
.branch(case![Command::Export].endpoint(commands::export))
|
.branch(case![Command::Export].endpoint(commands::export))
|
||||||
.branch(case![Command::Import].endpoint(commands::import));
|
.branch(case![Command::Import].endpoint(commands::import))
|
||||||
|
.branch(case![Command::ChangeLanguage].endpoint(commands::change_language));
|
||||||
|
|
||||||
let message_handler = Update::filter_message()
|
let message_handler = Update::filter_message()
|
||||||
.map_async(delete_mesage_handler::delete_message)
|
.map_async(delete_mesage_handler::delete_message)
|
||||||
@ -67,9 +69,11 @@ fn get_dispatcher(
|
|||||||
.branch(
|
.branch(
|
||||||
case![CallbackCommand::DeleteAccount { name, is_command }].endpoint(callbacks::delete),
|
case![CallbackCommand::DeleteAccount { name, is_command }].endpoint(callbacks::delete),
|
||||||
)
|
)
|
||||||
.branch(case![CallbackCommand::Alter(hash, field)].endpoint(callbacks::alter));
|
.branch(case![CallbackCommand::Alter(hash, field)].endpoint(callbacks::alter))
|
||||||
|
.branch(case![CallbackCommand::ChangeLocale(locale)].endpoint(callbacks::change_locale));
|
||||||
|
|
||||||
let handler = dptree::entry()
|
let handler = dptree::entry()
|
||||||
|
.map_async(Locale::from_update)
|
||||||
.enter_dialogue::<Update, InMemStorage<State>, State>()
|
.enter_dialogue::<Update, InMemStorage<State>, State>()
|
||||||
.branch(message_handler)
|
.branch(message_handler)
|
||||||
.branch(callback_handler);
|
.branch(callback_handler);
|
||||||
@ -85,6 +89,8 @@ async fn main() -> Result<()> {
|
|||||||
let _ = dotenv();
|
let _ = dotenv();
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
|
||||||
|
locales::LocaleStore::init()?;
|
||||||
|
|
||||||
let token = env::var("TOKEN").expect("expected TOKEN in the enviroment");
|
let token = env::var("TOKEN").expect("expected TOKEN in the enviroment");
|
||||||
let database_url = env::var("DATABASE_URL").expect("expected DATABASE_URL in the enviroment");
|
let database_url = env::var("DATABASE_URL").expect("expected DATABASE_URL in the enviroment");
|
||||||
let pool = Pool::connect(&database_url).await?;
|
let pool = Pool::connect(&database_url).await?;
|
||||||
|
@ -40,16 +40,16 @@ pub async fn menu_markup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn make_button(text: &str, command: &str, hash: &str) -> InlineKeyboardButton {
|
fn make_button(text: &str, command: &str, param: &str) -> InlineKeyboardButton {
|
||||||
let mut data = command.to_owned();
|
let mut data = command.to_owned();
|
||||||
data.reserve(44);
|
data.reserve(param.len() + 1);
|
||||||
data.push(' ');
|
data.push(' ');
|
||||||
data.push_str(hash);
|
data.push_str(param);
|
||||||
InlineKeyboardButton::callback(text, data)
|
InlineKeyboardButton::callback(text, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn account_markup(name: &str, is_encrypted: bool) -> InlineKeyboardMarkup {
|
pub fn account_markup(name: &str, is_encrypted: bool, locale: LocaleRef) -> InlineKeyboardMarkup {
|
||||||
let mut hash = [0; 43];
|
let mut hash = [0; 43];
|
||||||
B64_ENGINE
|
B64_ENGINE
|
||||||
.encode_slice(<Sha256 as Digest>::digest(name), &mut hash)
|
.encode_slice(<Sha256 as Digest>::digest(name), &mut hash)
|
||||||
@ -57,31 +57,41 @@ pub fn account_markup(name: &str, is_encrypted: bool) -> InlineKeyboardMarkup {
|
|||||||
let hash = std::str::from_utf8(&hash).unwrap();
|
let hash = std::str::from_utf8(&hash).unwrap();
|
||||||
|
|
||||||
let encryption_button = if is_encrypted {
|
let encryption_button = if is_encrypted {
|
||||||
("Decrypt", "decrypt")
|
(locale.decrypt_button.as_ref(), "decrypt")
|
||||||
} else {
|
} else {
|
||||||
("Hide", "get")
|
(locale.hide_button.as_ref(), "get")
|
||||||
};
|
};
|
||||||
|
|
||||||
let main_buttons = [
|
let main_buttons = [
|
||||||
("Alter name", "an"),
|
(locale.change_name_button.as_ref(), "an"),
|
||||||
("Alter login", "al"),
|
(locale.change_login_button.as_ref(), "al"),
|
||||||
("Alter password", "ap"),
|
(locale.change_password_button.as_ref(), "ap"),
|
||||||
encryption_button,
|
encryption_button,
|
||||||
("Delete account", "delete0"),
|
(locale.delete_account_button.as_ref(), "delete0"),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(text, command)| make_button(text, command, hash))
|
.map(|(text, command)| make_button(text, command, hash))
|
||||||
.chunks(3);
|
.chunks(3);
|
||||||
|
|
||||||
let menu_button = InlineKeyboardButton::callback("Back to the menu", "get_menu");
|
let menu_button = InlineKeyboardButton::callback(locale.menu_button.as_ref(), "get_menu");
|
||||||
|
|
||||||
InlineKeyboardMarkup::new(&main_buttons).append_row([menu_button])
|
InlineKeyboardMarkup::new(&main_buttons).append_row([menu_button])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn language_markup() -> InlineKeyboardMarkup {
|
||||||
|
let languages = [("🇷🇺 Русский", "ru"), ("🇬🇧 English", "en")]
|
||||||
|
.into_iter()
|
||||||
|
.map(|(text, param)| make_button(text, "change_locale", param))
|
||||||
|
.chunks(3);
|
||||||
|
InlineKeyboardMarkup::new(&languages)
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a markup with a "Delete message" button.
|
/// Creates a markup with a "Delete message" button.
|
||||||
/// This markup should be added for all messages that won't be deleted afterwards
|
/// This markup should be added for all messages that won't be deleted afterwards
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn deletion_markup() -> InlineKeyboardMarkup {
|
pub fn deletion_markup(locale: LocaleRef) -> InlineKeyboardMarkup {
|
||||||
let button = InlineKeyboardButton::callback("Delete message", "delete_message");
|
let button =
|
||||||
|
InlineKeyboardButton::callback(locale.delete_message_button.as_ref(), "delete_message");
|
||||||
InlineKeyboardMarkup::new([[button]])
|
InlineKeyboardMarkup::new([[button]])
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ async fn master_pass_exists(update: Update, db: Pool) -> Option<Option<DynError>
|
|||||||
#[inline]
|
#[inline]
|
||||||
async fn notify_about_no_master_pass(
|
async fn notify_about_no_master_pass(
|
||||||
bot: Throttle<Bot>,
|
bot: Throttle<Bot>,
|
||||||
|
locale: LocaleRef,
|
||||||
result: Option<DynError>,
|
result: Option<DynError>,
|
||||||
update: Update,
|
update: Update,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
@ -37,9 +38,9 @@ async fn notify_about_no_master_pass(
|
|||||||
}
|
}
|
||||||
bot.send_message(
|
bot.send_message(
|
||||||
update.chat_id().unwrap(),
|
update.chat_id().unwrap(),
|
||||||
"No master password set. Use /set_master_pass to set it",
|
locale.master_password_is_not_set.as_ref(),
|
||||||
)
|
)
|
||||||
.reply_markup(deletion_markup())
|
.reply_markup(deletion_markup(locale))
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ pub use crate::{
|
|||||||
commands::Command,
|
commands::Command,
|
||||||
errors::*,
|
errors::*,
|
||||||
first_handler, handler,
|
first_handler, handler,
|
||||||
|
locales::{Locale, LocaleRef},
|
||||||
markups::*,
|
markups::*,
|
||||||
models::*,
|
models::*,
|
||||||
state::{Handler, MainDialogue, MessageIds, PackagedHandler, State},
|
state::{Handler, MainDialogue, MessageIds, PackagedHandler, State},
|
||||||
|
@ -9,11 +9,16 @@ pub async fn generic<F>(
|
|||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
check: F,
|
check: F,
|
||||||
no_text_message: impl Into<String> + Send,
|
locale: LocaleRef,
|
||||||
handler: PackagedHandler<String>,
|
handler: PackagedHandler<String>,
|
||||||
) -> crate::Result<()>
|
) -> crate::Result<()>
|
||||||
where
|
where
|
||||||
for<'a> F: FnOnce(&'a Message, &'a Pool, &'a str) -> BoxFuture<'a, crate::Result<Option<String>>>
|
for<'a> F: FnOnce(
|
||||||
|
&'a Message,
|
||||||
|
&'a Pool,
|
||||||
|
LocaleRef,
|
||||||
|
&'a str,
|
||||||
|
) -> BoxFuture<'a, crate::Result<Option<String>>>
|
||||||
+ Send,
|
+ Send,
|
||||||
{
|
{
|
||||||
let mut handler = handler.lock().await;
|
let mut handler = handler.lock().await;
|
||||||
@ -25,7 +30,7 @@ where
|
|||||||
let Some(text) = msg.text().map(str::trim) else {
|
let Some(text) = msg.text().map(str::trim) else {
|
||||||
handler
|
handler
|
||||||
.previous
|
.previous
|
||||||
.alter_message(&bot, no_text_message, None, None)
|
.alter_message(&bot, locale.couldnt_get_message_text.as_ref(), None, None)
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
@ -34,12 +39,17 @@ where
|
|||||||
dialogue.exit().await?;
|
dialogue.exit().await?;
|
||||||
handler
|
handler
|
||||||
.previous
|
.previous
|
||||||
.alter_message(&bot, "Successfully cancelled", deletion_markup(), None)
|
.alter_message(
|
||||||
|
&bot,
|
||||||
|
locale.successfully_canceled.as_ref(),
|
||||||
|
deletion_markup(locale),
|
||||||
|
None,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(text) = check(&msg, &db, text).await? {
|
if let Some(text) = check(&msg, &db, locale, text).await? {
|
||||||
handler
|
handler
|
||||||
.previous
|
.previous
|
||||||
.alter_message(&bot, text, None, None)
|
.alter_message(&bot, text, None, None)
|
||||||
@ -52,7 +62,7 @@ where
|
|||||||
drop(handler);
|
drop(handler);
|
||||||
let text = text.to_owned();
|
let text = text.to_owned();
|
||||||
|
|
||||||
if let Err(err) = func(bot, msg, db, dialogue.clone(), previous, text).await {
|
if let Err(err) = func(bot, msg, db, dialogue.clone(), previous, locale, text).await {
|
||||||
let _ = dialogue.exit().await;
|
let _ = dialogue.exit().await;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn check_login(_: &Message, _: &Pool, login: &str) -> crate::Result<Option<String>> {
|
async fn check_login(
|
||||||
|
_: &Message,
|
||||||
|
_: &Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
|
login: &str,
|
||||||
|
) -> crate::Result<Option<String>> {
|
||||||
let is_valid = validate_field(login);
|
let is_valid = validate_field(login);
|
||||||
if !is_valid {
|
if !is_valid {
|
||||||
return Ok(Some("Invalid login. Try again".to_owned()));
|
return Ok(Some(locale.invalid_login.as_ref().into()));
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::simple_state_handler!(
|
crate::simple_state_handler!(get_login, check_login);
|
||||||
get_login,
|
|
||||||
check_login,
|
|
||||||
"Couldn't get the text of the message. Send the login again"
|
|
||||||
);
|
|
||||||
|
@ -8,14 +8,13 @@ use tokio::task::spawn_blocking;
|
|||||||
async fn check_master_pass(
|
async fn check_master_pass(
|
||||||
msg: &Message,
|
msg: &Message,
|
||||||
db: &Pool,
|
db: &Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
master_pass: &str,
|
master_pass: &str,
|
||||||
) -> crate::Result<Option<String>> {
|
) -> crate::Result<Option<String>> {
|
||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
||||||
let Some(model) = MasterPass::get(user_id, db).await? else {
|
let Some(model) = MasterPass::get(user_id, db).await? else {
|
||||||
error!("User was put into the GetMasterPass state with no master password set");
|
error!("User was put into the GetMasterPass state with no master password set");
|
||||||
return Ok(Some(
|
return Ok(Some(locale.master_password_is_not_set.as_ref().into()));
|
||||||
"No master password set. Use /cancel and set it by using /set_master_pass".to_owned(),
|
|
||||||
));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_valid = {
|
let is_valid = {
|
||||||
@ -25,13 +24,9 @@ async fn check_master_pass(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !is_valid {
|
if !is_valid {
|
||||||
return Ok(Some("Wrong master password. Try again".to_owned()));
|
return Ok(Some(locale.wrong_master_password.as_ref().into()));
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::simple_state_handler!(
|
crate::simple_state_handler!(get_master_pass, check_master_pass);
|
||||||
get_master_pass,
|
|
||||||
check_master_pass,
|
|
||||||
"Couldn't get the text of the message. Send the master password again"
|
|
||||||
);
|
|
||||||
|
@ -1,31 +1,32 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use cryptography::passwords::{check_master_pass, PasswordValidity};
|
use cryptography::passwords::{check_master_pass, PasswordValidity};
|
||||||
|
use std::fmt::Write as _;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn process_validity(validity: PasswordValidity) -> Result<(), String> {
|
fn process_validity(validity: PasswordValidity, locale: LocaleRef) -> Result<(), String> {
|
||||||
if validity.is_empty() {
|
if validity.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut error_text = "Your master password is invalid:\n".to_owned();
|
let mut error_text = locale.master_password_too_weak.as_ref().to_owned();
|
||||||
|
|
||||||
if validity.contains(PasswordValidity::NO_LOWERCASE) {
|
if validity.contains(PasswordValidity::NO_LOWERCASE) {
|
||||||
error_text.push_str("\n* It doesn't have any lowercase characters");
|
write!(error_text, "\n* {}", locale.no_lowercase).unwrap();
|
||||||
}
|
}
|
||||||
if validity.contains(PasswordValidity::NO_UPPERCASE) {
|
if validity.contains(PasswordValidity::NO_UPPERCASE) {
|
||||||
error_text.push_str("\n* It doesn't have any uppercase characters");
|
write!(error_text, "\n* {}", locale.no_uppercase).unwrap();
|
||||||
}
|
}
|
||||||
if validity.contains(PasswordValidity::NO_NUMBER) {
|
if validity.contains(PasswordValidity::NO_NUMBER) {
|
||||||
error_text.push_str("\n* It doesn't have any numbers");
|
write!(error_text, "\n* {}", locale.no_numbers).unwrap();
|
||||||
}
|
}
|
||||||
if validity.contains(PasswordValidity::NO_SPECIAL_CHARACTER) {
|
if validity.contains(PasswordValidity::NO_SPECIAL_CHARACTER) {
|
||||||
error_text.push_str("\n* It doesn't have any special characters");
|
write!(error_text, "\n* {}", locale.no_special_characters).unwrap();
|
||||||
}
|
}
|
||||||
if validity.contains(PasswordValidity::TOO_SHORT) {
|
if validity.contains(PasswordValidity::TOO_SHORT) {
|
||||||
error_text.push_str("\n* It is shorter than 8 characters");
|
write!(error_text, "\n* {}", locale.master_pass_too_short).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
error_text.push_str("\n\nModify your password and send it again");
|
error_text.push_str(&locale.change_master_password_and_send_again);
|
||||||
|
|
||||||
Err(error_text)
|
Err(error_text)
|
||||||
}
|
}
|
||||||
@ -35,15 +36,12 @@ fn process_validity(validity: PasswordValidity) -> Result<(), String> {
|
|||||||
async fn check_new_master_pass(
|
async fn check_new_master_pass(
|
||||||
_: &Message,
|
_: &Message,
|
||||||
_: &Pool,
|
_: &Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
password: &str,
|
password: &str,
|
||||||
) -> crate::Result<Option<String>> {
|
) -> crate::Result<Option<String>> {
|
||||||
let validity = check_master_pass(password);
|
let validity = check_master_pass(password);
|
||||||
|
|
||||||
Ok(process_validity(validity).err())
|
Ok(process_validity(validity, locale).err())
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::simple_state_handler!(
|
crate::simple_state_handler!(get_new_master_pass, check_new_master_pass);
|
||||||
get_new_master_pass,
|
|
||||||
check_new_master_pass,
|
|
||||||
"Couldn't get the text of the message. Send the master password again"
|
|
||||||
);
|
|
||||||
|
@ -5,21 +5,18 @@ use crate::prelude::*;
|
|||||||
async fn check_new_account_name(
|
async fn check_new_account_name(
|
||||||
msg: &Message,
|
msg: &Message,
|
||||||
db: &Pool,
|
db: &Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> crate::Result<Option<String>> {
|
) -> crate::Result<Option<String>> {
|
||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
||||||
|
|
||||||
if Account::exists(user_id, name, db).await? {
|
if Account::exists(user_id, name, db).await? {
|
||||||
Ok(Some("Account already exists".to_owned()))
|
Ok(Some(locale.account_already_exists.as_ref().into()))
|
||||||
} else if !validate_field(name) {
|
} else if !validate_field(name) {
|
||||||
Ok(Some("Invalid account name. Try again".to_owned()))
|
Ok(Some(locale.invalid_name.as_ref().into()))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::simple_state_handler!(
|
crate::simple_state_handler!(get_new_name, check_new_account_name);
|
||||||
get_new_name,
|
|
||||||
check_new_account_name,
|
|
||||||
"Couldn't get the text of the message. Send the name of the new account again"
|
|
||||||
);
|
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn check_password(_: &Message, _: &Pool, password: &str) -> crate::Result<Option<String>> {
|
async fn check_password(
|
||||||
|
_: &Message,
|
||||||
|
_: &Pool,
|
||||||
|
locale: LocaleRef,
|
||||||
|
password: &str,
|
||||||
|
) -> crate::Result<Option<String>> {
|
||||||
let is_valid = validate_field(password);
|
let is_valid = validate_field(password);
|
||||||
if !is_valid {
|
if !is_valid {
|
||||||
return Ok(Some("Invalid password. Try again".to_owned()));
|
return Ok(Some(locale.invalid_password.as_ref().into()));
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::simple_state_handler!(
|
crate::simple_state_handler!(get_password, check_password);
|
||||||
get_password,
|
|
||||||
check_password,
|
|
||||||
"Couldn't get the text of the message. Send the password again"
|
|
||||||
);
|
|
||||||
|
@ -9,24 +9,43 @@ use teloxide::{
|
|||||||
use tokio::{task::spawn_blocking, try_join};
|
use tokio::{task::spawn_blocking, try_join};
|
||||||
use trim_in_place::TrimInPlace;
|
use trim_in_place::TrimInPlace;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum InvalidDocument {
|
||||||
|
NoFileSend,
|
||||||
|
FileTooLarge,
|
||||||
|
CouldntGetFileName,
|
||||||
|
InvalidFileName,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InvalidDocument {
|
||||||
|
const fn into_str(self, locale: LocaleRef) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::NoFileSend => &locale.no_file_send,
|
||||||
|
Self::FileTooLarge => &locale.file_too_large,
|
||||||
|
Self::CouldntGetFileName => &locale.couldnt_get_file_name,
|
||||||
|
Self::InvalidFileName => &locale.invalid_file_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn validate_document(document: Option<&Document>) -> Result<&Document, &'static str> {
|
fn validate_document(document: Option<&Document>) -> Result<&Document, InvalidDocument> {
|
||||||
let Some(document) = document else {
|
let Some(document) = document else {
|
||||||
return Err("You didn't send a file. Try again");
|
return Err(InvalidDocument::NoFileSend);
|
||||||
};
|
};
|
||||||
|
|
||||||
if document.file.size > 1024 * 1024 * 200 {
|
if document.file.size > 1024 * 1024 * 200 {
|
||||||
return Err("The file is larger than 200 MiB. Try splitting it into multiple files");
|
return Err(InvalidDocument::FileTooLarge);
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = match document.file_name.as_deref() {
|
let name = match document.file_name.as_deref() {
|
||||||
Some(name) => Path::new(name.trim_end()),
|
Some(name) => Path::new(name.trim_end()),
|
||||||
None => return Err("Couldn't get the name of the file. Try sending it again"),
|
None => return Err(InvalidDocument::CouldntGetFileName),
|
||||||
};
|
};
|
||||||
|
|
||||||
match name.extension() {
|
match name.extension() {
|
||||||
Some(ext) if ext.eq_ignore_ascii_case("json") => Ok(document),
|
Some(ext) if ext.eq_ignore_ascii_case("json") => Ok(document),
|
||||||
_ => Err("Invalid file name. You need to send a json file. Try again"),
|
_ => Err(InvalidDocument::InvalidFileName),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +64,7 @@ async fn download_file(bot: &Throttle<Bot>, file: &FileMeta) -> crate::Result<Bo
|
|||||||
fn process_accounts(
|
fn process_accounts(
|
||||||
accounts: &mut [DecryptedAccount],
|
accounts: &mut [DecryptedAccount],
|
||||||
existing_names: ahash::HashSet<String>,
|
existing_names: ahash::HashSet<String>,
|
||||||
|
locale: LocaleRef,
|
||||||
) -> crate::Result<Result<(), String>> {
|
) -> crate::Result<Result<(), String>> {
|
||||||
for account in accounts.iter_mut() {
|
for account in accounts.iter_mut() {
|
||||||
account.name.trim_in_place();
|
account.name.trim_in_place();
|
||||||
@ -82,12 +102,13 @@ fn process_accounts(
|
|||||||
return Ok(Ok(()));
|
return Ok(Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut error_text = "Your accounts have the following problems:".to_owned();
|
let mut error_text = locale.following_accounts_have_problems.as_ref().to_owned();
|
||||||
|
|
||||||
if !duplicates.is_empty() {
|
if !duplicates.is_empty() {
|
||||||
write!(
|
write!(
|
||||||
error_text,
|
error_text,
|
||||||
"\n\nDuplicate names:\n{:?}",
|
"\n\n{}:\n{:?}",
|
||||||
|
locale.duplicate_names,
|
||||||
duplicates.into_iter().format("\n")
|
duplicates.into_iter().format("\n")
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -95,7 +116,8 @@ fn process_accounts(
|
|||||||
if !existing.is_empty() {
|
if !existing.is_empty() {
|
||||||
write!(
|
write!(
|
||||||
error_text,
|
error_text,
|
||||||
"\n\nAccounts with these names already exist in the database:\n{:?}",
|
"\n\n{}:\n{:?}",
|
||||||
|
locale.accounts_already_in_db,
|
||||||
existing.into_iter().format("\n")
|
existing.into_iter().format("\n")
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -103,12 +125,13 @@ fn process_accounts(
|
|||||||
if !invalid.is_empty() {
|
if !invalid.is_empty() {
|
||||||
write!(
|
write!(
|
||||||
error_text,
|
error_text,
|
||||||
"\n\nInvalid account fields:\n{:?}",
|
"\n\n{}:\n{:?}",
|
||||||
|
locale.invalid_fields,
|
||||||
invalid.into_iter().format("\n")
|
invalid.into_iter().format("\n")
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_text.push_str("\n\nFix these problems and send the file again");
|
error_text.push_str(&locale.fix_that_and_send_again);
|
||||||
|
|
||||||
Ok(Err(error_text))
|
Ok(Err(error_text))
|
||||||
}
|
}
|
||||||
@ -117,10 +140,11 @@ fn process_accounts(
|
|||||||
fn user_from_bytes(
|
fn user_from_bytes(
|
||||||
bytes: impl AsRef<[u8]>,
|
bytes: impl AsRef<[u8]>,
|
||||||
existing_names: ahash::HashSet<String>,
|
existing_names: ahash::HashSet<String>,
|
||||||
|
locale: LocaleRef,
|
||||||
) -> crate::Result<Result<User, String>> {
|
) -> crate::Result<Result<User, String>> {
|
||||||
let mut user: User = serde_json::from_slice(bytes.as_ref())?;
|
let mut user: User = serde_json::from_slice(bytes.as_ref())?;
|
||||||
drop(bytes);
|
drop(bytes);
|
||||||
match process_accounts(&mut user.accounts, existing_names)? {
|
match process_accounts(&mut user.accounts, existing_names, locale)? {
|
||||||
Ok(()) => Ok(Ok(user)),
|
Ok(()) => Ok(Ok(user)),
|
||||||
Err(error_text) => Ok(Err(error_text)),
|
Err(error_text) => Ok(Err(error_text)),
|
||||||
}
|
}
|
||||||
@ -132,21 +156,24 @@ async fn user_from_document(
|
|||||||
db: &Pool,
|
db: &Pool,
|
||||||
document: Option<&Document>,
|
document: Option<&Document>,
|
||||||
user_id: u64,
|
user_id: u64,
|
||||||
|
locale: LocaleRef,
|
||||||
) -> Result<User, Cow<'static, str>> {
|
) -> Result<User, Cow<'static, str>> {
|
||||||
let (data, existing_names) = {
|
let (data, existing_names) = {
|
||||||
let file = &validate_document(document)?.file;
|
let file = &validate_document(document)
|
||||||
let data = download_file(bot, file).map_err(|_| "Error downloading the file. Try again");
|
.map_err(|err| err.into_str(locale))?
|
||||||
|
.file;
|
||||||
|
let data = download_file(bot, file).map_err(|_| locale.error_downloading_file.as_ref());
|
||||||
|
|
||||||
let existing_names = Account::get_names(user_id, db)
|
let existing_names = Account::get_names(user_id, db)
|
||||||
.try_collect()
|
.try_collect()
|
||||||
.map_err(|_| "Error getting existing account names. Try again");
|
.map_err(|_| locale.error_getting_account_names.as_ref());
|
||||||
|
|
||||||
try_join!(data, existing_names)?
|
try_join!(data, existing_names)?
|
||||||
};
|
};
|
||||||
|
|
||||||
match spawn_blocking(|| user_from_bytes(data, existing_names)).await {
|
match spawn_blocking(|| user_from_bytes(data, existing_names, locale)).await {
|
||||||
Ok(Ok(user)) => user.map_err(Cow::Owned),
|
Ok(Ok(user)) => user.map_err(Cow::Owned),
|
||||||
_ => Err(Cow::Borrowed("Error parsing the json file. Try again")),
|
_ => Err(Cow::Borrowed(&locale.error_parsing_json_file)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +184,7 @@ pub async fn get_user(
|
|||||||
msg: Message,
|
msg: Message,
|
||||||
db: Pool,
|
db: Pool,
|
||||||
dialogue: MainDialogue,
|
dialogue: MainDialogue,
|
||||||
|
locale: LocaleRef,
|
||||||
handler: PackagedHandler<User>,
|
handler: PackagedHandler<User>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
|
||||||
@ -171,12 +199,17 @@ pub async fn get_user(
|
|||||||
dialogue.exit().await?;
|
dialogue.exit().await?;
|
||||||
handler
|
handler
|
||||||
.previous
|
.previous
|
||||||
.alter_message(&bot, "Successfully cancelled", deletion_markup(), None)
|
.alter_message(
|
||||||
|
&bot,
|
||||||
|
locale.successfully_canceled.as_ref(),
|
||||||
|
deletion_markup(locale),
|
||||||
|
None,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let user = match user_from_document(&bot, &db, msg.document(), user_id).await {
|
let user = match user_from_document(&bot, &db, msg.document(), user_id, locale).await {
|
||||||
Ok(user) => user,
|
Ok(user) => user,
|
||||||
Err(error_text) => {
|
Err(error_text) => {
|
||||||
handler
|
handler
|
||||||
@ -191,7 +224,7 @@ pub async fn get_user(
|
|||||||
let func = handler.func.take().unwrap();
|
let func = handler.func.take().unwrap();
|
||||||
drop(handler);
|
drop(handler);
|
||||||
|
|
||||||
if let Err(err) = func(bot, msg, db, dialogue.clone(), previous, user).await {
|
if let Err(err) = func(bot, msg, db, dialogue.clone(), previous, locale, user).await {
|
||||||
let _ = dialogue.exit().await;
|
let _ = dialogue.exit().await;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ type DynHanlder<T> = Box<
|
|||||||
Pool,
|
Pool,
|
||||||
MainDialogue,
|
MainDialogue,
|
||||||
MessageIds,
|
MessageIds,
|
||||||
|
LocaleRef,
|
||||||
T,
|
T,
|
||||||
) -> BoxFuture<'static, crate::Result<()>>
|
) -> BoxFuture<'static, crate::Result<()>>
|
||||||
+ Send,
|
+ Send,
|
||||||
@ -92,6 +93,7 @@ impl<T> Handler<T> {
|
|||||||
Pool,
|
Pool,
|
||||||
MainDialogue,
|
MainDialogue,
|
||||||
MessageIds,
|
MessageIds,
|
||||||
|
LocaleRef,
|
||||||
T,
|
T,
|
||||||
) -> BoxFuture<'static, crate::Result<()>>
|
) -> BoxFuture<'static, crate::Result<()>>
|
||||||
+ Send
|
+ Send
|
||||||
|
Loading…
Reference in New Issue
Block a user