From a233c3bcd0a4e839c768f1d08b61fa53c9ecb4b9 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sat, 20 Jan 2024 03:48:05 +0100 Subject: [PATCH 01/41] Update some easy deps --- crates/teloxide/Cargo.toml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/crates/teloxide/Cargo.toml b/crates/teloxide/Cargo.toml index 8286a3a7..bf698114 100644 --- a/crates/teloxide/Cargo.toml +++ b/crates/teloxide/Cargo.toml @@ -23,7 +23,11 @@ default = ["native-tls", "ctrlc_handler", "teloxide-core/default", "auto-send"] webhooks = ["rand"] webhooks-axum = ["webhooks", "axum", "tower", "tower-http"] -sqlite-storage-nativetls = ["sqlx", "sqlx/runtime-tokio-native-tls", "native-tls"] +sqlite-storage-nativetls = [ + "sqlx", + "sqlx/runtime-tokio-native-tls", + "native-tls", +] sqlite-storage-rustls = ["sqlx", "sqlx/runtime-tokio-rustls", "rustls"] redis-storage = ["redis"] cbor-serializer = ["serde_cbor"] @@ -94,15 +98,15 @@ derive_more = "0.99" thiserror = "1.0" futures = "0.3.15" pin-project = "1.0" -serde_with_macros = "1.4" -aquamarine = "0.1.11" +serde_with_macros = "3.4" +aquamarine = "0.5.0" either = "1.9.0" sqlx = { version = "0.7.3", optional = true, default-features = false, features = [ "macros", "sqlite", ] } -redis = { version = "0.21", features = ["tokio-comp"], optional = true } +redis = { version = "0.24", features = ["tokio-comp"], optional = true } serde_cbor = { version = "0.11", optional = true } bincode = { version = "1.3", optional = true } axum = { version = "0.6.0", optional = true } @@ -113,7 +117,7 @@ rand = { version = "0.8.5", optional = true } [dev-dependencies] rand = "0.8.3" -pretty_env_logger = "0.4.0" +pretty_env_logger = "0.5.0" serde = "1" serde_json = "1" tokio = { version = "1.8", features = ["fs", "rt-multi-thread", "macros"] } @@ -146,7 +150,11 @@ required-features = ["redis-storage", "cbor-serializer", "bincode-serializer"] [[test]] name = "sqlite" path = "tests/sqlite.rs" -required-features = ["sqlite-storage-nativetls", "cbor-serializer", "bincode-serializer"] +required-features = [ + "sqlite-storage-nativetls", + "cbor-serializer", + "bincode-serializer", +] [[example]] From 0e3ffc7e774e0007718f615fa0da9897d4f8818c Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 21 Jan 2024 17:58:13 +0100 Subject: [PATCH 02/41] Fix `cargo docs` and use `--cfg docsrs` in CI --- .cargo/config.toml | 10 +++++++++- .github/workflows/ci.yml | 2 +- crates/teloxide/Cargo.toml | 1 - 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 8fe98bda..995e7435 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,6 +3,8 @@ # https://github.com/rust-lang/cargo/issues/10333 # # "tokio/macros" and "tokio/rt-multi-thread" are required for examples +# +# N.B.: when changing this, also change `package.metadata.docs.rs` docs = """doc -Zrustdoc-scrape-examples --features=full --features=nightly @@ -11,4 +13,10 @@ docs = """doc [build] # We pass "--cfg docsrs" when building docs to add `This is supported on feature="..." only.` -rustdocflags = ["--cfg", "docsrs", "-Znormalize-docs"] +# +# FIXME: add back `-Znormalize-docs` once is fixed +# or we don't depend on `generic-array` anymore +# +# N.B.: when changing this, also change `RUSTDOCFLAGS` in `.github/workflows/ci.yml` and +# `package.metadata.docs.rs.rustdoc-args` in `crates/teloxide/Cargo.toml` +rustdocflags = ["--cfg", "docsrs"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d6d70fa..a3f20a57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ name: Continuous integration env: RUSTFLAGS: "--cfg CI_REDIS -Dwarnings" - RUSTDOCFLAGS: -Dwarnings + RUSTDOCFLAGS: "--cfg docsrs -Dwarnings" RUST_BACKTRACE: short CARGO_INCREMENTAL: 0 diff --git a/crates/teloxide/Cargo.toml b/crates/teloxide/Cargo.toml index bf698114..c3e445c5 100644 --- a/crates/teloxide/Cargo.toml +++ b/crates/teloxide/Cargo.toml @@ -129,7 +129,6 @@ tokio-stream = "0.1" [package.metadata.docs.rs] # NB: can't use `all-features = true`, because `sqlite-storage-nativetls` conflicts with `sqlite-storage-rustls` features = ["full", "nightly"] -# FIXME: Add back "-Znormalize-docs" when https://github.com/rust-lang/rust/issues/93703 is fixed rustdoc-args = ["--cfg", "docsrs"] rustc-args = ["--cfg", "dep_docsrs"] cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] From f09fc36b2e26be5be1abc0c8c89767bf1ccc01de Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 21 Jan 2024 17:58:48 +0100 Subject: [PATCH 03/41] Improve docs for `distribution_function` --- crates/teloxide/src/dispatching/dispatcher.rs | 64 +++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/crates/teloxide/src/dispatching/dispatcher.rs b/crates/teloxide/src/dispatching/dispatcher.rs index 91db674a..b5403423 100644 --- a/crates/teloxide/src/dispatching/dispatcher.rs +++ b/crates/teloxide/src/dispatching/dispatcher.rs @@ -106,6 +106,59 @@ where /// Specifies the distribution function that decides how updates are grouped /// before execution. + /// + /// ## Update grouping + /// + /// When [`Dispatcher`] receives updates, it runs dispatching tree + /// (handlers) concurrently. This means that multiple updates can be + /// processed at the same time. + /// + /// However, this is not always convenient. For example, if you have global + /// state, then you may want to process some updates sequentially, to + /// prevent state inconsistencies. + /// + /// This is why `teloxide` allows grouping updates. Updates for which the + /// distribution function `f` returns the same "distribution key" `K` will + /// be run in sequence (while still being processed concurrently with the + /// updates with different distribution keys). + /// + /// Updates for which `f` returns `None` will always be processed in + /// parallel. + /// + /// ## Default distribution function + /// + /// By default the distribution function is equivalent to `|upd| + /// upd.chat().map(|chat| chat.id)`, so updates from the same chat will be + /// processed sequentially. + /// + /// This pair nicely with dialogue system, which has state attached to + /// chats. + /// + /// ## Examples + /// + /// Grouping updates by user who caused this update to happen: + /// + /// ``` + /// use teloxide::{dispatching::Dispatcher, dptree, Bot}; + /// + /// let bot = Bot::new("TOKEN"); + /// let handler = dptree::entry() /* ... */; + /// let dp = Dispatcher::builder(bot, handler) + /// .distribution_function(|upd| upd.from().map(|user| user.id)) + /// .build(); + /// # let _: Dispatcher<_, (), _> = dp; + /// ``` + /// + /// Not grouping updates at all, always processing updates concurrently: + /// + /// ``` + /// use teloxide::{dispatching::Dispatcher, dptree, Bot}; + /// + /// let bot = Bot::new("TOKEN"); + /// let handler = dptree::entry() /* ... */; + /// let dp = Dispatcher::builder(bot, handler).distribution_function(|_| None::<()>).build(); + /// # let _: Dispatcher<_, (), _> = dp; + /// ``` #[must_use] pub fn distribution_function( self, @@ -184,10 +237,13 @@ where /// The base for update dispatching. /// -/// Updates from different chats are handled concurrently, whereas updates from -/// the same chats are handled sequentially. If the dispatcher is unable to -/// determine a chat ID of an incoming update, it will be handled concurrently. -/// Note that this behaviour can be altered with [`distribution_function`]. +/// ## Update grouping +/// +/// `Dispatcher` generally processes updates concurrently. However, by default, +/// updates from the same chat are processed sequentially. [Learn more about +/// update grouping]. +/// +/// [update grouping]: distribution_function#update-grouping /// /// See also: ["Dispatching or /// REPLs?"](../dispatching/index.html#dispatching-or-repls) From d2a9db3b803649ce9ca7f24830ebc6d99051bc2e Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 21 Jan 2024 19:09:11 +0100 Subject: [PATCH 04/41] Update contributing guidelines --- CONTRIBUTING.md | 112 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5fdbfd2f..c205850e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,109 @@ # Contributing -Before contributing, please read [our code style](https://github.com/teloxide/teloxide/blob/master/CODE_STYLE.md) and [the license](https://github.com/teloxide/teloxide/blob/master/LICENSE). +Before contributing, please read [our code style](./CODE_STYLE.md) and [the license](./LICENSE). -To change the source code, fork the `master` branch of this repository and work inside your own branch. Then send us a PR into `master` branch and wait for the CI to check everything. However, you'd better check changes first locally: +> **Note** +> +> These contributing instructions might not be fully up-to-date or complete. +> However, they should be a good starting point. +> +> If you find inaccuracies / missing things, please expand this or contact us. -``` -cargo clippy --all --all-features --all-targets -cargo test --all -RUSTDOCFLAGS="--cfg docsrs" cargo doc --open --all-features -# Using nightly rustfmt -cargo +nightly fmt --all -- --check +## Reporting bugs, questions, feature requests + +To report a bug or suggest new functionality go to [issues](https://github.com/teloxide/teloxide/issues). +Try to make MRE (**M**inimal **R**eproducible **E**xample) and specify your teloxide version to let others help you. + +If you want to ask a question, you can either +- Open a new [github discussion](https://github.com/teloxide/teloxide/discussions), or +- Write to our telegram group ([eng](https://t.me/teloxide), [ru](https://t.me/teloxide_ru)) + +## Code + +### Git + +To change the source code, you need a local copy of it. +Fork the `master` branch of this repository via github and clone your fork locally. + +When working on a new thing, create a new branch with `git switch -c my-branch-name` (or other commands that work with branches). +This way it will be easier to manage when you want to do other things. + +When your changes are ready, you can open a github pull request. + +If your branch has conflicts with master please resolve them by doing something like this: +```shell +# Temporary switch to master branch +git switch master + +# Pull changes from the upstream. +# You may need to use something different from "origin", +# depending on how you setup your remotes. +git pull origin master + +# Switch back to your feature branch +git switch - + +# Move your changes on top of changes in master branch. +git rebase master + +# Here you'll need to resolve the conflicts, +# git commands will print some guidance. + +# Once conflicts are resolved, +# forcefully push the changes to your fork +git push --force-with-lease ``` -To report a bug, suggest new functionality, or ask a question, go to [Issues](https://github.com/teloxide/teloxide/issues). Try to make MRE (**M**inimal **R**eproducible **E**xample) and specify your teloxide version to let others help you. +### Testing + +When you open a PR it will be tested in CI. +We recommend you test the PR before opening it: + +```shell +# Formatting (use `-- --check` if you only want to check) +cargo fmt --all + +# Build +cargo build --features "full nightly" + +# Run linter +cargo clippy --all-targets --features "full nightly" + +# Running tests +cargo test --features "full nightly" + +# Documentation (use --open if you want to open it in a browser) +# (note the -s, `docs` is an alias to pass some additional flags to `rustdoc`) +cargo docs +``` + +## Teloxide bot + +Teloxide uses @teloxidebot as a helper to manage PRs and issues. +It's based on triagebot developed by rustc developers which docs can be found [here](https://forge.rust-lang.org/triagebot/index.html). + +We'll describe here a few most used @teloxidebot's features, but we still recommend you read the docs. + +### PR status tracking + +Teloxide uses `S-*` labels (mainly https://github.com/teloxide/teloxide/labels/S-waiting-on-author and https://github.com/teloxide/teloxide/labels/S-waiting-on-review) to track the status of pull requests. + +You can change the status with `@teloxidebot review` and `@teloxidebot ready` (set the status to https://github.com/teloxide/teloxide/labels/S-waiting-on-review) or `@teloxidebot author` (sets the status to https://github.com/teloxide/teloxide/labels/S-waiting-on-author). + +Requesting a review from PR's assignee via github ui will also change the status of the PR to waiting on review. +Similarly, submitting a review that requests changes will change the status of the PR to waiting on author. + +There is also https://github.com/teloxide/teloxide/labels/S-blocked which can be set with `@teloxidebot blocked`. + +Please note that your PR won't be reviewed unless it's waiting for review :) + +### Labels + +Normally github only allows privileged users to change labels. +@teloxidebot allows anyone to add or remove certain [labels](https://github.com/teloxide/teloxide/labels/) with `@teloxidebot label +additional_label -removed_label`. +See more in the [documentation](https://forge.rust-lang.org/triagebot/index.html). + +### PR assignment + +When a PR is created @teloxidebot will automatically assign one of the maintainers to it. +If you want to override this assignment, use `r? @ReviewerUsername`. From 5901a8966711ff23f7d762251958e1adaf706aa3 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 21 Jan 2024 20:17:01 +0100 Subject: [PATCH 05/41] internal: Remove `match_prefix!` --- crates/teloxide-core/src/errors.rs | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/crates/teloxide-core/src/errors.rs b/crates/teloxide-core/src/errors.rs index 8741668d..9138a32d 100644 --- a/crates/teloxide-core/src/errors.rs +++ b/crates/teloxide-core/src/errors.rs @@ -88,28 +88,13 @@ impl AsResponseParameters for crate::RequestError { } } -macro_rules! match_prefix { - ("") => {{ - |data: &str| Some(data.to_owned()) - }}; - ($prefix:literal) => {{ - |data: &str| { - if data.starts_with($prefix) { - Some(data.to_owned()) - } else { - None - } - } - }}; -} - macro_rules! impl_api_error { ( $( #[$meta:meta] )* $vis:vis enum $ident:ident { $( $( #[$var_meta:meta] )* - $var_name:ident $( ($var_inner:ty) )? = $var_string:literal $(with $var_parser: block)? + $var_name:ident $( ($var_inner:ty) )? = $var_string:literal $(with $var_parser:expr)? ),* } ) => { @@ -616,7 +601,13 @@ impl_api_error! { /// 1. [`SendMessage`] /// /// [`SendMessage`]: crate::payloads::SendMessage - CantParseEntities(String) = "{0}" with {match_prefix!("Bad Request: can't parse entities")}, + CantParseEntities(String) = "{0}" with |text: &str| { + if text.starts_with("Bad Request: can't parse entities") { + Some(text.to_owned()) + } else { + None + } + }, /// Occurs when bot tries to use getUpdates while webhook is active. /// @@ -712,7 +703,7 @@ impl_api_error! { /// description of the error. /// /// [open an issue]: https://github.com/teloxide/teloxide/issues/new - Unknown(String) = "Unknown error: {0:?}" with {match_prefix!("")} + Unknown(String) = "Unknown error: {0:?}" with |text: &str| Some(text.to_owned()) } } From 1233b913ab3f4dca96116d29bea11bb0aaf17916 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 21 Jan 2024 20:27:25 +0100 Subject: [PATCH 06/41] Replace `ApiError::NotFound` with `InvalidToken` --- crates/teloxide-core/CHANGELOG.md | 3 +++ crates/teloxide-core/src/errors.rs | 24 +++++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index f8d06ed7..100ef1f0 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -145,6 +145,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `can_edit_messages` - `can_pin_messages` - `can_manage_topics` +- `ApiError::NotFound` is replaced with `ApiError::InvalidToken` which correctly parses all currently known errors caused by invalid bot tokens ([#998][pr998]) + +[pr998]: https://github.com/teloxide/teloxide/pull/998 ### Added diff --git a/crates/teloxide-core/src/errors.rs b/crates/teloxide-core/src/errors.rs index 9138a32d..7e07dc8b 100644 --- a/crates/teloxide-core/src/errors.rs +++ b/crates/teloxide-core/src/errors.rs @@ -123,7 +123,7 @@ macro_rules! impl_api_error { where E: ::serde::de::Error, { - $(impl_api_error!(@de v, $var_name, $var_string $(, $var_parser)*);)* + $(impl_api_error!(@de v, $var_name $( ($var_inner) )?, $var_string $(, $var_parser)*);)* Err(E::unknown_variant(v, &[])) } } @@ -138,17 +138,22 @@ macro_rules! impl_api_error { } }; }; - (@de $value: ident, $variant: ident, $val: literal) => { + (@de $value:ident, $variant:ident, $val:literal) => { if $value == $val { return Ok(Self::Value::$variant) } }; - (@de $value: ident, $variant: ident, $val: literal, $block: expr) => { + (@de $value:ident, $variant:ident ($var_inner:ty), $val:literal, $block:expr) => { match $block($value) { Some(data) => return Ok(Self::Value::$variant(data)), _ => {} } }; + (@de $value:ident, $variant:ident, $val:literal, $block:expr) => { + if $block($value) { + return Ok(Self::Value::$variant); + } + }; } impl_api_error! { @@ -159,9 +164,12 @@ impl_api_error! { /// Occurs when the bot tries to send message to user who blocked the bot. BotBlocked = "Forbidden: bot was blocked by the user", - /// Occurs when the bot token is incorrect. - // FIXME: rename this to something akin "InvalidToken" - NotFound = "Unauthorized", + /// Occurs when the bot token is invalid. + // N.B. These errors are actually slightly different, "Unauthorized" is when the bot token + // is formatted mostly right, but is incorrect, whereas "Not Found" is when the url is + // not handled by TBA at all. From user POV both of those are "token is invalid", but + // there might be some cases where this is not right... + InvalidToken = "Invalid bot token" with |text: &str| text == "Unauthorized" || text == "Not Found", /// Occurs when bot tries to modify a message without modification content. /// @@ -804,7 +812,8 @@ mod tests { let cases = &[ ("{\"data\": \"Forbidden: bot was blocked by the user\"}", ApiError::BotBlocked), - ("{\"data\": \"Unauthorized\"}", ApiError::NotFound), + ("{\"data\": \"Unauthorized\"}", ApiError::InvalidToken), + ("{\"data\": \"Not Found\"}", ApiError::InvalidToken), ( "{\"data\": \"Bad Request: message is not modified: specified new message content \ and reply markup are exactly the same as a current content and reply markup of \ @@ -1019,6 +1028,7 @@ mod tests { ApiError::Unknown(_) => { format!("Unknown error: \"{raw}\"") } + ApiError::InvalidToken => "Invalid bot token".to_owned(), _ => raw, }; assert_eq!(parsed.to_string(), expected_error_message); From e185c6c8a6803c27df555ebadf0ba39895989d32 Mon Sep 17 00:00:00 2001 From: Waffle Maybe Date: Tue, 23 Jan 2024 14:35:37 +0100 Subject: [PATCH 07/41] Update feature_request.md --- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index f6b479f7..d46162ce 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,7 +2,7 @@ name: Feature request about: Suggest an idea for this project title: 'Feature Request: ' -labels: feature-request +labels: K-feature-request assignees: Hirrolot, WaffleLapkin --- From e22d8623d7c443d25126608b215fefb52927f876 Mon Sep 17 00:00:00 2001 From: Waffle Maybe Date: Tue, 23 Jan 2024 14:37:54 +0100 Subject: [PATCH 08/41] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 4e5d23b5..f5b9076c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,7 +2,7 @@ name: Bug report about: Create a report to help us improve title: '' -labels: bug +labels: K-bug assignees: '' --- From 425a49dafa9fae328b72f8a78114e6df82c33ac9 Mon Sep 17 00:00:00 2001 From: Waffle Maybe Date: Tue, 23 Jan 2024 14:39:51 +0100 Subject: [PATCH 09/41] Update parse-error.md --- .github/ISSUE_TEMPLATE/parse-error.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/parse-error.md b/.github/ISSUE_TEMPLATE/parse-error.md index b5606563..6a7b7766 100644 --- a/.github/ISSUE_TEMPLATE/parse-error.md +++ b/.github/ISSUE_TEMPLATE/parse-error.md @@ -2,7 +2,7 @@ name: Parse error about: Report issue with `teloxide` parsing of telegram response title: 'Parse Error: ' -labels: bug, FIXME, core +labels: K-bug, FIXME, C-core assignees: WaffleLapkin --- From ddf00e6bf3ceaa7f867045ca5f4e2be0a4e2aa91 Mon Sep 17 00:00:00 2001 From: Waffle Maybe Date: Tue, 23 Jan 2024 14:40:51 +0100 Subject: [PATCH 10/41] Update unknown-telegram-error.md --- .github/ISSUE_TEMPLATE/unknown-telegram-error.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/unknown-telegram-error.md b/.github/ISSUE_TEMPLATE/unknown-telegram-error.md index 6421b271..4e15b76a 100644 --- a/.github/ISSUE_TEMPLATE/unknown-telegram-error.md +++ b/.github/ISSUE_TEMPLATE/unknown-telegram-error.md @@ -2,7 +2,7 @@ name: Unknown telegram error about: You've found telegram error which is not known to teloxide title: 'Unknown Error: ' -labels: bug, good first issue, FIXME, core, Unknown API error +labels: K-bug, good first issue, FIXME, C-core, A-unknown-error, A-tba-errors assignees: '' --- From b6e9dc8a81d0f3c94e89c1737e8aa521178e1ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=8B=D1=80=D1=86=D0=B5=D0=B2=20=D0=92=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D0=BC=20=D0=98=D0=B3=D0=BE=D1=80=D0=B5=D0=B2=D0=B8=D1=87?= Date: Wed, 31 Jan 2024 22:56:08 +0300 Subject: [PATCH 11/41] Add exponential backoff strategy to the polling --- crates/teloxide/src/backoff_strategy.rs | 10 ++++ crates/teloxide/src/lib.rs | 1 + .../teloxide/src/update_listeners/polling.rs | 51 ++++++++++++++++++- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 crates/teloxide/src/backoff_strategy.rs diff --git a/crates/teloxide/src/backoff_strategy.rs b/crates/teloxide/src/backoff_strategy.rs new file mode 100644 index 00000000..7e9f45b7 --- /dev/null +++ b/crates/teloxide/src/backoff_strategy.rs @@ -0,0 +1,10 @@ +use std::time::Duration; + +pub type BackoffStrategy = Box Duration + Send>; + +/// Calculates the backoff time in seconds for exponential strategy with base 2 +/// +/// More at: +pub fn exponential_backoff_strategy(error_count: u32) -> Duration { + Duration::from_secs(2_u64.pow(error_count)) +} diff --git a/crates/teloxide/src/lib.rs b/crates/teloxide/src/lib.rs index 836138c2..2ed44c89 100644 --- a/crates/teloxide/src/lib.rs +++ b/crates/teloxide/src/lib.rs @@ -135,6 +135,7 @@ pub use repls::{repl, repl_with_listener}; #[allow(deprecated)] pub use repls::{commands_repl, commands_repl_with_listener}; +pub mod backoff_strategy; pub mod dispatching; pub mod error_handlers; pub mod prelude; diff --git a/crates/teloxide/src/update_listeners/polling.rs b/crates/teloxide/src/update_listeners/polling.rs index 62d63076..18fa0d6b 100644 --- a/crates/teloxide/src/update_listeners/polling.rs +++ b/crates/teloxide/src/update_listeners/polling.rs @@ -12,8 +12,10 @@ use std::{ }; use futures::{ready, stream::Stream}; +use tokio::time::{sleep, Sleep}; use crate::{ + backoff_strategy::{exponential_backoff_strategy, BackoffStrategy}, requests::{HasPayload, Request, Requester}, stop::{mk_stop_token, StopFlag, StopToken}, types::{AllowedUpdate, Update}, @@ -31,6 +33,7 @@ pub struct PollingBuilder { pub limit: Option, pub allowed_updates: Option>, pub drop_pending_updates: bool, + pub backoff_strategy: BackoffStrategy, } impl PollingBuilder @@ -84,6 +87,14 @@ where Self { drop_pending_updates: true, ..self } } + /// The backoff strategy that will be used for delay calculation between + /// reconnections + /// + /// By default, the [`exponential_backoff_strategy`] is used + pub fn backoff_strategy(self, backoff_strategy: BackoffStrategy) -> Self { + Self { backoff_strategy, ..self } + } + /// Deletes webhook if it was set up. pub async fn delete_webhook(self) -> Self { delete_webhook_if_setup(&self.bot).await; @@ -96,7 +107,8 @@ where /// /// See also: [`polling_default`], [`Polling`]. pub fn build(self) -> Polling { - let Self { bot, timeout, limit, allowed_updates, drop_pending_updates } = self; + let Self { bot, timeout, limit, allowed_updates, drop_pending_updates, backoff_strategy } = + self; let (token, flag) = mk_stop_token(); let polling = Polling { bot, @@ -107,6 +119,7 @@ where flag: Some(flag), token, stop_token_cloned: false, + backoff_strategy, }; assert_update_listener(polling) @@ -252,6 +265,7 @@ pub struct Polling { flag: Option, token: StopToken, stop_token_cloned: bool, + backoff_strategy: BackoffStrategy, } impl Polling @@ -270,6 +284,7 @@ where limit: None, allowed_updates: None, drop_pending_updates: false, + backoff_strategy: Box::new(exponential_backoff_strategy), } } @@ -317,6 +332,14 @@ pub struct PollingStream<'a, B: Requester> { /// The flag that notifies polling to stop polling. #[pin] flag: StopFlag, + + /// How long it takes to make next reconnection attempt + #[pin] + eepy: Option, + + /// Counter for network errors occured during the current series of + /// reconnections + error_count: u32, } impl UpdateListener for Polling { @@ -369,6 +392,8 @@ impl<'a, B: Requester + Send + 'a> AsUpdateStream<'a> for Polling { buffer: Vec::new().into_iter(), in_flight: None, flag, + eepy: None, + error_count: 0, } } } @@ -415,6 +440,9 @@ impl Stream for PollingStream<'_, B> { return Ready(Some(Err(err))); } Ok(updates) => { + // Once we got the update hense the backoff reconnection strategy worked + *this.error_count = 0; + if let Some(upd) = updates.last() { *this.offset = upd.id.as_offset(); } @@ -424,7 +452,26 @@ impl Stream for PollingStream<'_, B> { true => *this.drop_pending_updates = false, } } - Err(err) => return Ready(Some(Err(err))), + Err(err) => { + // Prevents the CPU spike occuring at network connection lose: + let backoff_strategy = &this.polling.backoff_strategy; + this.eepy.set(Some(sleep(backoff_strategy(*this.error_count)))); + log::trace!("set {:?} reconnection delay", backoff_strategy(*this.error_count)); + return Ready(Some(Err(err))); + } + } + } + // Poll eepy future until completion, needed for backoff strategy + if let Some(eepy) = this.eepy.as_mut().as_pin_mut() { + match eepy.poll(cx) { + Poll::Ready(_) => { + // As soon as delay is waited we increment the counter + *this.error_count = this.error_count.saturating_add(1); + log::trace!("current error count: {}", *this.error_count); + log::trace!("backoff delay completed"); + this.eepy.set(None); + } + Poll::Pending => return Poll::Pending, } } From 927e0ad0443ab3713fbb9dcfd51ecea5a2b6d0e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=8B=D1=80=D1=86=D0=B5=D0=B2=20=D0=92=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D0=BC=20=D0=98=D0=B3=D0=BE=D1=80=D0=B5=D0=B2=D0=B8=D1=87?= Date: Wed, 31 Jan 2024 23:03:22 +0300 Subject: [PATCH 12/41] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cfe45b5..79b6d7e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Greatly improved the speed of graceful shutdown (`^C`) ([PR 938](https://github.com/teloxide/teloxide/pull/938)) - Fix typos in docstrings ([PR 953](https://github.com/teloxide/teloxide/pull/953)) - Use `Seconds` instead of `String` in `InlineQueryResultAudio` for `audio_duration` ([PR 994](https://github.com/teloxide/teloxide/pull/994)) +- Issue [#780](https://github.com/teloxide/teloxide/issues/780) ([PR 1002](https://github.com/teloxide/teloxide/pull/1002)) ### Changed From 58f8a35825e99446692af0e894162151d03dc5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=8B=D1=80=D1=86=D0=B5=D0=B2=20=D0=92=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D0=BC=20=D0=98=D0=B3=D0=BE=D1=80=D0=B5=D0=B2=D0=B8=D1=87?= <74814717+syrtcevvi@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:09:58 +0300 Subject: [PATCH 13/41] Apply suggestions from code review #1002 Co-authored-by: Waffle Maybe --- CHANGELOG.md | 2 +- crates/teloxide/src/backoff_strategy.rs | 4 ++-- crates/teloxide/src/update_listeners/polling.rs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79b6d7e7..37321ac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,7 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Greatly improved the speed of graceful shutdown (`^C`) ([PR 938](https://github.com/teloxide/teloxide/pull/938)) - Fix typos in docstrings ([PR 953](https://github.com/teloxide/teloxide/pull/953)) - Use `Seconds` instead of `String` in `InlineQueryResultAudio` for `audio_duration` ([PR 994](https://github.com/teloxide/teloxide/pull/994)) -- Issue [#780](https://github.com/teloxide/teloxide/issues/780) ([PR 1002](https://github.com/teloxide/teloxide/pull/1002)) +- High CPU usage on network errors ([PR 1002](https://github.com/teloxide/teloxide/pull/1002), [Issue 780](https://github.com/teloxide/teloxide/issues/780)) ### Changed diff --git a/crates/teloxide/src/backoff_strategy.rs b/crates/teloxide/src/backoff_strategy.rs index 7e9f45b7..b4541d6a 100644 --- a/crates/teloxide/src/backoff_strategy.rs +++ b/crates/teloxide/src/backoff_strategy.rs @@ -1,10 +1,10 @@ use std::time::Duration; -pub type BackoffStrategy = Box Duration + Send>; +pub type BackoffStrategy = Box Duration>; /// Calculates the backoff time in seconds for exponential strategy with base 2 /// /// More at: pub fn exponential_backoff_strategy(error_count: u32) -> Duration { - Duration::from_secs(2_u64.pow(error_count)) + Duration::from_secs((1_u64 << error_count).min(30 * 60)) } diff --git a/crates/teloxide/src/update_listeners/polling.rs b/crates/teloxide/src/update_listeners/polling.rs index 18fa0d6b..4d7e55a9 100644 --- a/crates/teloxide/src/update_listeners/polling.rs +++ b/crates/teloxide/src/update_listeners/polling.rs @@ -88,9 +88,9 @@ where } /// The backoff strategy that will be used for delay calculation between - /// reconnections + /// reconnections caused by network errors. /// - /// By default, the [`exponential_backoff_strategy`] is used + /// By default, the [`exponential_backoff_strategy`] is used. pub fn backoff_strategy(self, backoff_strategy: BackoffStrategy) -> Self { Self { backoff_strategy, ..self } } @@ -462,7 +462,7 @@ impl Stream for PollingStream<'_, B> { } } // Poll eepy future until completion, needed for backoff strategy - if let Some(eepy) = this.eepy.as_mut().as_pin_mut() { + else if let Some(eepy) = this.eepy.as_mut().as_pin_mut() { match eepy.poll(cx) { Poll::Ready(_) => { // As soon as delay is waited we increment the counter From cdca875b63d37bf0009c5ec09e951c6043ee9e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=8B=D1=80=D1=86=D0=B5=D0=B2=20=D0=92=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D0=BC=20=D0=98=D0=B3=D0=BE=D1=80=D0=B5=D0=B2=D0=B8=D1=87?= Date: Thu, 1 Feb 2024 10:35:10 +0300 Subject: [PATCH 14/41] Fix backoff bugs --- .../src/{backoff_strategy.rs => backoff.rs} | 7 +++++- crates/teloxide/src/lib.rs | 2 +- .../teloxide/src/update_listeners/polling.rs | 25 +++++++++---------- 3 files changed, 19 insertions(+), 15 deletions(-) rename crates/teloxide/src/{backoff_strategy.rs => backoff.rs} (50%) diff --git a/crates/teloxide/src/backoff_strategy.rs b/crates/teloxide/src/backoff.rs similarity index 50% rename from crates/teloxide/src/backoff_strategy.rs rename to crates/teloxide/src/backoff.rs index b4541d6a..26819a1d 100644 --- a/crates/teloxide/src/backoff_strategy.rs +++ b/crates/teloxide/src/backoff.rs @@ -4,7 +4,12 @@ pub type BackoffStrategy = Box Duration>; /// Calculates the backoff time in seconds for exponential strategy with base 2 /// +/// The maximum duration is limited to a little less than half an hour (1024 +/// secs), so the successive timings are(in secs): 1, 2, 4, .., 1024, 1024, .. +/// /// More at: pub fn exponential_backoff_strategy(error_count: u32) -> Duration { - Duration::from_secs((1_u64 << error_count).min(30 * 60)) + // The error_count has to be limited so as not to cause overflow: 2^10 = 1024 ~ + // a little less than half an hour + Duration::from_secs(1_u64 << error_count.min(10)) } diff --git a/crates/teloxide/src/lib.rs b/crates/teloxide/src/lib.rs index 2ed44c89..4535d843 100644 --- a/crates/teloxide/src/lib.rs +++ b/crates/teloxide/src/lib.rs @@ -135,7 +135,7 @@ pub use repls::{repl, repl_with_listener}; #[allow(deprecated)] pub use repls::{commands_repl, commands_repl_with_listener}; -pub mod backoff_strategy; +pub mod backoff; pub mod dispatching; pub mod error_handlers; pub mod prelude; diff --git a/crates/teloxide/src/update_listeners/polling.rs b/crates/teloxide/src/update_listeners/polling.rs index 4d7e55a9..e39ba977 100644 --- a/crates/teloxide/src/update_listeners/polling.rs +++ b/crates/teloxide/src/update_listeners/polling.rs @@ -15,7 +15,7 @@ use futures::{ready, stream::Stream}; use tokio::time::{sleep, Sleep}; use crate::{ - backoff_strategy::{exponential_backoff_strategy, BackoffStrategy}, + backoff::{exponential_backoff_strategy, BackoffStrategy}, requests::{HasPayload, Request, Requester}, stop::{mk_stop_token, StopFlag, StopToken}, types::{AllowedUpdate, Update}, @@ -91,8 +91,11 @@ where /// reconnections caused by network errors. /// /// By default, the [`exponential_backoff_strategy`] is used. - pub fn backoff_strategy(self, backoff_strategy: BackoffStrategy) -> Self { - Self { backoff_strategy, ..self } + pub fn backoff_strategy( + self, + backoff_strategy: impl 'static + Send + Fn(u32) -> Duration, + ) -> Self { + Self { backoff_strategy: Box::new(backoff_strategy), ..self } } /// Deletes webhook if it was set up. @@ -463,16 +466,12 @@ impl Stream for PollingStream<'_, B> { } // Poll eepy future until completion, needed for backoff strategy else if let Some(eepy) = this.eepy.as_mut().as_pin_mut() { - match eepy.poll(cx) { - Poll::Ready(_) => { - // As soon as delay is waited we increment the counter - *this.error_count = this.error_count.saturating_add(1); - log::trace!("current error count: {}", *this.error_count); - log::trace!("backoff delay completed"); - this.eepy.set(None); - } - Poll::Pending => return Poll::Pending, - } + ready!(eepy.poll(cx)); + // As soon as delay is waited we increment the counter + *this.error_count = this.error_count.saturating_add(1); + log::trace!("current error count: {}", *this.error_count); + log::trace!("backoff delay completed"); + this.eepy.as_mut().set(None); } let (offset, limit, timeout) = match (this.stopping, this.drop_pending_updates) { From cd2ef79b0ffe91f798728faa974efc4a3a2f5953 Mon Sep 17 00:00:00 2001 From: TheAwiteb Date: Tue, 26 Sep 2023 21:53:28 +0300 Subject: [PATCH 15/41] Add `can_send_audios`, `can_send_documents`, `can_send_photos`, `can_send_videos`, `can_send_video_notes`, and `can_send_voice_notes` fields for `ChatPermissions` and remove `can_send_media_messages` --- .../src/types/chat_permissions.rs | 171 +++++++++++++++--- 1 file changed, 141 insertions(+), 30 deletions(-) diff --git a/crates/teloxide-core/src/types/chat_permissions.rs b/crates/teloxide-core/src/types/chat_permissions.rs index 2a634c35..4a28288d 100644 --- a/crates/teloxide-core/src/types/chat_permissions.rs +++ b/crates/teloxide-core/src/types/chat_permissions.rs @@ -26,23 +26,23 @@ bitflags::bitflags! { /// assert!(!permissions_v0.contains(ChatPermissions::SEND_MESSAGES)); /// /// // Union, add permissions - /// let permissions_v1 = permissions_v0 | ChatPermissions::SEND_MEDIA_MESSAGES; + /// let permissions_v1 = permissions_v0 | ChatPermissions::SEND_VIDEOS; /// assert!(permissions_v1.contains(ChatPermissions::INVITE_USERS)); - /// assert!(permissions_v1.contains(ChatPermissions::SEND_MEDIA_MESSAGES)); + /// assert!(permissions_v1.contains(ChatPermissions::SEND_VIDEOS)); /// - /// // Implied by `SEND_MEDIA_MESSAGES` + /// // Implied by `SEND_VIDEOS` /// assert!(permissions_v1.contains(ChatPermissions::SEND_MESSAGES)); /// /// // Difference, remove permissions - /// let permissions_v2 = permissions_v1 - ChatPermissions::SEND_MEDIA_MESSAGES; - /// assert!(!permissions_v2.contains(ChatPermissions::SEND_MEDIA_MESSAGES)); + /// let permissions_v2 = permissions_v1 - ChatPermissions::SEND_VIDEOS; + /// assert!(!permissions_v2.contains(ChatPermissions::SEND_VIDEOS)); /// - /// // Removing `SEND_MEDIA_MESSAGES` also removes `SEND_MESSAGES` and vice versa - /// // because `SEND_MESSAGES` is implied by `SEND_MEDIA_MESSAGES` + /// // Removing `SEND_VIDEOS` also removes `SEND_MESSAGES` and vice versa + /// // because `SEND_MESSAGES` is implied by `SEND_VIDEOS` /// assert!(!permissions_v2.contains(ChatPermissions::SEND_MESSAGES)); /// /// let permissions_v3 = permissions_v1 - ChatPermissions::SEND_MESSAGES; - /// assert!(!permissions_v3.contains(ChatPermissions::SEND_MEDIA_MESSAGES)); + /// assert!(!permissions_v3.contains(ChatPermissions::SEND_VIDEOS)); /// ``` #[derive(Serialize, Deserialize)] #[serde(from = "ChatPermissionsRaw", into = "ChatPermissionsRaw")] @@ -51,36 +51,59 @@ bitflags::bitflags! { /// locations and venues. const SEND_MESSAGES = 1; - /// Set if the user is allowed to send audios, documents, - /// photos, videos, video notes and voice notes, implies - /// `SEND_MESSAGES`. - const SEND_MEDIA_MESSAGES = (1 << 1) | Self::SEND_MESSAGES.bits; + /// Set if the user is allowed to send audios. + const SEND_AUDIOS = (1 << 1) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send documents. + const SEND_DOCUMENTS = (1 << 2) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send photos. + const SEND_PHOTOS = (1 << 3) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send videos. + const SEND_VIDEOS = (1 << 4) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send video notes. + const SEND_VIDEO_NOTES = (1 << 5) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send voice notes. + const SEND_VOICE_NOTES = (1 << 6) | Self::SEND_MESSAGES.bits; /// Set if the user is allowed to send polls, implies /// `SEND_MESSAGES`. - const SEND_POLLS = (1 << 2) | Self::SEND_MESSAGES.bits; + const SEND_POLLS = (1 << 7) | Self::SEND_MESSAGES.bits; /// Set if the user is allowed to send animations, games, stickers and /// use inline bots, implies `SEND_MEDIA_MESSAGES`. - const SEND_OTHER_MESSAGES = (1 << 3) | Self::SEND_MEDIA_MESSAGES.bits; + const SEND_OTHER_MESSAGES = (1 << 8) | Self::SEND_AUDIOS.bits + | Self::SEND_DOCUMENTS.bits + | Self::SEND_PHOTOS.bits + | Self::SEND_VIDEOS.bits + | Self::SEND_VIDEO_NOTES.bits + | Self::SEND_VOICE_NOTES.bits; /// Set if the user is allowed to add web page previews to /// their messages, implies `SEND_MEDIA_MESSAGES`. - const ADD_WEB_PAGE_PREVIEWS = (1 << 4) | Self::SEND_MEDIA_MESSAGES.bits; + const ADD_WEB_PAGE_PREVIEWS = (1 << 9) | Self::SEND_AUDIOS.bits + | Self::SEND_DOCUMENTS.bits + | Self::SEND_PHOTOS.bits + | Self::SEND_VIDEOS.bits + | Self::SEND_VIDEO_NOTES.bits + | Self::SEND_VOICE_NOTES.bits; /// Set if the user is allowed to change the chat title, photo and /// other settings. Ignored in public supergroups. - const CHANGE_INFO = (1 << 5); + const CHANGE_INFO = (1 << 10); /// Set if the user is allowed to invite new users to the chat. - const INVITE_USERS = (1 << 6); + const INVITE_USERS = (1 << 11); /// Set if the user is allowed to pin messages. Ignored in public /// supergroups. - const PIN_MESSAGES = (1 << 7); + const PIN_MESSAGES = (1 << 12); /// Set if the user is allowed to create, rename, close, and reopen forum topics. - const MANAGE_TOPICS = (1 << 8); + const MANAGE_TOPICS = (1 << 13); } } @@ -96,7 +119,56 @@ impl ChatPermissions { /// /// [`SEND_MEDIA_MESSAGES`]: ChatPermissions::SEND_MEDIA_MESSAGES pub fn can_send_media_messages(&self) -> bool { - self.contains(ChatPermissions::SEND_MEDIA_MESSAGES) + self.contains( + ChatPermissions::SEND_AUDIOS + | ChatPermissions::SEND_DOCUMENTS + | ChatPermissions::SEND_PHOTOS + | ChatPermissions::SEND_VIDEOS + | ChatPermissions::SEND_VIDEO_NOTES + | ChatPermissions::SEND_VOICE_NOTES, + ) + } + + /// Checks for [`SEND_AUDIOS`] permission. + /// + /// [`SEND_AUDIOS`]: ChatPermissions::SEND_AUDIOS + pub fn can_send_audios(&self) -> bool { + self.contains(ChatPermissions::SEND_AUDIOS) + } + + /// Checks for [`SEND_DOCUMENTS`] permission. + /// + /// [`SEND_DOCUMENTS`]: ChatPermissions::SEND_DOCUMENTS + pub fn can_send_documents(&self) -> bool { + self.contains(ChatPermissions::SEND_DOCUMENTS) + } + + /// Checks for [`SEND_PHOTOS`] permission. + /// + /// [`SEND_PHOTOS`]: ChatPermissions::SEND_PHOTOS + pub fn can_send_photos(&self) -> bool { + self.contains(ChatPermissions::SEND_PHOTOS) + } + + /// Checks for [`SEND_VIDEOS`] permission. + /// + /// [`SEND_VIDEOS`]: ChatPermissions::SEND_VIDEOS + pub fn can_send_videos(&self) -> bool { + self.contains(ChatPermissions::SEND_VIDEOS) + } + + /// Checks for [`SEND_VIDEO_NOTES`] permission. + /// + /// [`SEND_VIDEO_NOTES`]: ChatPermissions::SEND_VIDEO_NOTES + pub fn can_send_video_notes(&self) -> bool { + self.contains(ChatPermissions::SEND_VIDEO_NOTES) + } + + /// Checks for [`SEND_VOICE_NOTES`] permission. + /// + /// [`SEND_VOICE_NOTES`]: ChatPermissions::SEND_VOICE_NOTES + pub fn can_send_voice_notes(&self) -> bool { + self.contains(ChatPermissions::SEND_VOICE_NOTES) } /// Checks for [`SEND_POLLS`] permission. @@ -156,7 +228,22 @@ struct ChatPermissionsRaw { can_send_messages: bool, #[serde(default, skip_serializing_if = "Not::not")] - can_send_media_messages: bool, + can_send_audios: bool, + + #[serde(default, skip_serializing_if = "Not::not")] + can_send_documents: bool, + + #[serde(default, skip_serializing_if = "Not::not")] + can_send_photos: bool, + + #[serde(default, skip_serializing_if = "Not::not")] + can_send_videos: bool, + + #[serde(default, skip_serializing_if = "Not::not")] + can_send_video_notes: bool, + + #[serde(default, skip_serializing_if = "Not::not")] + can_send_voice_notes: bool, #[serde(default, skip_serializing_if = "Not::not")] can_send_polls: bool, @@ -188,7 +275,12 @@ impl From for ChatPermissionsRaw { fn from(this: ChatPermissions) -> Self { Self { can_send_messages: this.can_send_messages(), - can_send_media_messages: this.can_send_media_messages(), + can_send_audios: this.contains(ChatPermissions::SEND_AUDIOS), + can_send_documents: this.contains(ChatPermissions::SEND_DOCUMENTS), + can_send_photos: this.contains(ChatPermissions::SEND_PHOTOS), + can_send_videos: this.contains(ChatPermissions::SEND_VIDEOS), + can_send_video_notes: this.contains(ChatPermissions::SEND_VIDEO_NOTES), + can_send_voice_notes: this.contains(ChatPermissions::SEND_VOICE_NOTES), can_send_polls: this.can_send_polls(), can_send_other_messages: this.can_send_other_messages(), can_add_web_page_previews: this.can_add_web_page_previews(), @@ -204,7 +296,12 @@ impl From for ChatPermissions { fn from( ChatPermissionsRaw { can_send_messages, - can_send_media_messages, + can_send_audios, + can_send_documents, + can_send_photos, + can_send_videos, + can_send_video_notes, + can_send_voice_notes, can_send_polls, can_send_other_messages, can_add_web_page_previews, @@ -219,8 +316,23 @@ impl From for ChatPermissions { if can_send_messages { this |= Self::SEND_MESSAGES; } - if can_send_media_messages { - this |= Self::SEND_MEDIA_MESSAGES + if can_send_audios { + this |= Self::SEND_AUDIOS; + } + if can_send_documents { + this |= Self::SEND_DOCUMENTS; + } + if can_send_photos { + this |= Self::SEND_PHOTOS; + } + if can_send_videos { + this |= Self::SEND_VIDEOS; + } + if can_send_video_notes { + this |= Self::SEND_VIDEO_NOTES; + } + if can_send_voice_notes { + this |= Self::SEND_VOICE_NOTES; } if can_send_polls { this |= Self::SEND_POLLS; @@ -255,17 +367,16 @@ mod tests { #[test] fn serialization() { - let permissions = ChatPermissions::SEND_MEDIA_MESSAGES | ChatPermissions::PIN_MESSAGES; - let expected = r#"{"can_send_messages":true,"can_send_media_messages":true,"can_pin_messages":true,"can_manage_topics":false}"#; + let permissions = ChatPermissions::SEND_AUDIOS | ChatPermissions::PIN_MESSAGES; + let expected = r#"{"can_send_messages":true,"can_send_audios":true,"can_pin_messages":true,"can_manage_topics":false}"#; let actual = serde_json::to_string(&permissions).unwrap(); assert_eq!(expected, actual); } #[test] fn deserialization() { - let json = - r#"{"can_send_messages":true,"can_send_media_messages":true,"can_pin_messages":true}"#; - let expected = ChatPermissions::SEND_MEDIA_MESSAGES | ChatPermissions::PIN_MESSAGES; + let json = r#"{"can_send_messages":true,"can_send_photos":true,"can_pin_messages":true}"#; + let expected = ChatPermissions::SEND_PHOTOS | ChatPermissions::PIN_MESSAGES; let actual = serde_json::from_str(json).unwrap(); assert_eq!(expected, actual); } From 803faf07e4965da2a5cc4b75dd2e9c2b83d124f5 Mon Sep 17 00:00:00 2001 From: TheAwiteb Date: Tue, 26 Sep 2023 22:04:57 +0300 Subject: [PATCH 16/41] Remove `ChatPermissions::can_send_media_messages` instance function --- .../src/types/chat_permissions.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/crates/teloxide-core/src/types/chat_permissions.rs b/crates/teloxide-core/src/types/chat_permissions.rs index 4a28288d..67b6cddc 100644 --- a/crates/teloxide-core/src/types/chat_permissions.rs +++ b/crates/teloxide-core/src/types/chat_permissions.rs @@ -74,7 +74,7 @@ bitflags::bitflags! { const SEND_POLLS = (1 << 7) | Self::SEND_MESSAGES.bits; /// Set if the user is allowed to send animations, games, stickers and - /// use inline bots, implies `SEND_MEDIA_MESSAGES`. + /// use inline bots, implies midia messages permissions. const SEND_OTHER_MESSAGES = (1 << 8) | Self::SEND_AUDIOS.bits | Self::SEND_DOCUMENTS.bits | Self::SEND_PHOTOS.bits @@ -83,7 +83,7 @@ bitflags::bitflags! { | Self::SEND_VOICE_NOTES.bits; /// Set if the user is allowed to add web page previews to - /// their messages, implies `SEND_MEDIA_MESSAGES`. + /// their messages, implies midia messages permissions. const ADD_WEB_PAGE_PREVIEWS = (1 << 9) | Self::SEND_AUDIOS.bits | Self::SEND_DOCUMENTS.bits | Self::SEND_PHOTOS.bits @@ -115,20 +115,6 @@ impl ChatPermissions { self.contains(ChatPermissions::SEND_MESSAGES) } - /// Checks for [`SEND_MEDIA_MESSAGES`] permission. - /// - /// [`SEND_MEDIA_MESSAGES`]: ChatPermissions::SEND_MEDIA_MESSAGES - pub fn can_send_media_messages(&self) -> bool { - self.contains( - ChatPermissions::SEND_AUDIOS - | ChatPermissions::SEND_DOCUMENTS - | ChatPermissions::SEND_PHOTOS - | ChatPermissions::SEND_VIDEOS - | ChatPermissions::SEND_VIDEO_NOTES - | ChatPermissions::SEND_VOICE_NOTES, - ) - } - /// Checks for [`SEND_AUDIOS`] permission. /// /// [`SEND_AUDIOS`]: ChatPermissions::SEND_AUDIOS From e3b2277fdfcea5d1646f985eebbb18940753f575 Mon Sep 17 00:00:00 2001 From: TheAwiteb Date: Wed, 27 Sep 2023 12:32:32 +0300 Subject: [PATCH 17/41] remove `can_send_media_messages` and add media types The media types is `can_send_audios`, `can_send_documents`, `can_send_photos`, `can_send_videos`, `can_send_video_notes`, and `can_send_voice_notes` --- crates/teloxide-core/src/types/chat_member.rs | 111 +++++++++++++----- 1 file changed, 83 insertions(+), 28 deletions(-) diff --git a/crates/teloxide-core/src/types/chat_member.rs b/crates/teloxide-core/src/types/chat_member.rs index 8b91b03b..3f712af8 100644 --- a/crates/teloxide-core/src/types/chat_member.rs +++ b/crates/teloxide-core/src/types/chat_member.rs @@ -120,9 +120,23 @@ pub struct Restricted { /// venues. pub can_send_messages: bool, - /// `true` if the user is allowed to send audios, documents, photos, videos, - /// video notes and voice notes. - pub can_send_media_messages: bool, + /// `true` if the user can send audios. + pub can_send_audios: bool, + + /// `true` if the user can send documents. + pub can_send_documents: bool, + + /// `true` if the user can send photos. + pub can_send_photos: bool, + + /// `true` if the user can send videos. + pub can_send_videos: bool, + + /// `true` if the user can send video notes. + pub can_send_video_notes: bool, + + /// `true` if the user can send voice notes. + pub can_send_voice_notes: bool, /// `true` if the user is allowed to send animations, games, stickers and /// use inline bots. @@ -618,30 +632,6 @@ impl ChatMemberKind { } } - /// Returns `true` if the user is allowed to send audios, documents, photos, - /// videos, video notes and voice notes. - /// - /// I.e. returns **`false`** if the user - /// - has left or has been banned in the chat - /// - is restricted and doesn't have the [`can_send_media_messages`] right - /// Returns `true` otherwise. - /// - /// [`can_send_media_messages`]: Restricted::can_send_media_messages - #[deprecated( - since = "0.9.0", - note = "Match manually and use `can_send_media_messages` field directly. Details: https://github.com/teloxide/teloxide/issues/781" - )] - #[must_use] - pub fn can_send_media_messages(&self) -> bool { - match &self { - Self::Restricted(Restricted { can_send_media_messages, .. }) => { - *can_send_media_messages - } - Self::Owner(_) | Self::Administrator(_) | Self::Member => true, - Self::Left | Self::Banned(_) => false, - } - } - /// Returns `true` if the user is allowed to send animations, games, /// stickers and use inline bots. /// @@ -826,7 +816,7 @@ mod tests { use super::*; #[test] - fn deserialize() { + fn deserialize_administrator() { let json = r#"{ "user":{ "id":1029940401, @@ -879,4 +869,69 @@ mod tests { let actual = serde_json::from_str::(json).unwrap(); assert_eq!(actual, expected) } + + #[test] + fn deserialize_restricted() { + let json = r#"{ + "user":{ + "id":1029940401, + "is_bot":false, + "first_name":"First", + "last_name":"Last", + "username":"fl", + "language_code":"en" + }, + "status":"restricted", + "is_member": true, + "can_send_messages": true, + "can_send_audios": false, + "can_send_documents": false, + "can_send_photos": true, + "can_send_videos": true, + "can_send_video_notes": false, + "can_send_voice_notes": true, + "can_manage_topics": false, + "can_send_polls": true, + "can_send_other_messages": true, + "can_add_web_page_previews": true, + "can_change_info": true, + "can_invite_users": true, + "can_pin_messages": true, + "until_date": 1620000000 + }"#; + let expected = ChatMember { + user: User { + id: UserId(1029940401), + is_bot: false, + first_name: "First".to_string(), + last_name: Some("Last".to_string()), + username: Some("fl".to_string()), + language_code: Some("en".to_string()), + is_premium: false, + added_to_attachment_menu: false, + }, + kind: ChatMemberKind::Restricted(Restricted { + is_member: true, + can_send_messages: true, + can_send_audios: false, + can_send_documents: false, + can_send_photos: true, + can_send_videos: true, + can_send_video_notes: false, + can_send_voice_notes: true, + can_manage_topics: false, + can_send_polls: true, + can_send_other_messages: true, + can_add_web_page_previews: true, + can_change_info: true, + can_invite_users: true, + can_pin_messages: true, + until_date: UntilDate::Date( + chrono::NaiveDateTime::from_timestamp_opt(1620000000, 0).unwrap().and_utc(), + ), + }), + }; + let actual = serde_json::from_str::(json).unwrap(); + assert_eq!(actual, expected) + } } From 3e05086d47a50bbbaf52860edda3ff496473471f Mon Sep 17 00:00:00 2001 From: TheAwiteb Date: Thu, 5 Oct 2023 00:32:47 +0300 Subject: [PATCH 18/41] Add the `use_independent_chat_permissions` field to `RestrictChatMember` and `SetChatPermissions` --- crates/teloxide-core/schema.ron | 10 ++++++++++ .../teloxide-core/src/payloads/restrict_chat_member.rs | 2 ++ .../teloxide-core/src/payloads/set_chat_permissions.rs | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/crates/teloxide-core/schema.ron b/crates/teloxide-core/schema.ron index 6d6c7ca6..346f64b5 100644 --- a/crates/teloxide-core/schema.ron +++ b/crates/teloxide-core/schema.ron @@ -1988,6 +1988,11 @@ Schema( ty: RawTy("ChatPermissions"), descr: Doc(md: "A JSON-serialized object for new user permissions") ), + Param( + name: "use_independent_chat_permissions", + ty: Option(bool), + descr: Doc(md: "Pass _True_ if chat permissions are set independently. Otherwise, the _can\\_send\\_other\\_messages_ and _can\\_add\\_web\\_page\\_previews_ permissions will imply the _can\\_send\\_messages_, _can\\_send\\_audios_, _can\\_send\\_documents_, _can\\_send\\_photos_, _can\\_send\\_videos_, _can\\_send\\_video\\_notes_, and _can\\_send\\_voice\\_notes_ permissions; the _can\\_send\\_polls_ permission will imply the _can\\_send\\_messages_ permission.") + ), Param( name: "until_date", ty: Option(u64), @@ -2153,6 +2158,11 @@ Schema( ty: RawTy("ChatPermissions"), descr: Doc(md: "New default chat permissions") ), + Param( + name: "use_independent_chat_permissions", + ty: Option(bool), + descr: Doc(md: "Pass _True_ if chat permissions are set independently. Otherwise, the _can\\_send\\_other\\_messages_ and _can\\_add\\_web\\_page\\_previews_ permissions will imply the _can\\_send\\_messages_, _can\\_send\\_audios_, _can\\_send\\_documents_, _can\\_send\\_photos_, _can\\_send\\_videos_, _can\\_send\\_video\\_notes_, and _can\\_send\\_voice\\_notes_ permissions; the _can\\_send\\_polls_ permission will imply the _can\\_send\\_messages_ permission.") + ), ], ), Method( diff --git a/crates/teloxide-core/src/payloads/restrict_chat_member.rs b/crates/teloxide-core/src/payloads/restrict_chat_member.rs index 282af1dd..9ed55079 100644 --- a/crates/teloxide-core/src/payloads/restrict_chat_member.rs +++ b/crates/teloxide-core/src/payloads/restrict_chat_member.rs @@ -18,6 +18,8 @@ impl_payload! { pub permissions: ChatPermissions, } optional { + /// Pass _True_ if chat permissions are set independently. Otherwise, the _can\_send\_other\_messages_ and _can\_add\_web\_page\_previews_ permissions will imply the _can\_send\_messages_, _can\_send\_audios_, _can\_send\_documents_, _can\_send\_photos_, _can\_send\_videos_, _can\_send\_video\_notes_, and _can\_send\_voice\_notes_ permissions; the _can\_send\_polls_ permission will imply the _can\_send\_messages_ permission. + pub use_independent_chat_permissions: bool, /// Date when the user will be unbanned, unix time. If user is banned for more than 366 days or less than 30 seconds from the current time they are considered to be banned forever #[serde(with = "crate::types::serde_opt_date_from_unix_timestamp")] pub until_date: DateTime [into], diff --git a/crates/teloxide-core/src/payloads/set_chat_permissions.rs b/crates/teloxide-core/src/payloads/set_chat_permissions.rs index debfc9a9..38d40b4e 100644 --- a/crates/teloxide-core/src/payloads/set_chat_permissions.rs +++ b/crates/teloxide-core/src/payloads/set_chat_permissions.rs @@ -14,5 +14,9 @@ impl_payload! { /// New default chat permissions pub permissions: ChatPermissions, } + optional { + /// Pass _True_ if chat permissions are set independently. Otherwise, the _can\_send\_other\_messages_ and _can\_add\_web\_page\_previews_ permissions will imply the _can\_send\_messages_, _can\_send\_audios_, _can\_send\_documents_, _can\_send\_photos_, _can\_send\_videos_, _can\_send\_video\_notes_, and _can\_send\_voice\_notes_ permissions; the _can\_send\_polls_ permission will imply the _can\_send\_messages_ permission. + pub use_independent_chat_permissions: bool, + } } } From f52665dbd0ec42189fd3cce324cb745a2a41f10d Mon Sep 17 00:00:00 2001 From: TheAwiteb Date: Thu, 5 Oct 2023 01:13:45 +0300 Subject: [PATCH 19/41] Add `user_chat_id` field to `ChatJoinRequest` --- crates/teloxide-core/src/types/chat_join_request.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/teloxide-core/src/types/chat_join_request.rs b/crates/teloxide-core/src/types/chat_join_request.rs index 9f9d9a6d..0d5b896c 100644 --- a/crates/teloxide-core/src/types/chat_join_request.rs +++ b/crates/teloxide-core/src/types/chat_join_request.rs @@ -1,7 +1,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::{Chat, ChatInviteLink, User}; +use crate::types::{Chat, ChatId, ChatInviteLink, User}; /// Represents a join request sent to a chat. #[serde_with_macros::skip_serializing_none] @@ -11,6 +11,11 @@ pub struct ChatJoinRequest { pub chat: Chat, /// User that sent the join request pub from: User, + /// Identifier of a private chat with the user who sent the join request. + /// The bot can use this identifier for 5 minutes to send messages until + /// the join request is processed, assuming no other administrator + /// contacted the user. + pub user_chat_id: ChatId, /// Date the request was sent in Unix time #[serde(with = "crate::types::serde_date_from_unix_timestamp")] pub date: DateTime, From dbf3e66a99a66fa23dd0ac15790f3fced6c80d30 Mon Sep 17 00:00:00 2001 From: Awiteb Date: Tue, 6 Feb 2024 06:41:43 +0300 Subject: [PATCH 20/41] Add request chat and user --- crates/teloxide-core/src/types.rs | 8 ++ crates/teloxide-core/src/types/chat_member.rs | 40 +++++- .../src/types/chat_permissions.rs | 91 ++++++++------ crates/teloxide-core/src/types/chat_shared.rs | 15 +++ .../src/types/keyboard_button.rs | 77 ++++++++++-- .../src/types/keyboard_button_request_chat.rs | 114 ++++++++++++++++++ .../src/types/keyboard_button_request_user.rs | 44 +++++++ crates/teloxide-core/src/types/message.rs | 95 +++++++++++++-- crates/teloxide-core/src/types/user_shared.rs | 15 +++ 9 files changed, 441 insertions(+), 58 deletions(-) create mode 100644 crates/teloxide-core/src/types/chat_shared.rs create mode 100644 crates/teloxide-core/src/types/keyboard_button_request_chat.rs create mode 100644 crates/teloxide-core/src/types/keyboard_button_request_user.rs create mode 100644 crates/teloxide-core/src/types/user_shared.rs diff --git a/crates/teloxide-core/src/types.rs b/crates/teloxide-core/src/types.rs index 0a94ce54..89897656 100644 --- a/crates/teloxide-core/src/types.rs +++ b/crates/teloxide-core/src/types.rs @@ -17,6 +17,7 @@ pub use chat_member::*; pub use chat_member_updated::*; pub use chat_permissions::*; pub use chat_photo::*; +pub use chat_shared::*; pub use chat_type::*; pub use chosen_inline_result::*; pub use contact::*; @@ -67,6 +68,8 @@ pub use input_sticker::*; pub use invoice::*; pub use keyboard_button::*; pub use keyboard_button_poll_type::*; +pub use keyboard_button_request_chat::*; +pub use keyboard_button_request_user::*; pub use label_price::*; pub use location::*; pub use login_url::*; @@ -106,6 +109,7 @@ pub use unit_true::*; pub use update::*; pub use user::*; pub use user_profile_photos::*; +pub use user_shared::*; pub use venue::*; pub use video::*; pub use video_chat_ended::*; @@ -136,6 +140,7 @@ mod chat_member; mod chat_member_updated; mod chat_permissions; mod chat_photo; +mod chat_shared; mod chat_type; mod chosen_inline_result; mod contact; @@ -162,6 +167,8 @@ mod input_sticker; mod invoice; mod keyboard_button; mod keyboard_button_poll_type; +mod keyboard_button_request_chat; +mod keyboard_button_request_user; mod label_price; mod location; mod login_url; @@ -198,6 +205,7 @@ mod unit_true; mod update; mod user; mod user_profile_photos; +mod user_shared; mod venue; mod video; mod video_chat_ended; diff --git a/crates/teloxide-core/src/types/chat_member.rs b/crates/teloxide-core/src/types/chat_member.rs index 3f712af8..221bc4a6 100644 --- a/crates/teloxide-core/src/types/chat_member.rs +++ b/crates/teloxide-core/src/types/chat_member.rs @@ -632,15 +632,46 @@ impl ChatMemberKind { } } + /// Returns `true` if the user is allowed to send audios, documents, photos, + /// videos, video notes and voice notes. + /// + /// I.e. returns **`false`** if the user + /// - has left or has been banned in the chat + /// - is restricted and doesn't have all send media right + /// Returns `true` otherwise. + #[must_use] + pub fn can_send_media_messages(&self) -> bool { + match &self { + Self::Restricted(Restricted { + can_send_audios, + can_send_documents, + can_send_photos, + can_send_videos, + can_send_video_notes, + can_send_voice_notes, + .. + }) => { + *can_send_audios + && *can_send_documents + && *can_send_photos + && *can_send_videos + && *can_send_video_notes + && *can_send_voice_notes + } + Self::Owner(_) | Self::Administrator(_) | Self::Member => true, + Self::Left | Self::Banned(_) => false, + } + } + /// Returns `true` if the user is allowed to send animations, games, /// stickers and use inline bots. /// /// I.e. returns **`false`** if the user /// - has left or has been banned from the chat - /// - is restricted and doesn't have the [`can_send_media_messages`] right + /// - is restricted and has no [`can_send_other_messages`] right /// Returns `true` otherwise. /// - /// [`can_send_media_messages`]: Restricted::can_send_media_messages + /// [`can_send_other_messages`]: Restricted::can_send_other_messages #[deprecated( since = "0.9.0", note = "Match manually and use `can_send_other_messages` field directly. Details: https://github.com/teloxide/teloxide/issues/781" @@ -661,10 +692,10 @@ impl ChatMemberKind { /// /// I.e. returns **`false`** if the user /// - has left or has been banned from the chat - /// - is restricted and doesn't have the [`can_send_media_messages`] right + /// - is restricted and has no [`can_add_web_page_previews`] right /// Returns `true` otherwise. /// - /// [`can_send_media_messages`]: Restricted::can_send_media_messages + /// [`can_add_web_page_previews`]: Restricted::can_add_web_page_previews #[deprecated( since = "0.9.0", note = "Match manually and use `can_add_web_page_previews` field directly. Details: https://github.com/teloxide/teloxide/issues/781" @@ -884,6 +915,7 @@ mod tests { "status":"restricted", "is_member": true, "can_send_messages": true, + "can_send_media_messages": true, "can_send_audios": false, "can_send_documents": false, "can_send_photos": true, diff --git a/crates/teloxide-core/src/types/chat_permissions.rs b/crates/teloxide-core/src/types/chat_permissions.rs index 67b6cddc..31b73e15 100644 --- a/crates/teloxide-core/src/types/chat_permissions.rs +++ b/crates/teloxide-core/src/types/chat_permissions.rs @@ -51,59 +51,69 @@ bitflags::bitflags! { /// locations and venues. const SEND_MESSAGES = 1; - /// Set if the user is allowed to send audios. - const SEND_AUDIOS = (1 << 1) | Self::SEND_MESSAGES.bits; - - /// Set if the user is allowed to send documents. - const SEND_DOCUMENTS = (1 << 2) | Self::SEND_MESSAGES.bits; - - /// Set if the user is allowed to send photos. - const SEND_PHOTOS = (1 << 3) | Self::SEND_MESSAGES.bits; - - /// Set if the user is allowed to send videos. - const SEND_VIDEOS = (1 << 4) | Self::SEND_MESSAGES.bits; - - /// Set if the user is allowed to send video notes. - const SEND_VIDEO_NOTES = (1 << 5) | Self::SEND_MESSAGES.bits; - - /// Set if the user is allowed to send voice notes. - const SEND_VOICE_NOTES = (1 << 6) | Self::SEND_MESSAGES.bits; - /// Set if the user is allowed to send polls, implies /// `SEND_MESSAGES`. - const SEND_POLLS = (1 << 7) | Self::SEND_MESSAGES.bits; + const SEND_POLLS = (1 << 2) | Self::SEND_MESSAGES.bits; /// Set if the user is allowed to send animations, games, stickers and - /// use inline bots, implies midia messages permissions. - const SEND_OTHER_MESSAGES = (1 << 8) | Self::SEND_AUDIOS.bits - | Self::SEND_DOCUMENTS.bits - | Self::SEND_PHOTOS.bits - | Self::SEND_VIDEOS.bits - | Self::SEND_VIDEO_NOTES.bits - | Self::SEND_VOICE_NOTES.bits; + /// use inline bots, implies `SEND_MEDIA_MESSAGES`. + const SEND_OTHER_MESSAGES = (1 << 3); /// Set if the user is allowed to add web page previews to - /// their messages, implies midia messages permissions. - const ADD_WEB_PAGE_PREVIEWS = (1 << 9) | Self::SEND_AUDIOS.bits - | Self::SEND_DOCUMENTS.bits - | Self::SEND_PHOTOS.bits - | Self::SEND_VIDEOS.bits - | Self::SEND_VIDEO_NOTES.bits - | Self::SEND_VOICE_NOTES.bits; + /// their messages, implies `SEND_MEDIA_MESSAGES`. + const ADD_WEB_PAGE_PREVIEWS = (1 << 4); /// Set if the user is allowed to change the chat title, photo and /// other settings. Ignored in public supergroups. - const CHANGE_INFO = (1 << 10); + const CHANGE_INFO = (1 << 5); /// Set if the user is allowed to invite new users to the chat. - const INVITE_USERS = (1 << 11); + const INVITE_USERS = (1 << 6); /// Set if the user is allowed to pin messages. Ignored in public /// supergroups. - const PIN_MESSAGES = (1 << 12); + const PIN_MESSAGES = (1 << 7); /// Set if the user is allowed to create, rename, close, and reopen forum topics. - const MANAGE_TOPICS = (1 << 13); + const MANAGE_TOPICS = (1 << 8); + + /// Set if the user is allowed to send audios. implies + /// `SEND_MESSAGES`. + const SEND_AUDIOS = (1 << 9) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send documents. implies + /// `SEND_MESSAGES`. + const SEND_DOCUMENTS = (1 << 10) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send photos. implies + /// `SEND_MESSAGES`. + const SEND_PHOTOS = (1 << 11) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send videos. implies + /// `SEND_MESSAGES`. + const SEND_VIDEOS = (1 << 12) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send video notes. implies + /// `SEND_MESSAGES`. + const SEND_VIDEO_NOTES = (1 << 13) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send voice notes. implies + /// `SEND_MESSAGES`. + const SEND_VOICE_NOTES = (1 << 14) | Self::SEND_MESSAGES.bits; + + /// Set if the user is allowed to send audios, documents, + /// photos, videos, video notes and voice notes, implies + /// `SEND_MESSAGES`, `SEND_AUDIOS`, `SEND_DOCUMENTS`, + /// `SEND_PHOTOS`, `SEND_VIDEOS`, `SEND_VIDEO_NOTES` and `SEND_VOICE_NOTES`. + /// Note: this is not a separate permission on it's own, this is just a alias for all the permissions mentioned. + const SEND_MEDIA_MESSAGES = Self::SEND_MESSAGES.bits + | Self::SEND_AUDIOS.bits + | Self::SEND_DOCUMENTS.bits + | Self::SEND_PHOTOS.bits + | Self::SEND_VIDEOS.bits + | Self::SEND_VIDEO_NOTES.bits + | Self::SEND_VOICE_NOTES.bits; + } } @@ -157,6 +167,13 @@ impl ChatPermissions { self.contains(ChatPermissions::SEND_VOICE_NOTES) } + /// Checks for [`SEND_MEDIA_MESSAGES`] permission. + /// + /// [`SEND_MEDIA_MESSAGES`]: ChatPermissions::SEND_MEDIA_MESSAGES + pub fn can_send_media_messages(&self) -> bool { + self.contains(ChatPermissions::SEND_MEDIA_MESSAGES) + } + /// Checks for [`SEND_POLLS`] permission. /// /// [`SEND_POLLS`]: ChatPermissions::SEND_POLLS diff --git a/crates/teloxide-core/src/types/chat_shared.rs b/crates/teloxide-core/src/types/chat_shared.rs new file mode 100644 index 00000000..4c75b94e --- /dev/null +++ b/crates/teloxide-core/src/types/chat_shared.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; + +use crate::types::ChatId; + +/// Information about the chat whose identifier was shared with the bot using a +/// [`KeyboardButtonRequestChat`] button. +/// +/// [`KeyboardButtonRequestChat`]: crate::types::KeyboardButtonRequestChat +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct ChatShared { + /// Identifier of the request. + pub request_id: i32, + /// Identifier of the shared chat. + pub chat_id: ChatId, +} diff --git a/crates/teloxide-core/src/types/keyboard_button.rs b/crates/teloxide-core/src/types/keyboard_button.rs index c6c3390d..42aab9bd 100644 --- a/crates/teloxide-core/src/types/keyboard_button.rs +++ b/crates/teloxide-core/src/types/keyboard_button.rs @@ -1,6 +1,8 @@ use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; -use crate::types::{KeyboardButtonPollType, True, WebAppInfo}; +use crate::types::{ + KeyboardButtonPollType, KeyboardButtonRequestChat, KeyboardButtonRequestUser, True, WebAppInfo, +}; /// This object represents one button of the reply keyboard. /// @@ -59,6 +61,18 @@ pub enum ButtonRequest { /// 9 April, 2016. Older clients will display unsupported message. Contact, + /// If this variant is used, pressing the button will open a list of + /// suitable chats. Tapping on a chat will send its identifier to the bot in + /// a [`chat_shared`] service message. + /// + /// [`chat_shared`]: crate::types::MessageKind::ChatShared + RequestChat(KeyboardButtonRequestChat), + + /// If this variant is used, pressing the button will open a list of + /// suitable users. Tapping on any user will send their identifier to the + /// bot in a “user_shared” service message. + RequestUser(KeyboardButtonRequestUser), + /// If this variant is used, the user will be asked to create a poll and /// send it to the bot when the button is pressed. /// @@ -89,6 +103,18 @@ struct RawRequest { #[serde(rename = "request_location")] location: Option, + /// If specified, pressing the button will open a list of suitable chats. + /// Tapping on a chat will send its identifier to the bot in a “chat_shared” + /// service message. Available in private chats only. + #[serde(rename = "request_chat")] + chat: Option, + + /// If specified, pressing the button will open a list of suitable users. + /// Tapping on any user will send their identifier to the bot in a + /// “user_shared” service message. Available in private chats only. + #[serde(rename = "request_user")] + user: Option, + /// If specified, the user will be asked to create a poll and /// send it to the bot when the button is pressed. Available in private /// chats only. @@ -108,25 +134,36 @@ impl<'de> Deserialize<'de> for ButtonRequest { { let raw = RawRequest::deserialize(deserializer)?; match raw { - RawRequest { contact, location, poll, web_app } + RawRequest { contact, location, chat, user, poll, web_app } if 1 < (contact.is_some() as u8 + location.is_some() as u8 + + chat.is_some() as u8 + + user.is_some() as u8 + poll.is_some() as u8 + web_app.is_some() as u8) => { Err(D::Error::custom( - "`request_contact`, `request_location`, `request_poll` and `web_app` fields \ - are mutually exclusive", + "`request_contact`, `request_location`, `request_chat`, `request_user`, \ + `request_poll` and `web_app` fields are mutually exclusive", )) } - RawRequest { contact: Some(_), .. } => Ok(Self::Contact), - RawRequest { location: Some(_), .. } => Ok(Self::Location), + RawRequest { contact: Some(True), .. } => Ok(Self::Contact), + RawRequest { location: Some(True), .. } => Ok(Self::Location), + RawRequest { chat: Some(request_chat), .. } => Ok(Self::RequestChat(request_chat)), + RawRequest { user: Some(request_user), .. } => Ok(Self::RequestUser(request_user)), RawRequest { poll: Some(poll_type), .. } => Ok(Self::Poll(poll_type)), RawRequest { web_app: Some(web_app), .. } => Ok(Self::WebApp(web_app)), - _ => Err(D::Error::custom( - "Either one of `request_contact`, `request_location`, `request_poll` and \ - `web_app` fields is required", + RawRequest { + contact: None, + location: None, + chat: None, + user: None, + poll: None, + web_app: None, + } => Err(D::Error::custom( + "Either one of `request_contact`, `request_chat`, `request_user`, \ + `request_location`, `request_poll` and `web_app` fields is required", )), } } @@ -137,11 +174,20 @@ impl Serialize for ButtonRequest { where S: Serializer, { - let mut raw = RawRequest { contact: None, location: None, poll: None, web_app: None }; + let mut raw = RawRequest { + contact: None, + location: None, + chat: None, + user: None, + poll: None, + web_app: None, + }; match self { Self::Contact => raw.contact = Some(True), Self::Location => raw.location = Some(True), + Self::RequestChat(request_chat) => raw.chat = Some(request_chat.clone()), + Self::RequestUser(request_user) => raw.user = Some(request_user.clone()), Self::Poll(poll_type) => raw.poll = Some(poll_type.clone()), Self::WebApp(web_app) => raw.web_app = Some(web_app.clone()), }; @@ -171,6 +217,17 @@ mod tests { assert_eq!(expected, actual); } + #[test] + fn serialize_chat_request() { + let button = KeyboardButton { + text: String::from(""), + request: Some(ButtonRequest::RequestChat(KeyboardButtonRequestChat::new(0, false))), + }; + let expected = r#"{"text":"","request_chat":{"request_id":0,"chat_is_channel":false}}"#; + let actual = serde_json::to_string(&button).unwrap(); + assert_eq!(expected, actual); + } + #[test] fn deserialize_no_request() { let json = r#"{"text":""}"#; diff --git a/crates/teloxide-core/src/types/keyboard_button_request_chat.rs b/crates/teloxide-core/src/types/keyboard_button_request_chat.rs new file mode 100644 index 00000000..fef4222b --- /dev/null +++ b/crates/teloxide-core/src/types/keyboard_button_request_chat.rs @@ -0,0 +1,114 @@ +use serde::{Deserialize, Serialize}; + +use crate::types::ChatAdministratorRights; + +/// This object defines the criteria used to request a suitable chat. The +/// identifier of the selected chat will be shared with the bot when the +/// corresponding button is pressed. [More about requesting chats »] +/// +/// [More about requesting chats »]: https://core.telegram.org/bots/features#chat-and-user-selection +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct KeyboardButtonRequestChat { + /// identifier of the request, which will be received back in the + /// [`ChatShared`] object. Must be unique within the message. + /// + /// [`ChatShared`]: crate::types::ChatShared + pub request_id: i32, + + /// Pass `true` to request a channel chat, pass `false` to request a group + /// or a supergroup chat. + pub chat_is_channel: bool, + + /// Pass `true` to request a forum supergroup, pass `false` to request a + /// non-forum chat. If not specified, no additional restrictions are + /// applied. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub chat_is_forum: Option, + + /// Pass `true` to request a supergroup or a channel with a username, pass + /// `false` to request a chat without a username. If not specified, no + /// additional restrictions are applied. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub chat_has_username: Option, + + /// Pass `true` to request a chat owned by the user. Otherwise, no + /// additional restrictions are applied. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub chat_is_created: Option, + + /// Listing the required administrator rights of the user in the chat. The + /// rights must be a superset of bot_administrator_rights. If not specified, + /// no additional restrictions are applied. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub user_administrator_rights: Option, + + /// Listing the required administrator rights of the bot in the chat. The + /// rights must be a subset of user_administrator_rights. If not specified, + /// no additional restrictions are applied. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub bot_administrator_rights: Option, + + /// Pass `true` to request a chat with the bot as a member. Otherwise, no + /// additional restrictions are applied. + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub bot_is_member: bool, +} + +impl KeyboardButtonRequestChat { + /// Creates a new [`KeyboardButtonRequestChat`]. + pub fn new(request_id: i32, chat_is_channel: bool) -> Self { + Self { + request_id, + chat_is_channel, + chat_is_forum: None, + chat_has_username: None, + chat_is_created: None, + user_administrator_rights: None, + bot_administrator_rights: None, + bot_is_member: false, + } + } + + /// Setter for `chat_is_forum` field. + #[must_use] + pub fn chat_is_forum(mut self, value: bool) -> Self { + self.chat_is_forum = Some(value); + self + } + + /// Setter for `chat_has_username` field. + #[must_use] + pub fn chat_has_username(mut self, value: bool) -> Self { + self.chat_has_username = Some(value); + self + } + + /// Setter for `chat_is_created` field. + #[must_use] + pub fn chat_is_created(mut self, value: bool) -> Self { + self.chat_is_created = Some(value); + self + } + + /// Request a chat where the user has the specified administrator rights. + #[must_use] + pub fn user_administrator_rights(mut self, rights: ChatAdministratorRights) -> Self { + self.user_administrator_rights = Some(rights); + self + } + + /// Request a chat where the bot has the specified administrator rights. + #[must_use] + pub fn bot_administrator_rights(mut self, rights: ChatAdministratorRights) -> Self { + self.bot_administrator_rights = Some(rights); + self + } + + /// Setter for `bot_is_member` field. + #[must_use] + pub fn bot_is_member(mut self, value: bool) -> Self { + self.bot_is_member = value; + self + } +} diff --git a/crates/teloxide-core/src/types/keyboard_button_request_user.rs b/crates/teloxide-core/src/types/keyboard_button_request_user.rs new file mode 100644 index 00000000..843b86d1 --- /dev/null +++ b/crates/teloxide-core/src/types/keyboard_button_request_user.rs @@ -0,0 +1,44 @@ +use serde::{Deserialize, Serialize}; + +/// This object defines the criteria used to request a suitable user. The +/// identifier of the selected user will be shared with the bot when the +/// corresponding button is pressed. More about requesting users » +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct KeyboardButtonRequestUser { + /// identifier of the request, which will be received back in the + /// [`UserShared`] object. Must be unique within the message. + /// + /// [`UserShared`]: crate::types::UserShared + pub request_id: i32, + + /// Pass `true` to request a bot, pass `false` to request a regular user. If + /// not specified, no additional restrictions are applied. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub user_is_bot: Option, + + /// Pass `true` to request a premium user, pass `false` to request a + /// non-premium user. If not specified, no additional restrictions are + /// applied. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub user_is_premium: Option, +} + +impl KeyboardButtonRequestUser { + /// Creates a new [`KeyboardButtonRequestUser`]. + pub fn new(request_id: i32) -> Self { + Self { request_id, user_is_bot: None, user_is_premium: None } + } + + /// Setter for `user_is_bot` field + pub fn user_is_bot(mut self, value: bool) -> Self { + self.user_is_bot = Some(value); + self + } + + /// Setter for `user_is_premium` field + pub fn user_is_premium(mut self, value: bool) -> Self { + self.user_is_premium = Some(value); + self + } +} diff --git a/crates/teloxide-core/src/types/message.rs b/crates/teloxide-core/src/types/message.rs index 781aab72..d988fad5 100644 --- a/crates/teloxide-core/src/types/message.rs +++ b/crates/teloxide-core/src/types/message.rs @@ -5,12 +5,12 @@ use serde::{Deserialize, Serialize}; use url::Url; use crate::types::{ - Animation, Audio, BareChatId, Chat, ChatId, Contact, Dice, Document, ForumTopicClosed, - ForumTopicCreated, ForumTopicEdited, ForumTopicReopened, Game, GeneralForumTopicHidden, - GeneralForumTopicUnhidden, InlineKeyboardMarkup, Invoice, Location, + Animation, Audio, BareChatId, Chat, ChatId, ChatShared, Contact, Dice, Document, + ForumTopicClosed, ForumTopicCreated, ForumTopicEdited, ForumTopicReopened, Game, + GeneralForumTopicHidden, GeneralForumTopicUnhidden, InlineKeyboardMarkup, Invoice, Location, MessageAutoDeleteTimerChanged, MessageEntity, MessageEntityRef, MessageId, PassportData, PhotoSize, Poll, ProximityAlertTriggered, Sticker, SuccessfulPayment, ThreadId, True, User, - Venue, Video, VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled, + UserShared, Venue, Video, VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled, VideoChatStarted, VideoNote, Voice, WebAppData, WriteAccessAllowed, }; @@ -60,6 +60,8 @@ pub enum MessageKind { ChannelChatCreated(MessageChannelChatCreated), MessageAutoDeleteTimerChanged(MessageMessageAutoDeleteTimerChanged), Pinned(MessagePinned), + ChatShared(MessageChatShared), + UserShared(MessageUserShared), Invoice(MessageInvoice), SuccessfulPayment(MessageSuccessfulPayment), ConnectedWebsite(MessageConnectedWebsite), @@ -247,6 +249,18 @@ pub struct MessagePinned { pub pinned: Box, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageChatShared { + /// A chat was shared with the bot. + pub chat_shared: ChatShared, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageUserShared { + /// A chat was shared with the bot. + pub user_shared: UserShared, +} + #[serde_with_macros::skip_serializing_none] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct MessageInvoice { @@ -655,12 +669,13 @@ mod getters { self, message::MessageKind::*, Chat, ChatId, ChatMigration, Forward, ForwardedFrom, MediaAnimation, MediaAudio, MediaContact, MediaDocument, MediaGame, MediaKind, MediaLocation, MediaPhoto, MediaPoll, MediaSticker, MediaText, MediaVenue, MediaVideo, - MediaVideoNote, MediaVoice, Message, MessageChannelChatCreated, MessageCommon, - MessageConnectedWebsite, MessageDeleteChatPhoto, MessageDice, MessageEntity, + MediaVideoNote, MediaVoice, Message, MessageChannelChatCreated, MessageChatShared, + MessageCommon, MessageConnectedWebsite, MessageDeleteChatPhoto, MessageDice, MessageEntity, MessageGroupChatCreated, MessageId, MessageInvoice, MessageLeftChatMember, MessageNewChatMembers, MessageNewChatPhoto, MessageNewChatTitle, MessagePassportData, MessagePinned, MessageProximityAlertTriggered, MessageSuccessfulPayment, - MessageSupergroupChatCreated, MessageVideoChatParticipantsInvited, PhotoSize, User, + MessageSupergroupChatCreated, MessageUserShared, MessageVideoChatParticipantsInvited, + PhotoSize, User, }; use super::{ @@ -1269,6 +1284,22 @@ mod getters { } } + #[must_use] + pub fn shared_chat(&self) -> Option<&types::ChatShared> { + match &self.kind { + ChatShared(MessageChatShared { chat_shared }) => Some(chat_shared), + _ => None, + } + } + + #[must_use] + pub fn shared_user(&self) -> Option<&types::UserShared> { + match &self.kind { + UserShared(MessageUserShared { user_shared }) => Some(user_shared), + _ => None, + } + } + #[must_use] pub fn dice(&self) -> Option<&types::Dice> { match &self.kind { @@ -1699,6 +1730,56 @@ mod tests { assert!(message.is_ok()); } + #[test] + fn de_shared_chat() { + let json = r#"{ + "message_id": 198283, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1567927221, + "chat_shared": { + "request_id": 348349, + "chat_id": 384939 + } + }"#; + let message = from_str::(json); + assert!(message.is_ok()); + assert_eq!( + message.unwrap(), + Message { + id: MessageId(198283), + thread_id: None, + date: chrono::NaiveDateTime::from_timestamp_opt(1567927221, 0).unwrap().and_utc(), + chat: Chat { + id: ChatId(250918540), + kind: ChatKind::Private(ChatPrivate { + first_name: Some("Андрей".to_string()), + last_name: Some("Власов".to_string()), + username: Some("aka_dude".to_string()), + bio: None, + emoji_status_custom_emoji_id: None, + has_private_forwards: None, + has_restricted_voice_and_video_messages: None + }), + photo: None, + has_aggressive_anti_spam_enabled: false, + pinned_message: None, + message_auto_delete_time: None, + has_hidden_members: false + }, + kind: MessageKind::ChatShared(MessageChatShared { + chat_shared: ChatShared { request_id: 348349, chat_id: ChatId(384939) } + }), + via_bot: None + } + ); + } + #[test] fn de_media_group_forwarded() { let json = r#"{ diff --git a/crates/teloxide-core/src/types/user_shared.rs b/crates/teloxide-core/src/types/user_shared.rs new file mode 100644 index 00000000..1fd0cefe --- /dev/null +++ b/crates/teloxide-core/src/types/user_shared.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; + +use crate::types::UserId; + +/// Information about the chat whose identifier was shared with the bot using a +/// [`KeyboardButtonRequestUser`] button. +/// +/// [`KeyboardButtonRequestUser`]: crate::types::KeyboardButtonRequestUser +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct UserShared { + /// Identifier of the request. + pub request_id: i32, + /// Identifier of the shared user. + pub user_id: UserId, +} From 43d93268d068022a981098104b64f4c210d8cfae Mon Sep 17 00:00:00 2001 From: Awiteb Date: Tue, 6 Feb 2024 06:41:52 +0300 Subject: [PATCH 21/41] Update `teloxide-core/CHANGELOG.md` --- crates/teloxide-core/CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index f8d06ed7..8749dc25 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -33,6 +33,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `video_chat_ended` - `web_app_data` - `is_delete_chat_photo`, `is_group_chat_created`, `is_super_group_chat_created`, `is_channel_chat_created` functions to `Message` ([#982][pr982]) +- Support for TBA 6.5 ([#954][pr954]) + - Add `can_send_audios`, `can_send_documents`, `can_send_photos`, `can_send_videos`, `can_send_video_notes`, and `can_send_voice_notes` to `ChatPermissions` and `Restricted` + - Add `use_independent_chat_permissions` optional parameter to `restrict_chat_member` and `set_chat_permissions` + - Add `user_chat_id` field to `ChatJoinRequest` + - Add `KeyboardButtonRequestChat` and `ChatShared` types + - Add `RequestChat` variant to `ButtonRequest` + - Add `ChatShared` variant to `MessageKind` + - Add `shared_chat` method to `Message` + - Add `KeyboardButtonRequestUser` and `UserShared` types + - Add `RequestUser` variant to `ButtonRequest` + - Add `UserShared` variant to `MessageKind` + - Add `shared_user` method to `Message` [pr851]: https://github.com/teloxide/teloxide/pull/851 [pr887]: https://github.com/teloxide/teloxide/pull/887 @@ -104,6 +116,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [pr850]: https://github.com/teloxide/teloxide/pull/850 +### Removed +- Remove `can_send_media_messages` from `ChatPermissions` ([#954][pr954]) +- Remove `can_send_media_messages` field from `Restricted` ([#954][pr954]) + +[pr954]: https://github.com/teloxide/teloxide/pull/954 + ### Fixed - Deserialization of `ApiError::CantParseEntities` ([#839][pr839]) From 423ef411a928d4c2c61d9d063a5ed0275229ef60 Mon Sep 17 00:00:00 2001 From: TheAwiteb Date: Sun, 7 Jan 2024 11:30:16 +0300 Subject: [PATCH 22/41] Update README.md Update the telegram support badge version to 6.5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45153b31..c0029f0f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ - + From 8ffac3802c31f73457e2541bb47c012bc377e967 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 8 Feb 2024 20:32:45 +0100 Subject: [PATCH 23/41] fixup clippy --- crates/teloxide-core/src/errors.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/teloxide-core/src/errors.rs b/crates/teloxide-core/src/errors.rs index 7e07dc8b..08d140e8 100644 --- a/crates/teloxide-core/src/errors.rs +++ b/crates/teloxide-core/src/errors.rs @@ -144,12 +144,14 @@ macro_rules! impl_api_error { } }; (@de $value:ident, $variant:ident ($var_inner:ty), $val:literal, $block:expr) => { + #[allow(clippy::redundant_closure_call)] match $block($value) { Some(data) => return Ok(Self::Value::$variant(data)), _ => {} } }; (@de $value:ident, $variant:ident, $val:literal, $block:expr) => { + #[allow(clippy::redundant_closure_call)] if $block($value) { return Ok(Self::Value::$variant); } From 199a9a8acc9b314e8bf5984a2b2901dbee74a540 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 14:33:48 +0100 Subject: [PATCH 24/41] Pin ahash version --- crates/teloxide/Cargo.toml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/teloxide/Cargo.toml b/crates/teloxide/Cargo.toml index 8286a3a7..7a708572 100644 --- a/crates/teloxide/Cargo.toml +++ b/crates/teloxide/Cargo.toml @@ -23,7 +23,11 @@ default = ["native-tls", "ctrlc_handler", "teloxide-core/default", "auto-send"] webhooks = ["rand"] webhooks-axum = ["webhooks", "axum", "tower", "tower-http"] -sqlite-storage-nativetls = ["sqlx", "sqlx/runtime-tokio-native-tls", "native-tls"] +sqlite-storage-nativetls = [ + "sqlx", + "sqlx/runtime-tokio-native-tls", + "native-tls", +] sqlite-storage-rustls = ["sqlx", "sqlx/runtime-tokio-rustls", "rustls"] redis-storage = ["redis"] cbor-serializer = ["serde_cbor"] @@ -110,6 +114,9 @@ tower = { version = "0.4.12", optional = true } tower-http = { version = "0.3.4", features = ["trace"], optional = true } rand = { version = "0.8.5", optional = true } +# HACK: ahash 0.8.7 bumped MSRV to 1.72, to keep MVSR 1.68 we need to depend on an older version. +# this can be removed once our MSRV crosses 1.72. +ahash = "=0.8.7" [dev-dependencies] rand = "0.8.3" @@ -146,7 +153,11 @@ required-features = ["redis-storage", "cbor-serializer", "bincode-serializer"] [[test]] name = "sqlite" path = "tests/sqlite.rs" -required-features = ["sqlite-storage-nativetls", "cbor-serializer", "bincode-serializer"] +required-features = [ + "sqlite-storage-nativetls", + "cbor-serializer", + "bincode-serializer", +] [[example]] From 2a17e625fceb3707b7c160d57c1971bc62831602 Mon Sep 17 00:00:00 2001 From: Tima Kinsart Date: Tue, 13 Feb 2024 23:34:24 +0800 Subject: [PATCH 25/41] =?UTF-8?q?Link=20Troy=20K=C3=B6hler's=20tutorials?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 45153b31..64b4db1e 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,11 @@ async fn receive_location( [More examples >>](crates/teloxide/examples/) +## Tutorials + + - [_"Migrating my family finance bot from Python to Rust (teloxide) because I am tired of exceptions (part 1)"_](https://trkohler.com/posts/i-migrated-my-family-finance-bot-from-python-to-rust-because-i-am-tired-of-exceptions/) by Troy Köhler. + - [_"Migrating my family finance bot from Python to Rust (teloxide) [part 2]"_](https://trkohler.com/posts/migrating-my-family-finance-bot-from-python-to-rust-teloxide-part-2/) by Troy Köhler. + ## FAQ **Q: Where I can ask questions?** From 8c3aa66af56bd80ba8597f64b000b64f34e41098 Mon Sep 17 00:00:00 2001 From: Waffle Maybe Date: Tue, 13 Feb 2024 19:47:23 +0100 Subject: [PATCH 26/41] Add more auto labeling to teloxidebot --- triagebot.toml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 3ff64fb3..54a675ea 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -28,6 +28,29 @@ trigger_files = ["crates/teloxide/"] [autolabel."C-macros"] trigger_files = ["crates/teloxide-macros/"] +[autolabel."A-dialogue"] +trigger_files = ["crates/teloxide/src/dispatching/dialogue/"] + +[autolabel."A-dispatching"] +trigger_files = ["crates/teloxide/src/dispatching/"] + +[autolabel."A-macros"] +trigger_files = ["crates/teloxide-macros/"] + +[autolabel."A-requester"] +trigger_files = ["crates/teloxide-core/src/requests/requester.rs", "crates/teloxide-core/src/requests/requester_ext.rs"] + +[autolabel."A-requests"] +trigger_files = ["crates/teloxide-core/src/requests/", "crates/teloxide-core/src/payloads/"] + +[autolabel."A-tba-errors"] +trigger_files = ["crates/teloxide-core/src/errors.rs"] + +[autolabel."A-tba-types"] +trigger_files = ["crates/teloxide-core/src/types"] + +[autolabel."A-update-listeners"] +trigger_files = ["crates/teloxide/src/update_listeners"] [relabel] allow-unauthenticated = [ From 8bbe0ecf1a3826eaf7e83b622a53c03a45fb0c97 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 20:22:17 +0100 Subject: [PATCH 27/41] Remove auto send adaptor It has become useless a while ago. --- crates/teloxide-core/CHANGELOG.md | 4 + crates/teloxide-core/Cargo.toml | 5 +- crates/teloxide-core/src/adaptors.rs | 15 -- .../teloxide-core/src/adaptors/auto_send.rs | 233 ------------------ crates/teloxide-core/src/lib.rs | 1 - .../src/requests/requester_ext.rs | 19 -- crates/teloxide/Cargo.toml | 4 +- crates/teloxide/src/features.md | 1 - crates/teloxide/src/prelude.rs | 4 - 9 files changed, 6 insertions(+), 280 deletions(-) delete mode 100644 crates/teloxide-core/src/adaptors/auto_send.rs diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index 258f0d0e..0ed9a13a 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -117,10 +117,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [pr850]: https://github.com/teloxide/teloxide/pull/850 ### Removed + - Remove `can_send_media_messages` from `ChatPermissions` ([#954][pr954]) - Remove `can_send_media_messages` field from `Restricted` ([#954][pr954]) +- Previously deprecated items ([#1013][pr1013]) + - `AutoSend` bot adaptor [pr954]: https://github.com/teloxide/teloxide/pull/954 +[pr1013]: https://github.com/teloxide/teloxide/pull/1013 ### Fixed diff --git a/crates/teloxide-core/Cargo.toml b/crates/teloxide-core/Cargo.toml index ab9addb7..b68731fc 100644 --- a/crates/teloxide-core/Cargo.toml +++ b/crates/teloxide-core/Cargo.toml @@ -42,11 +42,8 @@ erased = [] # CacheMe bot adaptor cache_me = [] -# AutoSend bot adaptor -auto_send = [] - # All features except nightly and tls-related -full = ["throttle", "trace_adaptor", "erased", "cache_me", "auto_send"] +full = ["throttle", "trace_adaptor", "erased", "cache_me"] [dependencies] diff --git a/crates/teloxide-core/src/adaptors.rs b/crates/teloxide-core/src/adaptors.rs index c54a65ec..070c1a24 100644 --- a/crates/teloxide-core/src/adaptors.rs +++ b/crates/teloxide-core/src/adaptors.rs @@ -5,18 +5,6 @@ //! //! [`Requester`]: crate::requests::Requester -/// [`AutoSend`] bot adaptor which used to allow sending a request without -/// calling [`send`]. -/// -/// [`AutoSend`]: auto_send::AutoSend -/// [`send`]: crate::requests::Request::send -#[cfg(feature = "auto_send")] -#[deprecated( - since = "0.8.0", - note = "`AutoSend` is no longer required to `.await` requests and is now noop" -)] -pub mod auto_send; - /// [`CacheMe`] bot adaptor which caches [`GetMe`] requests. /// /// [`CacheMe`]: cache_me::CacheMe @@ -47,9 +35,6 @@ pub mod throttle; mod parse_mode; -#[cfg(feature = "auto_send")] -#[allow(deprecated)] -pub use auto_send::AutoSend; #[cfg(feature = "cache_me")] pub use cache_me::CacheMe; #[cfg(feature = "erased")] diff --git a/crates/teloxide-core/src/adaptors/auto_send.rs b/crates/teloxide-core/src/adaptors/auto_send.rs deleted file mode 100644 index f72a6e1b..00000000 --- a/crates/teloxide-core/src/adaptors/auto_send.rs +++ /dev/null @@ -1,233 +0,0 @@ -use std::future::IntoFuture; - -use url::Url; - -use crate::{ - requests::{HasPayload, Output, Request, Requester}, - types::*, -}; - -/// Previously was used to send requests automatically. -/// -/// Before addition of [`IntoFuture`] you could only `.await` [`Future`]s. -/// This adaptor turned requests into futures, allowing to `.await` them, -/// without calling `.send()`. -/// -/// Now, however, all requests are required to implement `IntoFuture`, allowing -/// you to `.await` them directly. This adaptor is noop, and shouldn't be used. -/// -/// [`Future`]: std::future::Future -#[derive(Clone, Debug)] -pub struct AutoSend { - bot: B, -} - -impl AutoSend { - /// Creates new `AutoSend`. - /// - /// Note: it's recommended to use [`RequesterExt::auto_send`] instead. - /// - /// [`RequesterExt::auto_send`]: crate::requests::RequesterExt::auto_send - pub fn new(inner: B) -> AutoSend { - Self { bot: inner } - } - - /// Allows to access the inner bot. - pub fn inner(&self) -> &B { - &self.bot - } - - /// Unwraps the inner bot. - pub fn into_inner(self) -> B { - self.bot - } -} - -macro_rules! f { - ($m:ident $this:ident ($($arg:ident : $T:ty),*)) => { - AutoRequest::new($this.inner().$m($($arg),*)) - }; -} - -macro_rules! fty { - ($T:ident) => { - AutoRequest - }; -} - -impl Requester for AutoSend -where - B: Requester, -{ - type Err = B::Err; - - requester_forward! { - get_me, - log_out, - close, - get_updates, - set_webhook, - delete_webhook, - get_webhook_info, - forward_message, - copy_message, - send_message, - send_photo, - send_audio, - send_document, - send_video, - send_animation, - send_voice, - send_video_note, - send_media_group, - send_location, - edit_message_live_location, - edit_message_live_location_inline, - stop_message_live_location, - stop_message_live_location_inline, - send_venue, - send_contact, - send_poll, - send_dice, - send_chat_action, - get_user_profile_photos, - get_file, - kick_chat_member, - ban_chat_member, - unban_chat_member, - restrict_chat_member, - promote_chat_member, - set_chat_administrator_custom_title, - ban_chat_sender_chat, - unban_chat_sender_chat, - set_chat_permissions, - export_chat_invite_link, - create_chat_invite_link, - edit_chat_invite_link, - revoke_chat_invite_link, - set_chat_photo, - delete_chat_photo, - set_chat_title, - set_chat_description, - pin_chat_message, - unpin_chat_message, - unpin_all_chat_messages, - leave_chat, - get_chat, - get_chat_administrators, - get_chat_members_count, - get_chat_member_count, - get_chat_member, - set_chat_sticker_set, - delete_chat_sticker_set, - get_forum_topic_icon_stickers, - create_forum_topic, - edit_forum_topic, - close_forum_topic, - reopen_forum_topic, - delete_forum_topic, - unpin_all_forum_topic_messages, - edit_general_forum_topic, - close_general_forum_topic, - reopen_general_forum_topic, - hide_general_forum_topic, - unhide_general_forum_topic, - answer_callback_query, - set_my_commands, - get_my_commands, - set_chat_menu_button, - get_chat_menu_button, - set_my_default_administrator_rights, - get_my_default_administrator_rights, - delete_my_commands, - answer_inline_query, - answer_web_app_query, - edit_message_text, - edit_message_text_inline, - edit_message_caption, - edit_message_caption_inline, - edit_message_media, - edit_message_media_inline, - edit_message_reply_markup, - edit_message_reply_markup_inline, - stop_poll, - delete_message, - send_sticker, - get_sticker_set, - get_custom_emoji_stickers, - upload_sticker_file, - create_new_sticker_set, - add_sticker_to_set, - set_sticker_position_in_set, - delete_sticker_from_set, - set_sticker_set_thumb, - send_invoice, - create_invoice_link, - answer_shipping_query, - answer_pre_checkout_query, - set_passport_data_errors, - send_game, - set_game_score, - set_game_score_inline, - get_game_high_scores, - approve_chat_join_request, - decline_chat_join_request - => f, fty - } -} - -download_forward! { - B - AutoSend - { this => this.inner() } -} - -#[must_use = "Futures are lazy and do nothing unless polled or awaited"] -pub struct AutoRequest(R); - -impl AutoRequest -where - R: Request, -{ - pub fn new(inner: R) -> Self { - Self(inner) - } -} - -impl Request for AutoRequest -where - R: Request, -{ - type Err = R::Err; - type Send = R::Send; - type SendRef = R::SendRef; - - fn send(self) -> Self::Send { - self.0.send() - } - - fn send_ref(&self) -> Self::SendRef { - self.0.send_ref() - } -} - -impl IntoFuture for AutoRequest { - type Output = Result, ::Err>; - type IntoFuture = ::Send; - - fn into_future(self) -> Self::IntoFuture { - self.send() - } -} - -impl HasPayload for AutoRequest { - type Payload = R::Payload; - - fn payload_mut(&mut self) -> &mut Self::Payload { - self.0.payload_mut() - } - - fn payload_ref(&self) -> &Self::Payload { - self.0.payload_ref() - } -} diff --git a/crates/teloxide-core/src/lib.rs b/crates/teloxide-core/src/lib.rs index 679a4859..9c5ae94c 100644 --- a/crates/teloxide-core/src/lib.rs +++ b/crates/teloxide-core/src/lib.rs @@ -47,7 +47,6 @@ //! - `nightly` — enables nightly-only features, currently: //! - Removes some future boxing using `#![feature(type_alias_impl_trait)]` //! - Used to built docs (`#![feature(doc_cfg, doc_notable_trait)]`) -//! - `auto_send` — enables [`AutoSend`] bot adaptor (deprecated) //! //! [`AutoSend`]: adaptors::AutoSend //! [`Trace`]: adaptors::Trace diff --git a/crates/teloxide-core/src/requests/requester_ext.rs b/crates/teloxide-core/src/requests/requester_ext.rs index 4f5c5751..a5726ff6 100644 --- a/crates/teloxide-core/src/requests/requester_ext.rs +++ b/crates/teloxide-core/src/requests/requester_ext.rs @@ -3,10 +3,6 @@ use crate::{adaptors::DefaultParseMode, requests::Requester, types::ParseMode}; #[cfg(feature = "cache_me")] use crate::adaptors::CacheMe; -#[cfg(feature = "auto_send")] -#[allow(deprecated)] -use crate::adaptors::AutoSend; - #[cfg(feature = "erased")] use crate::adaptors::ErasedRequester; @@ -28,21 +24,6 @@ pub trait RequesterExt: Requester { CacheMe::new(self) } - /// Send requests automatically, see [`AutoSend`] for more. - #[cfg(feature = "auto_send")] - #[must_use] - #[deprecated( - since = "0.8.0", - note = "`AutoSend` is no longer required to `.await` requests and is now noop" - )] - #[allow(deprecated)] - fn auto_send(self) -> AutoSend - where - Self: Sized, - { - AutoSend::new(self) - } - /// Erase requester type. #[cfg(feature = "erased")] #[must_use] diff --git a/crates/teloxide/Cargo.toml b/crates/teloxide/Cargo.toml index 7a708572..58dc3a6b 100644 --- a/crates/teloxide/Cargo.toml +++ b/crates/teloxide/Cargo.toml @@ -18,7 +18,7 @@ categories = ["web-programming", "api-bindings", "asynchronous"] [features] -default = ["native-tls", "ctrlc_handler", "teloxide-core/default", "auto-send"] +default = ["native-tls", "ctrlc_handler", "teloxide-core/default"] webhooks = ["rand"] webhooks-axum = ["webhooks", "axum", "tower", "tower-http"] @@ -39,7 +39,6 @@ ctrlc_handler = ["tokio/signal"] native-tls = ["teloxide-core/native-tls"] rustls = ["teloxide-core/rustls"] -auto-send = ["teloxide-core/auto_send"] throttle = ["teloxide-core/throttle"] cache-me = [ "teloxide-core/cache_me", @@ -65,7 +64,6 @@ full = [ "teloxide-core/full", "native-tls", "rustls", - "auto-send", "throttle", "cache-me", "trace-adaptor", diff --git a/crates/teloxide/src/features.md b/crates/teloxide/src/features.md index 50a28701..e8ab3339 100644 --- a/crates/teloxide/src/features.md +++ b/crates/teloxide/src/features.md @@ -6,7 +6,6 @@ | `webhooks-axum` | Enables webhook implementation based on axum framework. | | `macros` | Re-exports macros from [`teloxide-macros`]. | | `ctrlc_handler` | Enables the [`DispatcherBuilder::enable_ctrlc_handler`] function (**enabled by default**). | -| `auto-send` | Enables the [`AutoSend`](adaptors::AutoSend) bot adaptor (**enabled by default; DEPRECATED**). | | `throttle` | Enables the [`Throttle`](adaptors::Throttle) bot adaptor. | | `cache-me` | Enables the [`CacheMe`](adaptors::CacheMe) bot adaptor. | | `trace-adaptor` | Enables the [`Trace`](adaptors::Trace) bot adaptor. | diff --git a/crates/teloxide/src/prelude.rs b/crates/teloxide/src/prelude.rs index 00c7fb2e..78db754b 100644 --- a/crates/teloxide/src/prelude.rs +++ b/crates/teloxide/src/prelude.rs @@ -20,10 +20,6 @@ pub use teloxide_core::{ }, }; -#[cfg(feature = "auto-send")] -#[allow(deprecated)] -pub use crate::adaptors::AutoSend; - #[doc(no_inline)] pub use teloxide_core::prelude::*; From e4f3ec78a249a63ad7e9df5bd446badec79e818e Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 20:36:21 +0100 Subject: [PATCH 28/41] Fix typos in changelog --- CHANGELOG.md | 2 +- crates/teloxide-core/CHANGELOG.md | 29 +++++++++++++---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37321ac8..626b4583 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use `UserId` instead of `i64` for `user_id` in `html::user_mention` and `markdown::user_mention` ([PR 896](https://github.com/teloxide/teloxide/pull/896)) - Greatly improved the speed of graceful shutdown (`^C`) ([PR 938](https://github.com/teloxide/teloxide/pull/938)) -- Fix typos in docstrings ([PR 953](https://github.com/teloxide/teloxide/pull/953)) +- Fix typos in documentation ([PR 953](https://github.com/teloxide/teloxide/pull/953)) - Use `Seconds` instead of `String` in `InlineQueryResultAudio` for `audio_duration` ([PR 994](https://github.com/teloxide/teloxide/pull/994)) - High CPU usage on network errors ([PR 1002](https://github.com/teloxide/teloxide/pull/1002), [Issue 780](https://github.com/teloxide/teloxide/issues/780)) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index 0ed9a13a..f6077121 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -57,7 +57,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove `latitude` and `longitude` parameters from `stop_message_live_location` and `stop_message_live_location_inline` ([#854][pr854]) - Fix the type of `photo_size`,`photo_width` and `photo_height` in the `send_invoice` method ([#936][pr936]) - Fix roundtrip de/serialization of `InlineQueryResult` ([#990][pr990]) +- Deserialization of `ApiError::CantParseEntities` ([#839][pr839]) +- Deserialization of empty (content-less) messages that can sometimes appear as a part of callback query ([#850][pr850], issue [#873][issue873]) +[pr839]: https://github.com/teloxide/teloxide/pull/839 +[pr879]: https://github.com/teloxide/teloxide/pull/879 +[issue873]: https://github.com/teloxide/teloxide/issues/873 [pr854]: https://github.com/teloxide/teloxide/pull/854 [pr936]: https://github.com/teloxide/teloxide/pull/936 [pr990]: https://github.com/teloxide/teloxide/pull/990 @@ -88,7 +93,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `message_thread_id` method parameters now use `ThreadId` instead of `i32` ([#887][pr887]) - `DiceEmoji` variant order ([#887][pr887]) - `Dice::value` now use `u8`, instead of `i32` ([#887][pr887]) -- `Invoice::total_amount`, `LabeledPrice::amount`, `PreCheckoutQuery::total_amount`, `SuccessfulPayment::total_amout` now use `u32`, instead of `i32` ([#887][pr887]) +- `Invoice::total_amount`, `LabeledPrice::amount`, `PreCheckoutQuery::total_amount`, `SuccessfulPayment::total_amount` now use `u32`, instead of `i32` ([#887][pr887]) - `Forward::message_id` and `Message::forward_from_message_id` now use `MessageId` instead of `i32` ([#887][pr887]) - `Poll::total_voter_count` and `PollOption::voter_count` now use `u32` instead of `i32` ([#887][pr887]) - `PollAnswer::option_ids` now use `u8` instead of `i32` ([#887][pr887]) @@ -126,14 +131,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [pr954]: https://github.com/teloxide/teloxide/pull/954 [pr1013]: https://github.com/teloxide/teloxide/pull/1013 -### Fixed - -- Deserialization of `ApiError::CantParseEntities` ([#839][pr839]) -- Deserialization of empty (content-less) messages that can sometimes appear as a part of callback query ([#850][pr850], issue [#873][issue873]) - -[pr839]: https://github.com/teloxide/teloxide/pull/839 -[pr879]: https://github.com/teloxide/teloxide/pull/879 -[issue873]: https://github.com/teloxide/teloxide/issues/873 ## 0.9.1 - 2023-02-15 @@ -388,7 +385,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - `user.id` now uses `UserId` type, `ChatId` now represents only _chat id_, not channel username, all `chat_id` function parameters now accept `Recipient` [**BC**] -- Improve `Throttling` adoptor ([#130][pr130]) +- Improve `Throttling` adaptor ([#130][pr130]) - Freeze when getting `RetryAfter(_)` error - Retry requests that previously returned `RetryAfter(_)` error - `RequestError::RetryAfter` now has a `Duration` field instead of `i32` @@ -514,7 +511,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Mark `ApiError` as `non_exhaustive` ([#125][pr125]) - `InputFile` and related structures now do **not** implement `PartialEq`, `Eq` and `Hash` ([#133][pr133]) - How forwarded messages are represented ([#151][pr151]) -- `RequestError::InvalidJson` now has a `raw` field with raw json for easier debugability ([#150][pr150]) +- `RequestError::InvalidJson` now has a `raw` field with raw json for easier debuggability ([#150][pr150]) - `ChatPermissions` is now bitflags ([#157][pr157]) - Type of `WebhookInfo::ip_address` from `Option` to `Option` ([#172][pr172]) - Type of `WebhookInfo::allowed_updates` from `Option>` to `Option>` ([#174][pr174]) @@ -592,7 +589,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `impl Clone` for {`CacheMe`, `DefaultParseMode`, `Throttle`} ([#76][pr76]) - `DefaultParseMode::parse_mode` which allows to get currently used default parse mode ([#77][pr77]) -- `Thrrotle::{limits,set_limits}` functions ([#77][pr77]) +- `Throttle::{limits,set_limits}` functions ([#77][pr77]) - `Throttle::{with_settings,spawn_with_settings}` and `throttle::Settings` ([#96][pr96]) - Getters for fields nested in `Chat` ([#80][pr80]) - API errors: `ApiError::NotEnoughRightsToManagePins`, `ApiError::BotKickedFromSupergroup` ([#84][pr84]) @@ -669,7 +666,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Refactor `ReplyMarkup` ([#pr65][pr65]) (**BC**) - Rename `ReplyMarkup::{InlineKeyboardMarkup => InlineKeyboard, ReplyKeyboardMarkup => Keyboard, ReplyKeyboardRemove => KeyboardRemove}` - - Add `inline_kb`, `keyboad`, `kb_remove` and `force_reply` `ReplyMarkup` consructors + - Add `inline_kb`, `keyboad`, `kb_remove` and `force_reply` `ReplyMarkup` constructors - Rename `ReplyKeyboardMarkup` => `KeyboardMarkup` - Rename `ReplyKeyboardRemove` => `KeyboardRemove` - Remove useless generic param from `ReplyKeyboardMarkup::new` and `InlineKeyboardMarkup::new` @@ -683,7 +680,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- `GetUpdatesFaultTolerant` - fault toletant version of `GetUpdates` ([#58][pr58]) (**BC**) +- `GetUpdatesFaultTolerant` - fault tolerant version of `GetUpdates` ([#58][pr58]) (**BC**) - Derive `Clone` for `AutoSend`. [pr58]: https://github.com/teloxide/teloxide-core/pull/58 @@ -785,7 +782,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Make `net::{TELEGRAM_API_URL, download_file{,_stream}}` pub - Refactor `Bot` ([#29][pr29]): - Move default parse mode to an adaptor (`DefaultParseMode`) - - Remove bot builder (it's not usefull anymore, since parse_mode is moved away) + - Remove bot builder (it's not useful anymore, since parse_mode is moved away) - Undeprecate bot constructors (`Bot::{new, with_client, from_env_with_client}`) - Rename `StickerType` => `InputSticker`, `{CreateNewStickerSet,AddStickerToSet}::sticker_type}` => `sticker` ([#23][pr23], [#43][pr43]) - Use `_: IntoIterator` bound instead of `_: Into>` in telegram methods which accept collections ([#21][pr21]) @@ -813,7 +810,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed -- `unstable-stream` feature (now `Bot::download_file_stream` is accesable by default) +- `unstable-stream` feature (now `Bot::download_file_stream` is accessible by default) - old `Request` trait - `RequestWithFile`, now multipart requests use `Request` - Remove all `#[non_exhaustive]` annotations ([#4][pr4]) From a69d0f17522a876e58a51065be8bc145381ddb5a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 20:36:36 +0100 Subject: [PATCH 29/41] Fixup supported TBA version in docs --- crates/teloxide-core/README.md | 2 +- crates/teloxide-core/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/teloxide-core/README.md b/crates/teloxide-core/README.md index d059b7c1..60bf2a2f 100644 --- a/crates/teloxide-core/README.md +++ b/crates/teloxide-core/README.md @@ -12,7 +12,7 @@ - + diff --git a/crates/teloxide-core/src/lib.rs b/crates/teloxide-core/src/lib.rs index 9c5ae94c..bbd6e743 100644 --- a/crates/teloxide-core/src/lib.rs +++ b/crates/teloxide-core/src/lib.rs @@ -1,7 +1,7 @@ //! Core part of the [`teloxide`] library. //! //! This library provides tools for making requests to the [Telegram Bot API] -//! (Currently, version `6.4` is supported) with ease. The library is fully +//! (Currently, version `6.5` is supported) with ease. The library is fully //! asynchronous and built using [`tokio`]. //! //!```toml From 11858ffb743f314981320d76ce5509a05843d21b Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 20:41:43 +0100 Subject: [PATCH 30/41] Remove deprecated chat member kind functions --- crates/teloxide-core/CHANGELOG.md | 4 + crates/teloxide-core/src/types/chat_member.rs | 257 ------------------ 2 files changed, 4 insertions(+), 257 deletions(-) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index f6077121..754b64ae 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -127,6 +127,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove `can_send_media_messages` field from `Restricted` ([#954][pr954]) - Previously deprecated items ([#1013][pr1013]) - `AutoSend` bot adaptor + - `ChatMemberKind::is_kicked` (use `is_banned` instead) + - `ChatMemberKind::is_creator` (use `is_owner` instead) + - `ChatMemberKind::{can_change_info, can_pin_messages, can_invite_users, can_manage_topics, can_send_polls, can_add_web_page_previews, can_send_other_messages, can_send_media_messages, can_send_messages}` (match on `ChatMemberKind` yourself) + - `ChatMemberStatus::is_present` (use `ChatMemberKind::is_present` instead) [pr954]: https://github.com/teloxide/teloxide/pull/954 [pr1013]: https://github.com/teloxide/teloxide/pull/1013 diff --git a/crates/teloxide-core/src/types/chat_member.rs b/crates/teloxide-core/src/types/chat_member.rs index 221bc4a6..fbf6cecb 100644 --- a/crates/teloxide-core/src/types/chat_member.rs +++ b/crates/teloxide-core/src/types/chat_member.rs @@ -268,24 +268,6 @@ impl ChatMemberKind { pub fn is_banned(&self) -> bool { matches!(self, Self::Banned { .. }) } - - /// Returns `true` if the user is [kicked] from the given chat. - /// - /// [kicked]: ChatMemberKind::Banned - #[deprecated = "use `is_banned` instead"] - #[must_use] - pub fn is_kicked(&self) -> bool { - self.is_banned() - } - - /// Returns `true` if the user is the [creator] (owner) of the given chat. - /// - /// [creator]: ChatMemberKind::Owner - #[deprecated = "use `is_owner` instead"] - #[must_use] - pub fn is_creator(&self) -> bool { - self.is_owner() - } } /// Compound methods for checking a user status. @@ -391,29 +373,6 @@ impl ChatMemberKind { } } - /// Returns `true` if the user can change the chat title, photo and other - /// settings. - /// - /// I.e. returns `true` if the user - /// - is the owner of the chat - /// - is an administrator in the given chat and has the - /// [`Administrator::can_change_info`] privilege. - /// - is restricted, but does have [`Restricted::can_change_info`] privilege - /// Returns `false` otherwise. - #[deprecated( - since = "0.9.0", - note = "Match manually and use `can_change_info` field directly. Details: https://github.com/teloxide/teloxide/issues/781" - )] - #[must_use] - pub fn can_change_info(&self) -> bool { - match self { - Self::Owner(_) => true, - Self::Administrator(Administrator { can_change_info, .. }) - | Self::Restricted(Restricted { can_change_info, .. }) => *can_change_info, - Self::Member | Self::Left | Self::Banned(_) => false, - } - } - /// Returns `true` if the user can post in the channel, channels only. /// /// I.e. returns `true` if the user @@ -489,35 +448,6 @@ impl ChatMemberKind { } } - #[deprecated(since = "0.6.0", note = "renamed to `can_manage_video_chats`")] - #[must_use] - pub fn can_manage_voice_chats(&self) -> bool { - self.can_manage_video_chats() - } - - /// Returns `true` if the user can can invite new users to the chat. - /// - /// I.e. returns `true` if the user - /// - is the owner of the chat - /// - is an administrator in the given chat and has the - /// [`Administrator::can_invite_users`] privilege. - /// - is restricted, but does have [`Restricted::can_invite_users`] - /// privilege - /// Returns `false` otherwise. - #[deprecated( - since = "0.9.0", - note = "Match manually and use `can_invite_users` field directly. Details: https://github.com/teloxide/teloxide/issues/781" - )] - #[must_use] - pub fn can_invite_users(&self) -> bool { - match &self { - Self::Owner(_) => true, - Self::Administrator(Administrator { can_invite_users, .. }) - | Self::Restricted(Restricted { can_invite_users, .. }) => *can_invite_users, - Self::Member | Self::Left | Self::Banned(_) => false, - } - } - /// Returns `true` if the user can restrict, ban or unban chat members. /// /// I.e. returns `true` if the user @@ -538,54 +468,6 @@ impl ChatMemberKind { } } - /// Returns `true` if the user can pin messages, supergroups only. - /// - /// I.e. returns `true` if the user - /// - is the owner of the chat (even if the chat is not a supergroup) - /// - is an administrator in the given chat and has the - /// [`Administrator::can_pin_messages`] privilege. - /// - is restricted, but does have [`Restricted::can_pin_messages`] - /// privilege - /// Returns `false` otherwise. - #[deprecated( - since = "0.9.0", - note = "Match manually and use `can_pin_messages` field directly. Details: https://github.com/teloxide/teloxide/issues/781" - )] - #[must_use] - pub fn can_pin_messages(&self) -> bool { - match self { - Self::Owner(_) => true, - Self::Administrator(Administrator { can_pin_messages, .. }) - | Self::Restricted(Restricted { can_pin_messages, .. }) => *can_pin_messages, - Self::Member | Self::Left | Self::Banned(_) => false, - } - } - - /// Returns `true` if the user is allowed to manage topics. - /// - /// I.e. returns `true` if the user - /// - is the owner of the chat (even if the chat is not a supergroup) - /// - is an administrator in the given chat and has the - /// [`Administrator::can_manage_topics`] privilege. - /// - is restricted, but does have [`Restricted::can_manage_topics`] - /// privilege - /// Returns `false` otherwise. - #[deprecated( - since = "0.9.0", - note = "Match manually and use `can_manage_topics` field directly. Details: https://github.com/teloxide/teloxide/issues/781" - )] - #[must_use] - pub fn can_manage_topics(&self) -> bool { - match self { - ChatMemberKind::Owner(_) => true, - ChatMemberKind::Administrator(Administrator { can_manage_topics, .. }) - | ChatMemberKind::Restricted(Restricted { can_manage_topics, .. }) => { - *can_manage_topics - } - ChatMemberKind::Member | ChatMemberKind::Left | ChatMemberKind::Banned(_) => false, - } - } - /// Returns `true` if the user can add new administrators with a subset of /// his own privileges or demote administrators that he has promoted, /// directly or indirectly (promoted by administrators that were appointed @@ -608,131 +490,6 @@ impl ChatMemberKind { } } -/// Methods for checking member rights. -impl ChatMemberKind { - /// Returns `true` if the user can send text messages, contacts, locations - /// and venues. - /// - /// I.e. returns **`false`** if the user - /// - has left or has been banned in the chat - /// - is restricted and doesn't have the [`can_send_messages`] right - /// Returns `true` otherwise. - /// - /// [`can_send_messages`]: Restricted::can_send_messages - #[deprecated( - since = "0.9.0", - note = "Match manually and use `can_send_messages` field directly. Details: https://github.com/teloxide/teloxide/issues/781" - )] - #[must_use] - pub fn can_send_messages(&self) -> bool { - match &self { - Self::Restricted(Restricted { can_send_messages, .. }) => *can_send_messages, - Self::Owner(_) | Self::Administrator(_) | Self::Member => true, - Self::Left | Self::Banned(_) => false, - } - } - - /// Returns `true` if the user is allowed to send audios, documents, photos, - /// videos, video notes and voice notes. - /// - /// I.e. returns **`false`** if the user - /// - has left or has been banned in the chat - /// - is restricted and doesn't have all send media right - /// Returns `true` otherwise. - #[must_use] - pub fn can_send_media_messages(&self) -> bool { - match &self { - Self::Restricted(Restricted { - can_send_audios, - can_send_documents, - can_send_photos, - can_send_videos, - can_send_video_notes, - can_send_voice_notes, - .. - }) => { - *can_send_audios - && *can_send_documents - && *can_send_photos - && *can_send_videos - && *can_send_video_notes - && *can_send_voice_notes - } - Self::Owner(_) | Self::Administrator(_) | Self::Member => true, - Self::Left | Self::Banned(_) => false, - } - } - - /// Returns `true` if the user is allowed to send animations, games, - /// stickers and use inline bots. - /// - /// I.e. returns **`false`** if the user - /// - has left or has been banned from the chat - /// - is restricted and has no [`can_send_other_messages`] right - /// Returns `true` otherwise. - /// - /// [`can_send_other_messages`]: Restricted::can_send_other_messages - #[deprecated( - since = "0.9.0", - note = "Match manually and use `can_send_other_messages` field directly. Details: https://github.com/teloxide/teloxide/issues/781" - )] - #[must_use] - pub fn can_send_other_messages(&self) -> bool { - match &self { - Self::Restricted(Restricted { can_send_other_messages, .. }) => { - *can_send_other_messages - } - Self::Owner(_) | Self::Administrator(_) | Self::Member => true, - Self::Left | Self::Banned(_) => false, - } - } - - /// Returns `true` if the user is allowed to add web page previews to their - /// messages. - /// - /// I.e. returns **`false`** if the user - /// - has left or has been banned from the chat - /// - is restricted and has no [`can_add_web_page_previews`] right - /// Returns `true` otherwise. - /// - /// [`can_add_web_page_previews`]: Restricted::can_add_web_page_previews - #[deprecated( - since = "0.9.0", - note = "Match manually and use `can_add_web_page_previews` field directly. Details: https://github.com/teloxide/teloxide/issues/781" - )] - #[must_use] - pub fn can_add_web_page_previews(&self) -> bool { - match &self { - Self::Restricted(Restricted { can_add_web_page_previews, .. }) => { - *can_add_web_page_previews - } - Self::Owner(_) | Self::Administrator(_) | Self::Member => true, - Self::Left | Self::Banned(_) => false, - } - } - - /// Returns `true` if the user is allowed to send polls. - /// - /// I.e. returns **`false`** if the user - /// - has left or has been banned from the chat - /// - is restricted and doesn't have the [`can_send_polls`] right - /// Returns `true` otherwise. - /// - /// [`can_send_polls`]: Restricted::can_send_polls - #[deprecated( - since = "0.9.0", - note = "Match manually and use `can_send_polls` field directly. Details: https://github.com/teloxide/teloxide/issues/781" - )] - #[must_use] - pub fn can_send_polls(&self) -> bool { - match &self { - Self::Restricted(Restricted { can_send_polls, .. }) => *can_send_polls, - Self::Owner(_) | Self::Administrator(_) | Self::Member => true, - Self::Left | Self::Banned(_) => false, - } - } -} - #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum ChatMemberStatus { @@ -824,20 +581,6 @@ impl ChatMemberStatus { pub fn is_privileged(&self) -> bool { self.is_administrator() || self.is_owner() } - - /// Returns `true` if the user is currently present in the chat. i.e. if the - /// user **hasn't** [left] or been [banned]. - /// - /// [left]: ChatMemberKind::Left - /// [banned]: ChatMemberKind::Banned - #[must_use] - #[deprecated( - since = "0.9.0", - note = "Use `ChatMemberKind::is_present` method instead. Details: https://github.com/teloxide/teloxide/issues/781" - )] - pub fn is_present(&self) -> bool { - !(self.is_left() || self.is_banned()) - } } #[cfg(test)] From b79c1f978d1d7e6b0976305dc9ef7b3be67069eb Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 20:43:15 +0100 Subject: [PATCH 31/41] Remove `InlineKeyboardButton::{text,kind}` --- crates/teloxide-core/CHANGELOG.md | 1 + .../src/types/inline_keyboard_button.rs | 24 ------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index 754b64ae..c91c4d2b 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -131,6 +131,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ChatMemberKind::is_creator` (use `is_owner` instead) - `ChatMemberKind::{can_change_info, can_pin_messages, can_invite_users, can_manage_topics, can_send_polls, can_add_web_page_previews, can_send_other_messages, can_send_media_messages, can_send_messages}` (match on `ChatMemberKind` yourself) - `ChatMemberStatus::is_present` (use `ChatMemberKind::is_present` instead) + - `InlineKeyboardButton::{text, kind}` [pr954]: https://github.com/teloxide/teloxide/pull/954 [pr1013]: https://github.com/teloxide/teloxide/pull/1013 diff --git a/crates/teloxide-core/src/types/inline_keyboard_button.rs b/crates/teloxide-core/src/types/inline_keyboard_button.rs index 8d269fed..aa79288d 100644 --- a/crates/teloxide-core/src/types/inline_keyboard_button.rs +++ b/crates/teloxide-core/src/types/inline_keyboard_button.rs @@ -192,27 +192,3 @@ impl InlineKeyboardButton { Self::new(text, InlineKeyboardButtonKind::Pay(True)) } } - -impl InlineKeyboardButton { - #[deprecated( - since = "0.7.0", - note = "set correct text in the constructor or access the field directly" - )] - pub fn text(mut self, val: S) -> Self - where - S: Into, - { - self.text = val.into(); - self - } - - #[deprecated( - since = "0.7.0", - note = "set correct kind in the constructor or access the field directly" - )] - #[must_use] - pub fn kind(mut self, val: InlineKeyboardButtonKind) -> Self { - self.kind = val; - self - } -} From 2e8b4cfa19eaff1444b56662dc31e5809bf7ac6f Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 20:44:32 +0100 Subject: [PATCH 32/41] Remove moved modules --- crates/teloxide-core/CHANGELOG.md | 1 + crates/teloxide/src/dispatching.rs | 17 ----------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index c91c4d2b..ff9e154e 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -132,6 +132,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ChatMemberKind::{can_change_info, can_pin_messages, can_invite_users, can_manage_topics, can_send_polls, can_add_web_page_previews, can_send_other_messages, can_send_media_messages, can_send_messages}` (match on `ChatMemberKind` yourself) - `ChatMemberStatus::is_present` (use `ChatMemberKind::is_present` instead) - `InlineKeyboardButton::{text, kind}` + `teloxide::dispatching::{update_listeners, repls}` (use `reloxide::{update_listeners, repls}` instead) [pr954]: https://github.com/teloxide/teloxide/pull/954 [pr1013]: https://github.com/teloxide/teloxide/pull/1013 diff --git a/crates/teloxide/src/dispatching.rs b/crates/teloxide/src/dispatching.rs index a4d9b6ce..5c048e23 100644 --- a/crates/teloxide/src/dispatching.rs +++ b/crates/teloxide/src/dispatching.rs @@ -217,23 +217,6 @@ pub mod dialogue; -/// This module was moved to [`teloxide::update_listeners`]. -/// -/// [`teloxide::update_listeners`]: crate::update_listeners -#[deprecated = "This module was moved. Use `teloxide::update_listeners` instead."] -pub mod update_listeners { - pub use crate::update_listeners::*; -} - -/// This module was moved to [`teloxide::repls`]. -/// -/// [`teloxide::repls`]: crate::repls -#[deprecated = "This module was moved. Use `teloxide::repls` instead."] -#[cfg(feature = "ctrlc_handler")] -pub mod repls { - pub use crate::repls::*; -} - mod dispatcher; mod distribution; mod filter_ext; From d7b954b1c60de9cf4d068448a71a43d7e06eab22 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 20:46:28 +0100 Subject: [PATCH 33/41] Remove `Dispatcher::setup_ctrlc_handler` --- crates/teloxide-core/CHANGELOG.md | 1 + crates/teloxide/src/dispatching/dispatcher.rs | 9 --------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index ff9e154e..f739bfdd 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -133,6 +133,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ChatMemberStatus::is_present` (use `ChatMemberKind::is_present` instead) - `InlineKeyboardButton::{text, kind}` `teloxide::dispatching::{update_listeners, repls}` (use `reloxide::{update_listeners, repls}` instead) + - `Dispatcher::setup_ctrlc_handler` (use `enable_ctrlc_handler` on the builder instead) [pr954]: https://github.com/teloxide/teloxide/pull/954 [pr1013]: https://github.com/teloxide/teloxide/pull/1013 diff --git a/crates/teloxide/src/dispatching/dispatcher.rs b/crates/teloxide/src/dispatching/dispatcher.rs index 91db674a..7f915ad8 100644 --- a/crates/teloxide/src/dispatching/dispatcher.rs +++ b/crates/teloxide/src/dispatching/dispatcher.rs @@ -482,15 +482,6 @@ where } } - /// Setups the `^C` handler in order to call [`ShutdownToken::shutdown`] - /// when pressed. - #[cfg(feature = "ctrlc_handler")] - #[deprecated(since = "0.10.0", note = "use `enable_ctrlc_handler` on builder instead")] - pub fn setup_ctrlc_handler(&mut self) -> &mut Self { - self.setup_ctrlc_handler_inner(); - self - } - /// Returns a shutdown token, which can later be used to /// [`ShutdownToken::shutdown`]. pub fn shutdown_token(&self) -> ShutdownToken { From f4127325dadd536ac9d0eaa4367e54ca5c52def6 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 20:48:01 +0100 Subject: [PATCH 34/41] Remove deprecated repl command stuff --- crates/teloxide-core/CHANGELOG.md | 1 + crates/teloxide/src/lib.rs | 4 - crates/teloxide/src/repls.rs | 2 - crates/teloxide/src/repls/commands_repl.rs | 153 +-------------------- crates/teloxide/src/utils/command.rs | 10 -- 5 files changed, 2 insertions(+), 168 deletions(-) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index f739bfdd..32c517a1 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -134,6 +134,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `InlineKeyboardButton::{text, kind}` `teloxide::dispatching::{update_listeners, repls}` (use `reloxide::{update_listeners, repls}` instead) - `Dispatcher::setup_ctrlc_handler` (use `enable_ctrlc_handler` on the builder instead) + - `BotCommands::ty` and `repls::{commands_repl, commands_repl_with_listener}` (use `CommandsRepl::{repl, repl_with_listener}` instead) [pr954]: https://github.com/teloxide/teloxide/pull/954 [pr1013]: https://github.com/teloxide/teloxide/pull/1013 diff --git a/crates/teloxide/src/lib.rs b/crates/teloxide/src/lib.rs index 4535d843..9a2ebeb3 100644 --- a/crates/teloxide/src/lib.rs +++ b/crates/teloxide/src/lib.rs @@ -131,10 +131,6 @@ #[cfg(feature = "ctrlc_handler")] pub use repls::{repl, repl_with_listener}; -#[cfg(feature = "ctrlc_handler")] -#[allow(deprecated)] -pub use repls::{commands_repl, commands_repl_with_listener}; - pub mod backoff; pub mod dispatching; pub mod error_handlers; diff --git a/crates/teloxide/src/repls.rs b/crates/teloxide/src/repls.rs index aea4806e..6ba3d640 100644 --- a/crates/teloxide/src/repls.rs +++ b/crates/teloxide/src/repls.rs @@ -12,6 +12,4 @@ mod commands_repl; mod repl; pub use commands_repl::CommandReplExt; -#[allow(deprecated)] -pub use commands_repl::{commands_repl, commands_repl_with_listener}; pub use repl::{repl, repl_with_listener}; diff --git a/crates/teloxide/src/repls/commands_repl.rs b/crates/teloxide/src/repls/commands_repl.rs index c846089e..699e57da 100644 --- a/crates/teloxide/src/repls/commands_repl.rs +++ b/crates/teloxide/src/repls/commands_repl.rs @@ -8,7 +8,7 @@ use crate::{ }; use dptree::di::{DependencyMap, Injectable}; use futures::future::BoxFuture; -use std::{fmt::Debug, marker::PhantomData}; +use std::fmt::Debug; /// A [REPL] for commands. /// @@ -147,154 +147,3 @@ where }) } } - -/// A [REPL] for commands. -// -/// -// -#[doc = include_str!("preamble.md")] -/// -/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop -/// -/// ## Signature -/// -/// Don't be scared by many trait bounds in the signature, in essence they -/// require: -/// -/// 1. `bot` is a bot, client for the Telegram bot API. It is represented via -/// the [`Requester`] trait. -/// 2. `handler` is an `async` function that takes arguments from -/// [`DependencyMap`] (see below) and returns [`ResponseResult`]. -/// 3. `cmd` is a type hint for your command enumeration `MyCommand`: just write -/// `MyCommand::ty()`. Note that `MyCommand` must implement the -/// [`BotCommands`] trait, typically via -/// `#[derive(BotCommands)]`. -/// -/// All the other requirements are about thread safety and data validity and can -/// be ignored for most of the time. -/// -/// ## Handler arguments -/// -/// `teloxide` provides the following types to the `handler`: -/// - [`Message`] -/// - `R` (type of the `bot`) -/// - `Cmd` (type of the parsed command) -/// - [`Me`] -/// -/// Each of these types can be accepted as a handler parameter. Note that they -/// aren't all required at the same time: e.g., you can take only the bot and -/// the command without [`Me`] and [`Message`]. -/// -/// [`Me`]: crate::types::Me -/// [`Message`]: crate::types::Message -/// -/// ## Stopping -// -#[doc = include_str!("stopping.md")] -/// -/// ## Caution -// -#[doc = include_str!("caution.md")] -/// -#[cfg(feature = "ctrlc_handler")] -#[deprecated(note = "Use `CommandsRepl::repl` instead")] -pub async fn commands_repl<'a, R, Cmd, H, Args>(bot: R, handler: H, cmd: PhantomData) -where - R: Requester + Clone + Send + Sync + 'static, - ::GetUpdates: Send, - H: Injectable, Args> + Send + Sync + 'static, - Cmd: BotCommands + Send + Sync + 'static, -{ - let cloned_bot = bot.clone(); - - #[allow(deprecated)] - commands_repl_with_listener( - bot, - handler, - update_listeners::polling_default(cloned_bot).await, - cmd, - ) - .await; -} - -/// A [REPL] for commands, with a custom [`UpdateListener`]. -// -/// -// -#[doc = include_str!("preamble.md")] -/// -/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop -/// -/// ## Signature -/// -/// Don't be scared by many trait bounds in the signature, in essence they -/// require: -/// -/// 1. `bot` is a bot, client for the Telegram bot API. It is represented via -/// the [`Requester`] trait. -/// 2. `handler` is an `async` function that takes arguments from -/// [`DependencyMap`] (see below) and returns [`ResponseResult`]. -/// 3. `listener` is something that takes updates from a Telegram server and -/// implements [`UpdateListener`]. -/// 4. `cmd` is a type hint for your command enumeration `MyCommand`: just write -/// `MyCommand::ty()`. Note that `MyCommand` must implement the -/// [`BotCommands`] trait, typically via `#[derive(BotCommands)]`. -/// -/// All the other requirements are about thread safety and data validity and can -/// be ignored for most of the time. -/// -/// ## Handler arguments -/// -/// `teloxide` provides the following types to the `handler`: -/// - [`Message`] -/// - `R` (type of the `bot`) -/// - `Cmd` (type of the parsed command) -/// - [`Me`] -/// -/// Each of these types can be accepted as a handler parameter. Note that they -/// aren't all required at the same time: e.g., you can take only the bot and -/// the command without [`Me`] and [`Message`]. -/// -/// [`Me`]: crate::types::Me -/// [`Message`]: crate::types::Message -/// -/// ## Stopping -// -#[doc = include_str!("stopping.md")] -/// -/// ## Caution -// -#[doc = include_str!("caution.md")] -/// -#[cfg(feature = "ctrlc_handler")] -#[deprecated(note = "Use `CommandsRepl::repl_with_listener` instead")] -pub async fn commands_repl_with_listener<'a, R, Cmd, H, L, Args>( - bot: R, - handler: H, - listener: L, - cmd: PhantomData, -) where - Cmd: BotCommands + Send + Sync + 'static, - H: Injectable, Args> + Send + Sync + 'static, - L: UpdateListener + Send + 'a, - L::Err: Debug + Send + 'a, - R: Requester + Clone + Send + Sync + 'static, -{ - use crate::dispatching::Dispatcher; - - let _ = cmd; - - // Other update types are of no interest to use since this REPL is only for - // commands. See . - let ignore_update = |_upd| Box::pin(async {}); - - Dispatcher::builder(bot, Update::filter_message().filter_command::().endpoint(handler)) - .default_handler(ignore_update) - .enable_ctrlc_handler() - .build() - .dispatch_with_listener( - listener, - LoggingErrorHandler::with_custom_text("An error from the update listener"), - ) - .await; -} diff --git a/crates/teloxide/src/utils/command.rs b/crates/teloxide/src/utils/command.rs index 32aba462..ab85f893 100644 --- a/crates/teloxide/src/utils/command.rs +++ b/crates/teloxide/src/utils/command.rs @@ -55,7 +55,6 @@ use std::{ fmt::{Display, Formatter, Write}, }; -use std::marker::PhantomData; use teloxide_core::types::{BotCommand, Me}; #[cfg(feature = "macros")] pub use teloxide_macros::BotCommands; @@ -265,15 +264,6 @@ pub trait BotCommands: Sized { /// [`BotCommand`]: crate::types::BotCommand /// [`set_my_commands`]: crate::requests::Requester::set_my_commands fn bot_commands() -> Vec; - - /// Returns `PhantomData` that is used as a param of [`commands_repl`] - /// - /// [`commands_repl`]: (crate::repls::commands_repl) - #[must_use] - #[deprecated(note = "Use `CommandReplExt` instead")] - fn ty() -> PhantomData { - PhantomData - } } pub type PrefixedBotCommand = String; From 6e176113cd86d480f6649774bcdc7fc163fa8344 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 22:15:08 +0100 Subject: [PATCH 35/41] Remove `Message::chat_id`, `Update::user` --- crates/teloxide-core/CHANGELOG.md | 2 ++ crates/teloxide-core/src/types/message.rs | 6 ------ crates/teloxide-core/src/types/update.rs | 5 ----- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index 32c517a1..cfb16151 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -135,6 +135,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `teloxide::dispatching::{update_listeners, repls}` (use `reloxide::{update_listeners, repls}` instead) - `Dispatcher::setup_ctrlc_handler` (use `enable_ctrlc_handler` on the builder instead) - `BotCommands::ty` and `repls::{commands_repl, commands_repl_with_listener}` (use `CommandsRepl::{repl, repl_with_listener}` instead) + - `Message::chat_id` (use `.chat.id`) + - `Update::user` (use `Update::from`) [pr954]: https://github.com/teloxide/teloxide/pull/954 [pr1013]: https://github.com/teloxide/teloxide/pull/1013 diff --git a/crates/teloxide-core/src/types/message.rs b/crates/teloxide-core/src/types/message.rs index d988fad5..3f46a556 100644 --- a/crates/teloxide-core/src/types/message.rs +++ b/crates/teloxide-core/src/types/message.rs @@ -716,12 +716,6 @@ mod getters { } } - #[deprecated(since = "0.4.2", note = "use `.chat.id` field instead")] - #[must_use] - pub fn chat_id(&self) -> ChatId { - self.chat.id - } - #[must_use] pub fn forward(&self) -> Option<&Forward> { self.common().and_then(|m| m.forward.as_ref()) diff --git a/crates/teloxide-core/src/types/update.rs b/crates/teloxide-core/src/types/update.rs index 44a2eeeb..ec41ad94 100644 --- a/crates/teloxide-core/src/types/update.rs +++ b/crates/teloxide-core/src/types/update.rs @@ -231,11 +231,6 @@ impl Update { Some(chat) } - - #[deprecated(note = "renamed to `from`", since = "0.10.0")] - pub fn user(&self) -> Option<&User> { - self.from() - } } impl UpdateId { From 74b03664cfee39066b80667d5045b42d1110452c Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 22:15:36 +0100 Subject: [PATCH 36/41] Fill-in deprecation version, remove useless `allow` --- crates/teloxide-core/src/types/parse_mode.rs | 7 +++++-- crates/teloxide/src/prelude.rs | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/teloxide-core/src/types/parse_mode.rs b/crates/teloxide-core/src/types/parse_mode.rs index edd652fe..d5a07c31 100644 --- a/crates/teloxide-core/src/types/parse_mode.rs +++ b/crates/teloxide-core/src/types/parse_mode.rs @@ -145,8 +145,11 @@ pub enum ParseMode { MarkdownV2, #[serde(rename = "HTML")] Html, - #[deprecated = "This is a legacy mode, retained for backward compatibility. Use `MarkdownV2` \ - instead."] + #[deprecated( + since = "0.1.0", + note = "This is a legacy mode, retained for backward compatibility. Use `MarkdownV2` \ + instead." + )] Markdown, } diff --git a/crates/teloxide/src/prelude.rs b/crates/teloxide/src/prelude.rs index 78db754b..b9c4aba4 100644 --- a/crates/teloxide/src/prelude.rs +++ b/crates/teloxide/src/prelude.rs @@ -2,7 +2,6 @@ pub use crate::error_handlers::{LoggingErrorHandler, OnError}; -#[allow(deprecated)] pub use crate::respond; pub use crate::dispatching::{ From d42d2b78122944bd5d2c7be2f869b969934a5a2b Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 13 Feb 2024 22:17:15 +0100 Subject: [PATCH 37/41] Remove `update_listeners::polling` --- crates/teloxide-core/CHANGELOG.md | 1 + crates/teloxide/src/update_listeners.rs | 11 ++++----- .../teloxide/src/update_listeners/polling.rs | 23 ++----------------- .../src/update_listeners/stateful_listener.rs | 4 ++-- 4 files changed, 10 insertions(+), 29 deletions(-) diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index cfb16151..9af978f6 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -137,6 +137,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `BotCommands::ty` and `repls::{commands_repl, commands_repl_with_listener}` (use `CommandsRepl::{repl, repl_with_listener}` instead) - `Message::chat_id` (use `.chat.id`) - `Update::user` (use `Update::from`) + - `update_listeners::polling` (use `Polling::builder` instead) [pr954]: https://github.com/teloxide/teloxide/pull/954 [pr1013]: https://github.com/teloxide/teloxide/pull/1013 diff --git a/crates/teloxide/src/update_listeners.rs b/crates/teloxide/src/update_listeners.rs index 6e03ef01..34f8a0de 100644 --- a/crates/teloxide/src/update_listeners.rs +++ b/crates/teloxide/src/update_listeners.rs @@ -5,7 +5,7 @@ //! //! - [`polling_default`] function, which returns a default long polling //! listener. -//! - [`polling`] function, which returns a long polling listener with your +//! - [`Polling`] function, which returns a long polling listener with your //! configuration. //! - Various functions in the [`webhooks`] module that return webhook listeners //! @@ -13,12 +13,11 @@ //! [`Dispatcher`]. //! //! Telegram supports two ways of [getting updates]: [long polling] and -//! [webhooks]. For the former see [`polling`] and [`polling_default`], for the +//! [webhooks]. For the former see [`Polling`] and [`polling_default`], for the //! latter see the [`webhooks`] module. //! //! [`UpdateListener`]: UpdateListener //! [`polling_default`]: polling_default -//! [`polling`]: polling() //! [`Dispatcher`]: crate::dispatching::Dispatcher //! [`Box::get_updates`]: crate::requests::Requester::get_updates //! [getting updates]: https://core.telegram.org/bots/api#getting-updates @@ -26,7 +25,7 @@ //! [webhooks]: https://en.wikipedia.org/wiki/Webhook /// Implementations of webhook update listeners - an alternative (to -/// [`fn@polling`]) way of receiving updates from telegram. +/// [`Polling`]) way of receiving updates from telegram. #[cfg(feature = "webhooks")] pub mod webhooks; @@ -42,7 +41,7 @@ mod stateful_listener; #[allow(deprecated)] pub use self::{ - polling::{polling, polling_default, Polling, PollingBuilder, PollingStream}, + polling::{polling_default, Polling, PollingBuilder, PollingStream}, stateful_listener::StatefulListener, }; @@ -80,7 +79,7 @@ pub trait UpdateListener: /// Hint which updates should the listener listen for. /// - /// For example [`polling()`] should send the hint as + /// For example [`Polling`] should send the hint as /// [`GetUpdates::allowed_updates`] /// /// Note however that this is a _hint_ and as such, it can be ignored. The diff --git a/crates/teloxide/src/update_listeners/polling.rs b/crates/teloxide/src/update_listeners/polling.rs index e39ba977..be035f90 100644 --- a/crates/teloxide/src/update_listeners/polling.rs +++ b/crates/teloxide/src/update_listeners/polling.rs @@ -147,25 +147,6 @@ where assert_update_listener(polling) } -/// Returns a long polling update listener with some additional options. -#[deprecated(since = "0.10.0", note = "use `Polling::builder()` instead")] -pub fn polling( - bot: R, - timeout: Option, - limit: Option, - allowed_updates: Option>, -) -> Polling -where - R: Requester + Send + 'static, - ::GetUpdates: Send, -{ - let mut builder = Polling::builder(bot); - builder.timeout = timeout; - builder.limit = limit; - builder.allowed_updates = allowed_updates; - assert_update_listener(builder.build()) -} - async fn delete_webhook_if_setup(requester: &R) where R: Requester, @@ -513,8 +494,8 @@ impl Stream for PollingStream<'_, B> { #[test] fn polling_is_send() { let bot = crate::Bot::new("TOKEN"); - #[allow(deprecated)] - let mut polling = polling(bot, None, None, None); + + let mut polling = Polling::builder(bot).build(); assert_send(&polling); assert_send(&polling.as_stream()); diff --git a/crates/teloxide/src/update_listeners/stateful_listener.rs b/crates/teloxide/src/update_listeners/stateful_listener.rs index 87ae492a..6c452f96 100644 --- a/crates/teloxide/src/update_listeners/stateful_listener.rs +++ b/crates/teloxide/src/update_listeners/stateful_listener.rs @@ -11,9 +11,9 @@ use crate::{ /// This type allows to turn a stream of updates (+ some additional functions) /// into an [`UpdateListener`]. /// -/// For an example of usage, see [`polling`]. +/// For an example of usage, see [`Polling`]. /// -/// [`polling`]: crate::update_listeners::polling() +/// [`Polling`]: crate::update_listeners::Polling #[non_exhaustive] pub struct StatefulListener { /// The state of the listener. From c934e678f6a9cbf0e367505b3fd1eb53ec358376 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 14 Feb 2024 20:59:02 +0100 Subject: [PATCH 38/41] Expand on pull request & minor fixes to CONTRIBUTING.md --- CONTRIBUTING.md | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c205850e..d43544bf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,8 +1,8 @@ # Contributing -Before contributing, please read [our code style](./CODE_STYLE.md) and [the license](./LICENSE). +Before contributing, please read [the license](./LICENSE). -> **Note** +> [!NOTE] > > These contributing instructions might not be fully up-to-date or complete. > However, they should be a good starting point. @@ -20,6 +20,10 @@ If you want to ask a question, you can either ## Code +### Style guide + +Before writing code, please read [our code style](./CODE_STYLE.md). + ### Git To change the source code, you need a local copy of it. @@ -30,7 +34,28 @@ This way it will be easier to manage when you want to do other things. When your changes are ready, you can open a github pull request. +### Pull Requests + +If your pull request fixes/resolves an existing [github issue] please specify so in the PR description. +For example: + +> Fixes #991 + +You can learn more about [Using keywords in issues and pull requests] in github documentation. + +If your pull request suggests new functionality or new changes, +please explain your point of view and all the necessary details. +(pros, cons, why you chose design you chose, your use cases, etc) + +In general try to make PR title/description clear, as they are the primary ways of communicating your intent to the reviewer + +[github issue]: https://github.com/teloxide/teloxide/issues +[Using keywords in issues and pull requests]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests + +### Merge conflicts + If your branch has conflicts with master please resolve them by doing something like this: + ```shell # Temporary switch to master branch git switch master From 4ab24a0a0c6b2d7bd3e67e456e7a8187b92803e0 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 15 Feb 2024 21:41:26 +0100 Subject: [PATCH 39/41] Review changes to CONTRIBUTING.md --- CONTRIBUTING.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d43544bf..ecb368b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,5 @@ # Contributing -Before contributing, please read [the license](./LICENSE). - > [!NOTE] > > These contributing instructions might not be fully up-to-date or complete. @@ -43,11 +41,10 @@ For example: You can learn more about [Using keywords in issues and pull requests] in github documentation. -If your pull request suggests new functionality or new changes, -please explain your point of view and all the necessary details. +If your pull request suggests new functionality or new changes, please explain your point of view and all the necessary details. (pros, cons, why you chose design you chose, your use cases, etc) -In general try to make PR title/description clear, as they are the primary ways of communicating your intent to the reviewer +In general try to make PR title/description clear, as they are the primary ways of communicating your intent to the reviewer. [github issue]: https://github.com/teloxide/teloxide/issues [Using keywords in issues and pull requests]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests From 8669c87f6fd03b8885daeee136998aa215b0e2d6 Mon Sep 17 00:00:00 2001 From: Tima Kinsart Date: Fri, 16 Feb 2024 05:01:01 +0800 Subject: [PATCH 40/41] Improve the style of `CONTRIBUTING.md` --- CONTRIBUTING.md | 61 ++++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ecb368b2..06b9d35d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,16 +5,15 @@ > These contributing instructions might not be fully up-to-date or complete. > However, they should be a good starting point. > -> If you find inaccuracies / missing things, please expand this or contact us. +> If you find inaccuracies/missing things, please expand this or contact us. ## Reporting bugs, questions, feature requests -To report a bug or suggest new functionality go to [issues](https://github.com/teloxide/teloxide/issues). -Try to make MRE (**M**inimal **R**eproducible **E**xample) and specify your teloxide version to let others help you. +To report a bug or suggest new functionality, go to the [issues](https://github.com/teloxide/teloxide/issues). Try to make MRE (**M**inimal **R**eproducible **E**xample) and specify your `teloxide` version to let others help you. If you want to ask a question, you can either -- Open a new [github discussion](https://github.com/teloxide/teloxide/discussions), or -- Write to our telegram group ([eng](https://t.me/teloxide), [ru](https://t.me/teloxide_ru)) +- open a new [GitHub discussion](https://github.com/teloxide/teloxide/discussions), or +- write to our Telegram group ([ENG](https://t.me/teloxide), [RU](https://t.me/teloxide_ru)). ## Code @@ -24,34 +23,30 @@ Before writing code, please read [our code style](./CODE_STYLE.md). ### Git -To change the source code, you need a local copy of it. -Fork the `master` branch of this repository via github and clone your fork locally. +To change the source code, you need a local copy of it. Fork the `master` branch of this repository via GitHub and clone your fork locally. -When working on a new thing, create a new branch with `git switch -c my-branch-name` (or other commands that work with branches). -This way it will be easier to manage when you want to do other things. +When working on a new thing, create a new branch with `git switch -c my-branch-name` (or other commands that work with branches). This way, it will be easier to manage when you want to do other things. -When your changes are ready, you can open a github pull request. +When your changes are ready, you can open a new GitHub pull request. ### Pull Requests -If your pull request fixes/resolves an existing [github issue] please specify so in the PR description. -For example: +If your pull request fixes/resolves an existing [GitHub issue], please specify so in the PR description. For example: -> Fixes #991 +> Fixes #991. -You can learn more about [Using keywords in issues and pull requests] in github documentation. +You can learn more about [using keywords in issues and pull requests] in the GitHub documentation. -If your pull request suggests new functionality or new changes, please explain your point of view and all the necessary details. -(pros, cons, why you chose design you chose, your use cases, etc) +If your pull request suggests new functionality or new changes, please explain your point of view and all the necessary details (pros, cons, why you chose the design you chose, your use cases, etc.) -In general try to make PR title/description clear, as they are the primary ways of communicating your intent to the reviewer. +In general, try to make PR title/description as clear as possible, as they are the primary ways of communicating your intent to the reviewer. -[github issue]: https://github.com/teloxide/teloxide/issues -[Using keywords in issues and pull requests]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests +[GitHub issue]: https://github.com/teloxide/teloxide/issues +[using keywords in issues and pull requests]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests ### Merge conflicts -If your branch has conflicts with master please resolve them by doing something like this: +If your branch has conflicts with master, please resolve them by doing something like this: ```shell # Temporary switch to master branch @@ -78,8 +73,7 @@ git push --force-with-lease ### Testing -When you open a PR it will be tested in CI. -We recommend you test the PR before opening it: +When you open a PR, it will be tested in the CI. We recommend you test the PR before opening it: ```shell # Formatting (use `-- --check` if you only want to check) @@ -99,33 +93,28 @@ cargo test --features "full nightly" cargo docs ``` -## Teloxide bot +## @teloxidebot -Teloxide uses @teloxidebot as a helper to manage PRs and issues. -It's based on triagebot developed by rustc developers which docs can be found [here](https://forge.rust-lang.org/triagebot/index.html). +`teloxide` uses @teloxidebot as a helper to manage PRs and issues. It is based on triagebot used by rustc developers, which docs can be found [here](https://forge.rust-lang.org/triagebot/index.html). -We'll describe here a few most used @teloxidebot's features, but we still recommend you read the docs. +We will describe here a few most used @teloxidebot's features, but we still recommend you to read the docs. ### PR status tracking -Teloxide uses `S-*` labels (mainly https://github.com/teloxide/teloxide/labels/S-waiting-on-author and https://github.com/teloxide/teloxide/labels/S-waiting-on-review) to track the status of pull requests. +`teloxide` uses `S-*` labels (mainly https://github.com/teloxide/teloxide/labels/S-waiting-on-author and https://github.com/teloxide/teloxide/labels/S-waiting-on-review) to track the status of pull requests. -You can change the status with `@teloxidebot review` and `@teloxidebot ready` (set the status to https://github.com/teloxide/teloxide/labels/S-waiting-on-review) or `@teloxidebot author` (sets the status to https://github.com/teloxide/teloxide/labels/S-waiting-on-author). +You can change the status with `@teloxidebot review` and `@teloxidebot ready` (sets the status to https://github.com/teloxide/teloxide/labels/S-waiting-on-review) or `@teloxidebot author` (sets the status to https://github.com/teloxide/teloxide/labels/S-waiting-on-author). -Requesting a review from PR's assignee via github ui will also change the status of the PR to waiting on review. -Similarly, submitting a review that requests changes will change the status of the PR to waiting on author. +Requesting a review from PR's assignee via GitHub UI will also change the status of the PR to waiting on review. Similarly, submitting a review that requests changes will change the status of the PR to waiting on author. -There is also https://github.com/teloxide/teloxide/labels/S-blocked which can be set with `@teloxidebot blocked`. +There is also https://github.com/teloxide/teloxide/labels/S-blocked, which can be set with `@teloxidebot blocked`. Please note that your PR won't be reviewed unless it's waiting for review :) ### Labels -Normally github only allows privileged users to change labels. -@teloxidebot allows anyone to add or remove certain [labels](https://github.com/teloxide/teloxide/labels/) with `@teloxidebot label +additional_label -removed_label`. -See more in the [documentation](https://forge.rust-lang.org/triagebot/index.html). +Normally, GitHub only allows privileged users to change labels. @teloxidebot allows anyone to add or remove certain [labels](https://github.com/teloxide/teloxide/labels/) with `@teloxidebot label +additional_label -removed_label`. See more in the [documentation](https://forge.rust-lang.org/triagebot/index.html). ### PR assignment -When a PR is created @teloxidebot will automatically assign one of the maintainers to it. -If you want to override this assignment, use `r? @ReviewerUsername`. +When a PR is created, @teloxidebot will automatically assign one of the maintainers to it. If you want to override this assignment, use `r? @ReviewerUsername`. From 4c0589ab3914854d396ce1d737709bf79fb3bfde Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Sun, 18 Feb 2024 00:20:39 +0530 Subject: [PATCH 41/41] crates: remove unused dependencies --- crates/teloxide-core/Cargo.toml | 1 - crates/teloxide/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/crates/teloxide-core/Cargo.toml b/crates/teloxide-core/Cargo.toml index b68731fc..c2cb2ac2 100644 --- a/crates/teloxide-core/Cargo.toml +++ b/crates/teloxide-core/Cargo.toml @@ -72,7 +72,6 @@ once_cell = "1.5.0" takecell = "0.1" take_mut = "0.2" rc-box = "1.1.1" -never = "0.1.0" chrono = { version = "0.4.30", default-features = false } either = "1.6.1" bitflags = { version = "1.2" } diff --git a/crates/teloxide/Cargo.toml b/crates/teloxide/Cargo.toml index 573f2aba..02f78faa 100644 --- a/crates/teloxide/Cargo.toml +++ b/crates/teloxide/Cargo.toml @@ -96,7 +96,6 @@ derive_more = "0.99" thiserror = "1.0" futures = "0.3.15" pin-project = "1.0" -serde_with_macros = "3.4" aquamarine = "0.5.0" either = "1.9.0"