mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 22:46:39 +01:00
Merge branch 'dev' into v0.3.1_release
This commit is contained in:
commit
814adabdb6
42 changed files with 1116 additions and 323 deletions
41
.github/workflows/ci.yml
vendored
41
.github/workflows/ci.yml
vendored
|
@ -3,7 +3,7 @@ on:
|
|||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
branches: [ master, dev ]
|
||||
|
||||
name: Continuous integration
|
||||
|
||||
|
@ -27,23 +27,52 @@ jobs:
|
|||
override: true
|
||||
- name: Cargo clippy
|
||||
run: cargo clippy --all --all-targets --all-features -- -D warnings
|
||||
stable-test:
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
include:
|
||||
- rust: stable
|
||||
features: "--features \"redis-storage cbor-serializer bincode-serializer frunk-\""
|
||||
- rust: beta
|
||||
features: "--features \"redis-storage cbor-serializer bincode-serializer frunk-\""
|
||||
- rust: nightly
|
||||
features: "--all-features"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --verbose ${{ matrix.features }}
|
||||
|
||||
- name: Setup redis
|
||||
run: |
|
||||
sudo apt install redis-server
|
||||
redis-server --port 7777 > /dev/null &
|
||||
redis-server --port 7778 > /dev/null &
|
||||
redis-server --port 7779 > /dev/null &
|
||||
- name: Cargo test
|
||||
run: cargo test --all --all-features
|
||||
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --verbose ${{ matrix.features }}
|
||||
|
||||
build-example:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
|
@ -65,5 +94,5 @@ jobs:
|
|||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
- name: Test the example
|
||||
- name: Check the example
|
||||
run: cd examples && cd ${{ matrix.example }} && cargo check
|
||||
|
|
21
CHANGELOG.md
21
CHANGELOG.md
|
@ -4,6 +4,27 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [unreleased]
|
||||
|
||||
### Added
|
||||
- Allow arbitrary error types to be returned from (sub)transitions ([issue 242](https://github.com/teloxide/teloxide/issues/242)).
|
||||
- The `respond` function, a shortcut for `ResponseResult::Ok(())`.
|
||||
|
||||
### Changed
|
||||
- Allow `bot_name` be `N`, where `N: Into<String> + ...` in `commands_repl` & `commands_repl_with_listener`.
|
||||
- 'Edit methods' (namely `edit_message_live_location`, `stop_message_live_location`, `edit_message_text`,
|
||||
`edit_message_caption`, `edit_message_media` and `edit_message_reply_markup`) are split into common and inline
|
||||
versions (e.g.: `edit_message_text` and `edit_inline_message_text`). Instead of `ChatOrInlineMessage` common versions
|
||||
accept `chat_id: impl Into<ChatId>` and `message_id: i32` whereas inline versions accept
|
||||
`inline_message_id: impl Into<String>`. Also note that return type of inline versions is `True` ([issue 253], [pr 257])
|
||||
- `ChatOrInlineMessage` is renamed to `TargetMessage`, it's `::Chat` variant is renamed to `::Common`,
|
||||
`#[non_exhaustive]` annotation is removed from the enum, type of `TargetMessage::Inline::inline_message_id` changed
|
||||
`i32` => `String`. `TargetMessage` now implements `From<String>`, `get_game_high_scores` and `set_game_score` use
|
||||
`Into<TargetMessage>` to accept `String`s. ([issue 253], [pr 257])
|
||||
|
||||
[issue 253]: https://github.com/teloxide/teloxide/issues/253
|
||||
[pr 257]: https://github.com/teloxide/teloxide/pull/257
|
||||
|
||||
## [0.3.1] - 2020-08-25
|
||||
|
||||
### Added
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# 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).
|
||||
|
||||
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:
|
||||
To change the source code, fork the `dev` branch of this repository and work inside your own branch. Then send us a PR into `dev` branch and wait for the CI to check everything. However, you'd better check changes first locally:
|
||||
|
||||
```
|
||||
cargo clippy --all --all-features --all-targets
|
||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -30,6 +30,8 @@ bincode-serializer = ["bincode"]
|
|||
|
||||
frunk- = ["frunk"]
|
||||
|
||||
nightly = [] # currently used only for `README.md` tests
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0.55"
|
||||
serde = { version = "1.0.114", features = ["derive"] }
|
||||
|
@ -55,7 +57,7 @@ serde_cbor = { version = "0.11.1", optional = true }
|
|||
bincode = { version = "1.3.1", optional = true }
|
||||
frunk = { version = "0.3.1", optional = true }
|
||||
|
||||
teloxide-macros = "0.3.2"
|
||||
teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "master" }
|
||||
|
||||
[dev-dependencies]
|
||||
smart-default = "0.6.0"
|
||||
|
@ -63,3 +65,11 @@ rand = "0.7.3"
|
|||
pretty_env_logger = "0.4.0"
|
||||
lazy_static = "1.4.0"
|
||||
tokio = { version = "0.2.21", features = ["fs", "stream", "rt-threaded", "macros"] }
|
||||
|
||||
[package.metadata."docs.rs"]
|
||||
all-features = true
|
||||
|
||||
[[test]]
|
||||
name = "redis"
|
||||
path = "tests/redis.rs"
|
||||
required-features = ["redis-storage", "cbor-serializer", "bincode-serializer"]
|
||||
|
|
96
README.md
96
README.md
|
@ -1,52 +1,54 @@
|
|||
<div align="center">
|
||||
<img src="ICON.png" width="250"/>
|
||||
<h1>teloxide</h1>
|
||||
|
||||
<a href="https://docs.rs/teloxide/">
|
||||
<img src="https://docs.rs/teloxide/badge.svg">
|
||||
</a>
|
||||
<a href="https://github.com/teloxide/teloxide/actions">
|
||||
<img src="https://github.com/teloxide/teloxide/workflows/Continuous%20integration/badge.svg">
|
||||
</a>
|
||||
<a href="https://teloxide.netlify.com">
|
||||
<img src="https://img.shields.io/badge/docs-dev-blue)">
|
||||
</a>
|
||||
<a href="https://crates.io/crates/teloxide">
|
||||
<img src="https://img.shields.io/crates/v/teloxide.svg">
|
||||
</a>
|
||||
<a href="https://core.telegram.org/bots/api">
|
||||
<img src="https://img.shields.io/badge/API coverage-Up to 0.4.9 (inclusively)-green.svg">
|
||||
</a>
|
||||
<a href="https://t.me/teloxide">
|
||||
<img src="https://img.shields.io/badge/official%20chat-t.me%2Fteloxide-blueviolet">
|
||||
</a>
|
||||
<a href="https://core.telegram.org/bots/api">
|
||||
<img src="https://img.shields.io/badge/API coverage-Up to 0.4.7 (inclusively)-green.svg">
|
||||
</a>
|
||||
|
||||
A full-featured framework that empowers you to easily build [Telegram bots](https://telegram.org/blog/bot-revolution) using the [`async`/`.await`](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html) syntax in [Rust](https://www.rust-lang.org/). It handles all the difficult stuff so you can focus only on your business logic.
|
||||
</div>
|
||||
|
||||
## Table of contents
|
||||
- [Highlights](https://github.com/teloxide/teloxide#highlights)
|
||||
- [Setting up your environment](https://github.com/teloxide/teloxide#setting-up-your-environment)
|
||||
- [API overview](https://github.com/teloxide/teloxide#api-overview)
|
||||
- [The dices bot](https://github.com/teloxide/teloxide#the-dices-bot)
|
||||
- [Commands](https://github.com/teloxide/teloxide#commands)
|
||||
- [Dialogues management](https://github.com/teloxide/teloxide#dialogues-management)
|
||||
- [Recommendations](https://github.com/teloxide/teloxide#recommendations)
|
||||
- [Cargo features](https://github.com/teloxide/teloxide#cargo-features)
|
||||
- [FAQ](https://github.com/teloxide/teloxide#faq)
|
||||
- [Community bots](https://github.com/teloxide/teloxide#community-bots)
|
||||
- [Contributing](https://github.com/teloxide/teloxide#contributing)
|
||||
- [Highlights](#highlights)
|
||||
- [Setting up your environment](#setting-up-your-environment)
|
||||
- [API overview](#api-overview)
|
||||
- [The dices bot](#the-dices-bot)
|
||||
- [Commands](#commands)
|
||||
- [Dialogues management](#dialogues-management)
|
||||
- [Recommendations](#recommendations)
|
||||
- [Cargo features](#cargo-features)
|
||||
- [FAQ](#faq)
|
||||
- [Community bots](#community-bots)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
## Highlights
|
||||
|
||||
- **Functional reactive design.** teloxide has [functional reactive design], allowing you to declaratively manipulate streams of updates from Telegram using filters, maps, folds, zips, and a lot of [other adaptors].
|
||||
- **Functional reactive design.** teloxide follows [functional reactive design], allowing you to declaratively manipulate streams of updates from Telegram using filters, maps, folds, zips, and a lot of [other adaptors].
|
||||
|
||||
[functional reactive design]: https://en.wikipedia.org/wiki/Functional_reactive_programming
|
||||
[other adaptors]: https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html
|
||||
|
||||
- **Persistence.** Dialogues management is independent of how/where dialogues are stored: you can just replace one line and make them [persistent]. Out-of-the-box storages include [Redis].
|
||||
- **Dialogues management subsystem.** We have designed our dialogues management subsystem to be easy-to-use, and, furthermore, to be independent of how/where dialogues are stored. For example, you can just replace one line to achieve [persistence]. Out-of-the-box storages include [Redis].
|
||||
|
||||
[persistent]: https://en.wikipedia.org/wiki/Persistence_(computer_science)
|
||||
[persistence]: https://en.wikipedia.org/wiki/Persistence_(computer_science)
|
||||
[Redis]: https://redis.io/
|
||||
|
||||
- **Strongly typed bot commands.** You can describe bot commands as enumerations, and then they'll be automatically constructed from strings. Just like you describe JSON structures in [serde-json] and command-line arguments in [structopt].
|
||||
- **Strongly typed bot commands.** You can describe bot commands as enumerations, and then they'll be automatically constructed from strings — just like JSON structures in [serde-json] and command-line arguments in [structopt].
|
||||
|
||||
[structopt]: https://github.com/TeXitoi/structopt
|
||||
[serde-json]: https://github.com/serde-rs/json
|
||||
|
@ -90,8 +92,8 @@ tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] }
|
|||
### The dices bot
|
||||
This bot throws a dice on each incoming message:
|
||||
|
||||
([Full](https://github.com/teloxide/teloxide/blob/master/examples/dices_bot/src/main.rs))
|
||||
```rust
|
||||
([Full](./examples/dices_bot/src/main.rs))
|
||||
```rust,no_run
|
||||
use teloxide::prelude::*;
|
||||
|
||||
#[tokio::main]
|
||||
|
@ -107,12 +109,11 @@ async fn main() {
|
|||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<div align="center">
|
||||
<kbd>
|
||||
<img src=https://github.com/teloxide/teloxide/raw/master/media/DICES_BOT.gif />
|
||||
<img src=../../raw/master/media/DICES_BOT.gif />
|
||||
</kbd>
|
||||
</div>
|
||||
|
||||
|
@ -126,9 +127,9 @@ Commands are strongly typed and defined declaratively, similar to how we define
|
|||
[structopt]: https://docs.rs/structopt/0.3.9/structopt/
|
||||
[serde-json]: https://github.com/serde-rs/json
|
||||
|
||||
([Full](https://github.com/teloxide/teloxide/blob/master/examples/simple_commands_bot/src/main.rs))
|
||||
```rust
|
||||
// Imports are omitted...
|
||||
([Full](./examples/simple_commands_bot/src/main.rs))
|
||||
```rust,no_run
|
||||
use teloxide::{utils::command::BotCommand, prelude::*};
|
||||
|
||||
#[derive(BotCommand)]
|
||||
#[command(rename = "lowercase", description = "These commands are supported:")]
|
||||
|
@ -162,13 +163,14 @@ async fn main() {
|
|||
|
||||
let bot = Bot::from_env();
|
||||
|
||||
teloxide::commands_repl(bot, panic!("Your bot's name here"), answer).await;
|
||||
let bot_name: String = panic!("Your bot's name here");
|
||||
teloxide::commands_repl(bot, bot_name, answer).await;
|
||||
}
|
||||
```
|
||||
|
||||
<div align="center">
|
||||
<kbd>
|
||||
<img src=https://github.com/teloxide/teloxide/raw/master/media/SIMPLE_COMMANDS_BOT.gif />
|
||||
<img src=../../raw/master/media/SIMPLE_COMMANDS_BOT.gif />
|
||||
</kbd>
|
||||
</div>
|
||||
|
||||
|
@ -179,8 +181,8 @@ A dialogue is described by an enumeration, where each variant is one of possible
|
|||
|
||||
Below is a bot, which asks you three questions and then sends the answers back to you. First, let's start with an enumeration (a collection of our dialogue's states):
|
||||
|
||||
([dialogue_bot/src/dialogue/mod.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/mod.rs))
|
||||
```rust
|
||||
([dialogue_bot/src/dialogue/mod.rs](./examples/dialogue_bot/src/dialogue/mod.rs))
|
||||
```rust,ignore
|
||||
// Imports are omitted...
|
||||
|
||||
#[derive(Transition, From)]
|
||||
|
@ -203,8 +205,8 @@ When a user sends a message to our bot, and such a dialogue does not yet exist,
|
|||
<details>
|
||||
<summary>Dialogue::Start</summary>
|
||||
|
||||
([dialogue_bot/src/dialogue/states/start.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/start.rs))
|
||||
```rust
|
||||
([dialogue_bot/src/dialogue/states/start.rs](./examples/dialogue_bot/src/dialogue/states/start.rs))
|
||||
```rust,ignore
|
||||
// Imports are omitted...
|
||||
|
||||
pub struct StartState;
|
||||
|
@ -221,8 +223,8 @@ async fn start(_state: StartState, cx: TransitionIn, _ans: String) -> Transition
|
|||
<details>
|
||||
<summary>Dialogue::ReceiveFullName</summary>
|
||||
|
||||
([dialogue_bot/src/dialogue/states/receive_full_name.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/receive_full_name.rs))
|
||||
```rust
|
||||
([dialogue_bot/src/dialogue/states/receive_full_name.rs](./examples/dialogue_bot/src/dialogue/states/receive_full_name.rs))
|
||||
```rust,ignore
|
||||
// Imports are omitted...
|
||||
|
||||
#[derive(Generic)]
|
||||
|
@ -244,8 +246,8 @@ async fn receive_full_name(
|
|||
<details>
|
||||
<summary>Dialogue::ReceiveAge</summary>
|
||||
|
||||
([dialogue_bot/src/dialogue/states/receive_age.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/receive_age.rs))
|
||||
```rust
|
||||
([dialogue_bot/src/dialogue/states/receive_age.rs](./examples/dialogue_bot/src/dialogue/states/receive_age.rs))
|
||||
```rust,ignore
|
||||
// Imports are omitted...
|
||||
|
||||
#[derive(Generic)]
|
||||
|
@ -277,8 +279,8 @@ async fn receive_age_state(
|
|||
<details>
|
||||
<summary>Dialogue::ReceiveLocation</summary>
|
||||
|
||||
([dialogue_bot/src/dialogue/states/receive_location.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/receive_location.rs))
|
||||
```rust
|
||||
([dialogue_bot/src/dialogue/states/receive_location.rs](./examples/dialogue_bot/src/dialogue/states/receive_location.rs))
|
||||
```rust,ignore
|
||||
// Imports are omitted...
|
||||
|
||||
#[derive(Generic)]
|
||||
|
@ -305,8 +307,8 @@ All these subtransitions accept a corresponding state (one of the many variants
|
|||
|
||||
Finally, the `main` function looks like this:
|
||||
|
||||
([dialogue_bot/src/main.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/main.rs))
|
||||
```rust
|
||||
([dialogue_bot/src/main.rs](./examples/dialogue_bot/src/main.rs))
|
||||
```rust,ignore
|
||||
// Imports are omitted...
|
||||
|
||||
#[tokio::main]
|
||||
|
@ -335,11 +337,11 @@ async fn handle_message(cx: UpdateWithCx<Message>, dialogue: Dialogue) -> Transi
|
|||
|
||||
<div align="center">
|
||||
<kbd>
|
||||
<img src=https://github.com/teloxide/teloxide/raw/master/media/DIALOGUE_BOT.gif />
|
||||
<img src=../../raw/master/media/DIALOGUE_BOT.gif />
|
||||
</kbd>
|
||||
</div>
|
||||
|
||||
[More examples!](https://github.com/teloxide/teloxide/tree/master/examples)
|
||||
[More examples!](./examples)
|
||||
|
||||
## Recommendations
|
||||
- Use this pattern:
|
||||
|
@ -403,7 +405,7 @@ UPD: The current design spreads wide and deep trait bounds, thereby increasing c
|
|||
|
||||
Q: Can I use webhooks?
|
||||
|
||||
A: teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you setup your webhook by yourself, as shown in [`examples/ngrok_ping_pong_bot`](examples/ngrok_ping_pong_bot/src/main.rs) and [`examples/heroku_ping_pong_bot`](examples/heroku_ping_pong_bot/src/main.rs).
|
||||
A: teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you setup your webhook by yourself, as shown in [`examples/ngrok_ping_pong_bot`](./examples/ngrok_ping_pong_bot/src/main.rs) and [`examples/heroku_ping_pong_bot`](./examples/heroku_ping_pong_bot/src/main.rs).
|
||||
|
||||
Associated links:
|
||||
- [Marvin's Marvellous Guide to All Things Webhook](https://core.telegram.org/bots/webhooks)
|
||||
|
@ -421,9 +423,11 @@ A: Yes. You can setup any logger, for example, [fern], e.g. teloxide has no spec
|
|||
## Community bots
|
||||
Feel free to push your own bot into our collection!
|
||||
|
||||
- [_Rust subreddit reader_](https://github.com/steadylearner/Rust-Full-Stack/tree/master/commits/teloxide/subreddit_reader)
|
||||
- [_vzmuinebot -- Telegram bot for food menu navigate_](https://github.com/ArtHome12/vzmuinebot)
|
||||
- [_Tepe -- A CLI to command a bot to send messages and files over Telegram_](https://lib.rs/crates/tepe)
|
||||
- [_steadylearner/subreddit_reader_](https://github.com/steadylearner/Rust-Full-Stack/tree/master/commits/teloxide/subreddit_reader)
|
||||
- [_ArtHome12/vzmuinebot -- Telegram bot for food menu navigate_](https://github.com/ArtHome12/vzmuinebot)
|
||||
- [_Hermitter/tepe -- A CLI to command a bot to send messages and files over Telegram_](https://github.com/Hermitter/tepe)
|
||||
- [_ArtHome12/cognito_bot -- The bot is designed to anonymize messages to a group_](https://github.com/ArtHome12/cognito_bot)
|
||||
- [_GoldsteinE/tg-vimhelpbot -- Link `:help` for Vim in Telegram_](https://github.com/GoldsteinE/tg-vimhelpbot)
|
||||
|
||||
## Contributing
|
||||
See [CONRIBUTING.md](https://github.com/teloxide/teloxide/blob/master/CONTRIBUTING.md).
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
Just enter the directory (for example, `cd dialogue_bot`) and execute `cargo run` to run an example. Don't forget to initialise the `TELOXIDE_TOKEN` environmental variable.
|
||||
| Bot | Description |
|
||||
|---|-----------|
|
||||
| [dices_bot](dices_bot) | This bot throws a dice on each incoming message. |
|
||||
| [dices_bot](dices_bot) | Throws a dice on each incoming message. |
|
||||
| [ngrok_ping_pong_bot](ngrok_ping_pong_bot) | The ngrok version of ping-pong-bot that uses webhooks. |
|
||||
| [heroku_ping_pong_bot](heroku_ping_pong_bot) | The Heroku version of ping-pong-bot that uses webhooks. |
|
||||
| [simple_commands_bot](simple_commands_bot) | Shows how to deal with bot's commands. |
|
||||
| [guess_a_number_bot](guess_a_number_bot) | The "guess a number" game. |
|
||||
| [dialogue_bot](dialogue_bot) | Drive a dialogue with a user using a type-safe finite automaton. |
|
||||
| [admin_bot](admin_bot) | A bot, which can ban, kick, and mute on a command. |
|
||||
| [shared_state_bot](shared_state_bot) | A bot that shows how to deal with shared state. |
|
||||
| [redis_remember_bot](redis_remember_bot) | Uses `RedisStorage` instead of `InMemStorage`. |
|
||||
| [dialogue_bot](dialogue_bot) | How to deal with dialogues. |
|
||||
| [admin_bot](admin_bot) | Ban, kick, and mute on a command. |
|
||||
| [shared_state_bot](shared_state_bot) | How to deal with shared state. |
|
||||
|
|
|
@ -139,5 +139,6 @@ async fn run() {
|
|||
|
||||
let bot = Bot::from_env();
|
||||
|
||||
teloxide::commands_repl(bot, panic!("Your bot's name here"), action).await;
|
||||
let bot_name: String = panic!("Your bot's name here");
|
||||
teloxide::commands_repl(bot, bot_name, action).await;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ futures = "0.3.5"
|
|||
tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] }
|
||||
|
||||
teloxide = { path = "../../", features = ["frunk"] }
|
||||
teloxide-macros = "0.3.2"
|
||||
teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "master" }
|
||||
|
||||
derive_more = "0.99.9"
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ async fn run() {
|
|||
|
||||
teloxide::repl(bot, |message| async move {
|
||||
message.answer_dice().send().await?;
|
||||
ResponseResult::<()>::Ok(())
|
||||
respond(())
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] }
|
|||
|
||||
# You can also choose "cbor-serializer" or built-in JSON serializer
|
||||
teloxide = { path = "../../", features = ["redis-storage", "bincode-serializer"] }
|
||||
teloxide-macros = "0.3.2"
|
||||
teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "master" }
|
||||
|
||||
serde = "1.0.104"
|
||||
futures = "0.3.5"
|
||||
|
|
|
@ -36,5 +36,6 @@ async fn run() {
|
|||
|
||||
let bot = Bot::from_env();
|
||||
|
||||
teloxide::commands_repl(bot, panic!("Your bot's name here"), answer).await;
|
||||
let bot_name: String = panic!("Your bot's name here");
|
||||
teloxide::commands_repl(bot, bot_name, answer).await;
|
||||
}
|
||||
|
|
12
netlify.toml
Normal file
12
netlify.toml
Normal file
|
@ -0,0 +1,12 @@
|
|||
[build]
|
||||
# Directory (relative to root of your repo) that contains the deploy-ready
|
||||
# HTML files and assets generated by the build. If a base directory has
|
||||
# been specified, include it in the publish directory path.
|
||||
publish = "target/doc"
|
||||
|
||||
# Default build command.
|
||||
command = 'curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly --profile minimal && source $HOME/.cargo/env && RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --no-deps --all-features'
|
||||
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/teloxide"
|
331
src/bot/api.rs
331
src/bot/api.rs
|
@ -2,26 +2,27 @@ use crate::{
|
|||
requests::{
|
||||
AddStickerToSet, AnswerCallbackQuery, AnswerInlineQuery, AnswerPreCheckoutQuery,
|
||||
AnswerShippingQuery, CreateNewStickerSet, DeleteChatPhoto, DeleteChatStickerSet,
|
||||
DeleteMessage, DeleteStickerFromSet, DeleteWebhook, EditMessageCaption,
|
||||
EditMessageLiveLocation, EditMessageMedia, EditMessageReplyMarkup, EditMessageText,
|
||||
ExportChatInviteLink, ForwardMessage, GetChat, GetChatAdministrators, GetChatMember,
|
||||
GetChatMembersCount, GetFile, GetGameHighScores, GetMe, GetMyCommands, GetStickerSet,
|
||||
GetUpdates, GetUserProfilePhotos, GetWebhookInfo, KickChatMember, LeaveChat,
|
||||
PinChatMessage, PromoteChatMember, RestrictChatMember, SendAnimation, SendAudio,
|
||||
SendChatAction, SendChatActionKind, SendContact, SendDice, SendDocument, SendGame,
|
||||
SendInvoice, SendLocation, SendMediaGroup, SendMessage, SendPhoto, SendPoll, SendSticker,
|
||||
SendVenue, SendVideo, SendVideoNote, SendVoice, SetChatAdministratorCustomTitle,
|
||||
SetChatDescription, SetChatPermissions, SetChatPhoto, SetChatStickerSet, SetChatTitle,
|
||||
SetGameScore, SetMyCommands, SetStickerPositionInSet, SetStickerSetThumb, SetWebhook,
|
||||
StopMessageLiveLocation, StopPoll, UnbanChatMember, UnpinChatMessage, UploadStickerFile,
|
||||
DeleteMessage, DeleteStickerFromSet, DeleteWebhook, EditInlineMessageCaption,
|
||||
EditInlineMessageLiveLocation, EditInlineMessageMedia, EditInlineMessageReplyMarkup,
|
||||
EditInlineMessageText, EditMessageCaption, EditMessageLiveLocation, EditMessageMedia,
|
||||
EditMessageReplyMarkup, EditMessageText, ExportChatInviteLink, ForwardMessage, GetChat,
|
||||
GetChatAdministrators, GetChatMember, GetChatMembersCount, GetFile, GetGameHighScores,
|
||||
GetMe, GetMyCommands, GetStickerSet, GetUpdates, GetUserProfilePhotos, GetWebhookInfo,
|
||||
KickChatMember, LeaveChat, PinChatMessage, PromoteChatMember, RestrictChatMember,
|
||||
SendAnimation, SendAudio, SendChatAction, SendChatActionKind, SendContact, SendDice,
|
||||
SendDocument, SendGame, SendInvoice, SendLocation, SendMediaGroup, SendMessage, SendPhoto,
|
||||
SendPoll, SendSticker, SendVenue, SendVideo, SendVideoNote, SendVoice,
|
||||
SetChatAdministratorCustomTitle, SetChatDescription, SetChatPermissions, SetChatPhoto,
|
||||
SetChatStickerSet, SetChatTitle, SetGameScore, SetMyCommands, SetStickerPositionInSet,
|
||||
SetStickerSetThumb, SetWebhook, StopInlineMessageLiveLocation, StopMessageLiveLocation,
|
||||
StopPoll, UnbanChatMember, UnpinChatMessage, UploadStickerFile,
|
||||
},
|
||||
types::{
|
||||
BotCommand, ChatId, ChatOrInlineMessage, ChatPermissions, InlineQueryResult, InputFile,
|
||||
InputMedia, LabeledPrice, ParseMode, StickerType,
|
||||
BotCommand, ChatId, ChatPermissions, InlineQueryResult, InputFile, InputMedia,
|
||||
LabeledPrice, ParseMode, StickerType, TargetMessage,
|
||||
},
|
||||
Bot,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
|
||||
impl Bot {
|
||||
/// Use this method to receive incoming updates using long polling ([wiki]).
|
||||
|
@ -410,42 +411,89 @@ impl Bot {
|
|||
/// Use this method to edit live location messages.
|
||||
///
|
||||
/// A location can be edited until its live_period expires or editing is
|
||||
/// explicitly disabled by a call to stopMessageLiveLocation. On success, if
|
||||
/// the edited message was sent by the bot, the edited [`Message`] is
|
||||
/// returned, otherwise [`True`] is returned.
|
||||
/// explicitly disabled by a call to stopMessageLiveLocation. On success,
|
||||
/// the edited [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagelivelocation).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
///
|
||||
/// # Params
|
||||
/// - `latitude`: Latitude of new location.
|
||||
/// - `longitude`: Longitude of new location.
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
pub fn edit_message_live_location(
|
||||
pub fn edit_message_live_location<C>(
|
||||
&self,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
chat_id: C,
|
||||
message_id: i32,
|
||||
latitude: f32,
|
||||
longitude: f32,
|
||||
) -> EditMessageLiveLocation {
|
||||
EditMessageLiveLocation::new(self.clone(), chat_or_inline_message, latitude, longitude)
|
||||
) -> EditMessageLiveLocation
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
EditMessageLiveLocation::new(self.clone(), chat_id, message_id, latitude, longitude)
|
||||
}
|
||||
|
||||
/// Use this method to edit live location messages sent via the bot.
|
||||
///
|
||||
/// A location can be edited until its live_period expires or editing is
|
||||
/// explicitly disabled by a call to stopMessageLiveLocation. On success,
|
||||
/// [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagelivelocation).
|
||||
///
|
||||
/// [`True`]: crate::types::True
|
||||
///
|
||||
/// # Params
|
||||
/// - `latitude`: Latitude of new location.
|
||||
/// - `longitude`: Longitude of new location.
|
||||
pub fn edit_inline_message_live_location<I>(
|
||||
&self,
|
||||
inline_message_id: I,
|
||||
latitude: f32,
|
||||
longitude: f32,
|
||||
) -> EditInlineMessageLiveLocation
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
EditInlineMessageLiveLocation::new(self.clone(), inline_message_id, latitude, longitude)
|
||||
}
|
||||
|
||||
/// Use this method to stop updating a live location message before
|
||||
/// `live_period` expires.
|
||||
///
|
||||
/// On success, if the message was sent by the bot, the sent [`Message`] is
|
||||
/// returned, otherwise [`True`] is returned.
|
||||
/// On success, the sent [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#stopmessagelivelocation).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
pub fn stop_message_live_location(
|
||||
pub fn stop_message_live_location<C>(
|
||||
&self,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
) -> StopMessageLiveLocation {
|
||||
StopMessageLiveLocation::new(self.clone(), chat_or_inline_message)
|
||||
chat_id: C,
|
||||
message_id: i32,
|
||||
) -> StopMessageLiveLocation
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
StopMessageLiveLocation::new(self.clone(), chat_id, message_id)
|
||||
}
|
||||
|
||||
/// Use this method to stop updating a live location message (sent via the
|
||||
/// bot) before `live_period` expires.
|
||||
///
|
||||
/// On success, [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#stopmessagelivelocation).
|
||||
///
|
||||
/// [`True`]: crate::types::True
|
||||
pub fn stop_inline_message_live_location<I>(
|
||||
&self,
|
||||
inline_message_id: I,
|
||||
) -> StopInlineMessageLiveLocation
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
StopInlineMessageLiveLocation::new(self.clone(), inline_message_id)
|
||||
}
|
||||
|
||||
/// Use this method to send information about a venue.
|
||||
|
@ -983,45 +1031,105 @@ impl Bot {
|
|||
|
||||
/// Use this method to edit text and game messages.
|
||||
///
|
||||
/// On success, if edited message is sent by the bot, the edited [`Message`]
|
||||
/// is returned, otherwise [`True`] is returned.
|
||||
/// On success, the edited [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagetext).
|
||||
///
|
||||
/// # Params
|
||||
/// - New text of the message.
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
///
|
||||
/// # Params
|
||||
///
|
||||
/// - `chat_id`: Unique identifier for the target chat or username of the
|
||||
/// target channel (in the format `@channelusername`).
|
||||
/// - `message_id`: Identifier of the message to edit.
|
||||
/// - `text`: New text of the message.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// Uses [a default parse mode] if specified in [`BotBuilder`].
|
||||
///
|
||||
/// [a default parse mode]: crate::BotBuilder::parse_mode
|
||||
/// [`BotBuilder`]: crate::BotBuilder
|
||||
pub fn edit_message_text<T>(
|
||||
&self,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
text: T,
|
||||
) -> EditMessageText
|
||||
pub fn edit_message_text<C, T>(&self, chat_id: C, message_id: i32, text: T) -> EditMessageText
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
T: Into<String>,
|
||||
{
|
||||
match self.parse_mode.deref() {
|
||||
None => EditMessageText::new(self.clone(), chat_or_inline_message, text),
|
||||
Some(parse_mode) => EditMessageText::new(self.clone(), chat_or_inline_message, text)
|
||||
.parse_mode(*parse_mode.deref()),
|
||||
match self.parse_mode {
|
||||
None => EditMessageText::new(self.clone(), chat_id, message_id, text),
|
||||
Some(parse_mode) => {
|
||||
EditMessageText::new(self.clone(), chat_id, message_id, text).parse_mode(parse_mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Use this method to edit captions of messages.
|
||||
/// Use this method to edit text and game messages sent via the bot.
|
||||
///
|
||||
/// On success, if edited message is sent by the bot, the edited [`Message`]
|
||||
/// is returned, otherwise [`True`] is returned.
|
||||
/// On success, [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagetext).
|
||||
///
|
||||
/// [`True`]: crate::types::True
|
||||
///
|
||||
/// # Params
|
||||
///
|
||||
/// - `inline_message_id`: Identifier of the inline message.
|
||||
/// - `text`: New text of the message.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// Uses [a default parse mode] if specified in [`BotBuilder`].
|
||||
///
|
||||
/// [a default parse mode]: crate::BotBuilder::parse_mode
|
||||
/// [`BotBuilder`]: crate::BotBuilder
|
||||
pub fn edit_inline_message_text<I, T>(
|
||||
&self,
|
||||
inline_message_id: I,
|
||||
text: T,
|
||||
) -> EditInlineMessageText
|
||||
where
|
||||
I: Into<String>,
|
||||
T: Into<String>,
|
||||
{
|
||||
match self.parse_mode {
|
||||
None => EditInlineMessageText::new(self.clone(), inline_message_id, text),
|
||||
Some(parse_mode) => EditInlineMessageText::new(self.clone(), inline_message_id, text)
|
||||
.parse_mode(parse_mode),
|
||||
}
|
||||
}
|
||||
|
||||
/// Use this method to edit captions of messages sent via the bot.
|
||||
///
|
||||
/// On success, [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagecaption).
|
||||
///
|
||||
/// [`True`]: crate::types::True
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// Uses [a default parse mode] if specified in [`BotBuilder`].
|
||||
///
|
||||
/// [a default parse mode]: crate::BotBuilder::parse_mode
|
||||
/// [`BotBuilder`]: crate::BotBuilder
|
||||
pub fn edit_message_caption<C>(&self, chat_id: C, message_id: i32) -> EditMessageCaption
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
match self.parse_mode {
|
||||
None => EditMessageCaption::new(self.clone(), chat_id, message_id),
|
||||
Some(parse_mode) => {
|
||||
EditMessageCaption::new(self.clone(), chat_id, message_id).parse_mode(parse_mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Use this method to edit captions of messages sent via the bot.
|
||||
///
|
||||
/// On success, [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagecaption).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
///
|
||||
/// # Notes
|
||||
|
@ -1029,14 +1137,14 @@ impl Bot {
|
|||
///
|
||||
/// [a default parse mode]: crate::BotBuilder::parse_mode
|
||||
/// [`BotBuilder`]: crate::BotBuilder
|
||||
pub fn edit_message_caption(
|
||||
&self,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
) -> EditMessageCaption {
|
||||
match self.parse_mode.deref() {
|
||||
None => EditMessageCaption::new(self.clone(), chat_or_inline_message),
|
||||
Some(parse_mode) => EditMessageCaption::new(self.clone(), chat_or_inline_message)
|
||||
.parse_mode(*parse_mode.deref()),
|
||||
pub fn edit_inline_message_caption<I>(&self, inline_message_id: I) -> EditInlineMessageCaption
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
match self.parse_mode {
|
||||
None => EditInlineMessageCaption::new(self.clone(), inline_message_id),
|
||||
Some(parse_mode) => EditInlineMessageCaption::new(self.clone(), inline_message_id)
|
||||
.parse_mode(parse_mode),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1045,37 +1153,81 @@ impl Bot {
|
|||
///
|
||||
/// If a message is a part of a message album, then it can be edited only to
|
||||
/// a photo or a video. Otherwise, message type can be changed
|
||||
/// arbitrarily. When inline message is edited, new file can't be
|
||||
/// uploaded. Use previously uploaded file via its `file_id` or specify
|
||||
/// a URL. On success, if the edited message was sent by the bot, the
|
||||
/// edited [`Message`] is returned, otherwise [`True`] is returned.
|
||||
/// arbitrarily. On success, the edited [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagemedia).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
pub fn edit_message_media(
|
||||
pub fn edit_message_media<C>(
|
||||
&self,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
chat_id: C,
|
||||
message_id: i32,
|
||||
media: InputMedia,
|
||||
) -> EditMessageMedia {
|
||||
EditMessageMedia::new(self.clone(), chat_or_inline_message, media)
|
||||
) -> EditMessageMedia
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
EditMessageMedia::new(self.clone(), chat_id, message_id, media)
|
||||
}
|
||||
|
||||
/// Use this method to edit animation, audio, document, photo, or video
|
||||
/// messages sent via the bot.
|
||||
///
|
||||
/// If a message is a part of a message album, then it can be edited only to
|
||||
/// a photo or a video. Otherwise, message type can be changed
|
||||
/// arbitrarily. When this method is used, new file can't be uploaded.
|
||||
/// Use previously uploaded file via its `file_id` or specify a URL. On
|
||||
/// success, [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagemedia).
|
||||
///
|
||||
/// [`True`]: crate::types::True
|
||||
pub fn edit_inline_message_media<I>(
|
||||
&self,
|
||||
inline_message_id: I,
|
||||
media: InputMedia,
|
||||
) -> EditInlineMessageMedia
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
EditInlineMessageMedia::new(self.clone(), inline_message_id, media)
|
||||
}
|
||||
|
||||
/// Use this method to edit only the reply markup of messages.
|
||||
///
|
||||
/// On success, if edited message is sent by the bot, the edited [`Message`]
|
||||
/// is returned, otherwise [`True`] is returned.
|
||||
/// On success, the edited [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagereplymarkup).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
pub fn edit_message_reply_markup<C>(
|
||||
&self,
|
||||
chat_id: C,
|
||||
message_id: i32,
|
||||
) -> EditMessageReplyMarkup
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
EditMessageReplyMarkup::new(self.clone(), chat_id, message_id)
|
||||
}
|
||||
|
||||
/// Use this method to edit only the reply markup of messages sent via the
|
||||
/// bot.
|
||||
///
|
||||
/// On success, [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagereplymarkup).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
pub fn edit_message_reply_markup(
|
||||
pub fn edit_inline_message_reply_markup<I>(
|
||||
&self,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
) -> EditMessageReplyMarkup {
|
||||
EditMessageReplyMarkup::new(self.clone(), chat_or_inline_message)
|
||||
inline_message_id: I,
|
||||
) -> EditInlineMessageReplyMarkup
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
EditInlineMessageReplyMarkup::new(self.clone(), inline_message_id)
|
||||
}
|
||||
|
||||
/// Use this method to stop a poll which was sent by the bot.
|
||||
|
@ -1413,18 +1565,18 @@ impl Bot {
|
|||
/// [The official docs](https://core.telegram.org/bots/api#setgamescore).
|
||||
///
|
||||
/// # Params
|
||||
/// - `target`: Target message, either chat id and message id or inline
|
||||
/// message id.
|
||||
/// - `user_id`: User identifier.
|
||||
/// - `score`: New score, must be non-negative.
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
pub fn set_game_score(
|
||||
&self,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
user_id: i32,
|
||||
score: i32,
|
||||
) -> SetGameScore {
|
||||
SetGameScore::new(self.clone(), chat_or_inline_message, user_id, score)
|
||||
pub fn set_game_score<T>(&self, target: T, user_id: i32, score: i32) -> SetGameScore
|
||||
where
|
||||
T: Into<TargetMessage>,
|
||||
{
|
||||
SetGameScore::new(self.clone(), target, user_id, score)
|
||||
}
|
||||
|
||||
/// Use this method to get data for high score tables.
|
||||
|
@ -1441,13 +1593,14 @@ impl Bot {
|
|||
/// [The official docs](https://core.telegram.org/bots/api#getgamehighscores).
|
||||
///
|
||||
/// # Params
|
||||
/// - `target`: Target message, either chat id and message id or inline
|
||||
/// message id.
|
||||
/// - `user_id`: Target user id.
|
||||
pub fn get_game_high_scores(
|
||||
&self,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
user_id: i32,
|
||||
) -> GetGameHighScores {
|
||||
GetGameHighScores::new(self.clone(), chat_or_inline_message, user_id)
|
||||
pub fn get_game_high_scores<T>(&self, target: T, user_id: i32) -> GetGameHighScores
|
||||
where
|
||||
T: Into<TargetMessage>,
|
||||
{
|
||||
GetGameHighScores::new(self.clone(), target, user_id)
|
||||
}
|
||||
|
||||
/// Use this method to set a custom title for an administrator in a
|
||||
|
@ -1530,9 +1683,9 @@ impl Bot {
|
|||
builder: Builder,
|
||||
f: fn(Builder, ParseMode) -> Builder,
|
||||
) -> Builder {
|
||||
match self.parse_mode.deref() {
|
||||
match self.parse_mode {
|
||||
None => builder,
|
||||
Some(parse_mode) => f(builder, *parse_mode.deref()),
|
||||
Some(parse_mode) => f(builder, parse_mode),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ pub(crate) const TELOXIDE_PROXY: &str = "TELOXIDE_PROXY";
|
|||
pub struct Bot {
|
||||
token: Arc<str>,
|
||||
client: Client,
|
||||
parse_mode: Arc<Option<ParseMode>>,
|
||||
parse_mode: Option<ParseMode>,
|
||||
}
|
||||
|
||||
impl Bot {
|
||||
|
@ -41,8 +41,7 @@ impl Bot {
|
|||
/// client.
|
||||
///
|
||||
/// # Panics
|
||||
/// - If cannot get the `TELOXIDE_TOKEN` and `TELOXIDE_PROXY` environmental
|
||||
/// variables.
|
||||
/// - If cannot get the `TELOXIDE_TOKEN` environmental variable.
|
||||
/// - If it cannot create [`reqwest::Client`].
|
||||
///
|
||||
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||
|
@ -106,7 +105,7 @@ impl Bot {
|
|||
Self {
|
||||
token: Into::<Arc<str>>::into(Into::<String>::into(token)),
|
||||
client,
|
||||
parse_mode: Arc::new(None),
|
||||
parse_mode: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,11 +230,11 @@ impl BotBuilder {
|
|||
///
|
||||
/// This method will attempt to build a new client with a proxy, specified
|
||||
/// in the `TELOXIDE_PROXY` (passed into [`reqwest::Proxy::all`])
|
||||
/// environmental variable, if a client haven't been specified.
|
||||
/// environmental variable, if a client haven't been specified. If
|
||||
/// `TELOXIDE_PROXY` is unspecified, it'll use no proxy.
|
||||
///
|
||||
/// # Panics
|
||||
/// - If cannot get the `TELOXIDE_TOKEN` and `TELOXIDE_PROXY` environmental
|
||||
/// variables.
|
||||
/// - If cannot get the `TELOXIDE_TOKEN` environmental variable.
|
||||
/// - If it cannot create [`reqwest::Client`].
|
||||
///
|
||||
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||
|
@ -247,7 +246,7 @@ impl BotBuilder {
|
|||
Bot {
|
||||
client: self.client.unwrap_or_else(crate::utils::client_from_env),
|
||||
token: self.token.unwrap_or_else(|| get_env(TELOXIDE_TOKEN)).into(),
|
||||
parse_mode: Arc::new(self.parse_mode),
|
||||
parse_mode: self.parse_mode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ pub enum DialogueStage<D> {
|
|||
///
|
||||
/// [`From`]: std::convert::From
|
||||
/// [derive-more]: https://crates.io/crates/derive_more
|
||||
pub fn next<Dialogue, State>(new_state: State) -> TransitionOut<Dialogue>
|
||||
pub fn next<Dialogue, State, E>(new_state: State) -> TransitionOut<Dialogue, E>
|
||||
where
|
||||
Dialogue: From<State>,
|
||||
{
|
||||
|
@ -32,6 +32,6 @@ where
|
|||
///
|
||||
/// See [the module-level documentation for the design
|
||||
/// overview](crate::dispatching::dialogue).
|
||||
pub fn exit<D>() -> TransitionOut<D> {
|
||||
pub fn exit<D, E>() -> TransitionOut<D, E> {
|
||||
Ok(DialogueStage::Exit)
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
//! struct _2State;
|
||||
//! struct _3State;
|
||||
//!
|
||||
//! type Out = TransitionOut<D>;
|
||||
//! type Out = TransitionOut<D, RequestError>;
|
||||
//!
|
||||
//! #[teloxide(subtransition)]
|
||||
//! async fn _1_transition(_state: _1State, _cx: TransitionIn) -> Out {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::{
|
||||
dispatching::{dialogue::DialogueStage, UpdateWithCx},
|
||||
requests::ResponseResult,
|
||||
types::Message,
|
||||
};
|
||||
use futures::future::BoxFuture;
|
||||
|
@ -8,11 +7,16 @@ use futures::future::BoxFuture;
|
|||
/// Represents a transition function of a dialogue FSM.
|
||||
pub trait Transition: Sized {
|
||||
type Aux;
|
||||
type Error;
|
||||
|
||||
/// Turns itself into another state, depending on the input message.
|
||||
///
|
||||
/// `aux` will be passed to each subtransition function.
|
||||
fn react(self, cx: TransitionIn, aux: Self::Aux) -> BoxFuture<'static, TransitionOut<Self>>;
|
||||
fn react(
|
||||
self,
|
||||
cx: TransitionIn,
|
||||
aux: Self::Aux,
|
||||
) -> BoxFuture<'static, TransitionOut<Self, Self::Error>>;
|
||||
}
|
||||
|
||||
/// Like [`Transition`], but from `StateN` -> `Dialogue`.
|
||||
|
@ -24,6 +28,7 @@ where
|
|||
{
|
||||
type Aux;
|
||||
type Dialogue;
|
||||
type Error;
|
||||
|
||||
/// Turns itself into another state, depending on the input message.
|
||||
///
|
||||
|
@ -33,7 +38,7 @@ where
|
|||
self,
|
||||
cx: TransitionIn,
|
||||
aux: Self::Aux,
|
||||
) -> BoxFuture<'static, TransitionOut<Self::Dialogue>>;
|
||||
) -> BoxFuture<'static, TransitionOut<Self::Dialogue, Self::Error>>;
|
||||
}
|
||||
|
||||
/// A type returned from a FSM subtransition function.
|
||||
|
@ -41,14 +46,16 @@ where
|
|||
/// Now it is used only inside `#[teloxide(subtransition)]` for type inference.
|
||||
pub trait SubtransitionOutputType {
|
||||
type Output;
|
||||
type Error;
|
||||
}
|
||||
|
||||
impl<D> SubtransitionOutputType for TransitionOut<D> {
|
||||
impl<D, E> SubtransitionOutputType for TransitionOut<D, E> {
|
||||
type Output = D;
|
||||
type Error = E;
|
||||
}
|
||||
|
||||
/// An input passed into a FSM (sub)transition function.
|
||||
pub type TransitionIn = UpdateWithCx<Message>;
|
||||
|
||||
/// A type returned from a FSM (sub)transition function.
|
||||
pub type TransitionOut<D> = ResponseResult<DialogueStage<D>>;
|
||||
pub type TransitionOut<D, E = crate::RequestError> = Result<DialogueStage<D>, E>;
|
||||
|
|
|
@ -22,13 +22,14 @@ use std::{fmt::Debug, future::Future, sync::Arc};
|
|||
///
|
||||
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
|
||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||
pub async fn commands_repl<Cmd, H, Fut, HandlerE>(bot: Bot, bot_name: &'static str, handler: H)
|
||||
pub async fn commands_repl<Cmd, H, Fut, HandlerE, N>(bot: Bot, bot_name: N, handler: H)
|
||||
where
|
||||
Cmd: BotCommand + Send + 'static,
|
||||
H: Fn(UpdateWithCx<Message>, Cmd) -> Fut + Send + Sync + 'static,
|
||||
Fut: Future<Output = Result<(), HandlerE>> + Send + 'static,
|
||||
Result<(), HandlerE>: OnError<HandlerE>,
|
||||
HandlerE: Debug + Send,
|
||||
N: Into<String> + Send + 'static,
|
||||
{
|
||||
let cloned_bot = bot.clone();
|
||||
|
||||
|
@ -53,9 +54,9 @@ where
|
|||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||
/// [`commands_repl`]: crate::dispatching::repls::commands_repl()
|
||||
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
|
||||
pub async fn commands_repl_with_listener<'a, Cmd, H, Fut, L, ListenerE, HandlerE>(
|
||||
pub async fn commands_repl_with_listener<'a, Cmd, H, Fut, L, ListenerE, HandlerE, N>(
|
||||
bot: Bot,
|
||||
bot_name: &'static str,
|
||||
bot_name: N,
|
||||
handler: H,
|
||||
listener: L,
|
||||
) where
|
||||
|
@ -66,21 +67,19 @@ pub async fn commands_repl_with_listener<'a, Cmd, H, Fut, L, ListenerE, HandlerE
|
|||
ListenerE: Debug + Send + 'a,
|
||||
Result<(), HandlerE>: OnError<HandlerE>,
|
||||
HandlerE: Debug + Send,
|
||||
N: Into<String> + Send + 'static,
|
||||
{
|
||||
let handler = Arc::new(handler);
|
||||
|
||||
Dispatcher::new(bot)
|
||||
.messages_handler(move |rx: DispatcherHandlerRx<Message>| {
|
||||
rx.commands::<Cmd, &'static str>(bot_name).for_each_concurrent(
|
||||
None,
|
||||
move |(cx, cmd)| {
|
||||
let handler = Arc::clone(&handler);
|
||||
rx.commands::<Cmd, N>(bot_name).for_each_concurrent(None, move |(cx, cmd)| {
|
||||
let handler = Arc::clone(&handler);
|
||||
|
||||
async move {
|
||||
handler(cx, cmd).await.log_on_error().await;
|
||||
}
|
||||
},
|
||||
)
|
||||
async move {
|
||||
handler(cx, cmd).await.log_on_error().await;
|
||||
}
|
||||
})
|
||||
})
|
||||
.dispatch_with_listener(
|
||||
listener,
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
SendLocation, SendMediaGroup, SendMessage, SendPhoto, SendSticker, SendVenue, SendVideo,
|
||||
SendVideoNote, SendVoice,
|
||||
},
|
||||
types::{ChatId, ChatOrInlineMessage, InputFile, InputMedia, Message},
|
||||
types::{ChatId, InputFile, InputMedia, Message},
|
||||
Bot,
|
||||
};
|
||||
|
||||
|
@ -130,20 +130,11 @@ impl UpdateWithCx<Message> {
|
|||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.bot.edit_message_text(
|
||||
ChatOrInlineMessage::Chat {
|
||||
chat_id: self.update.chat.id.into(),
|
||||
message_id: self.update.id,
|
||||
},
|
||||
text,
|
||||
)
|
||||
self.bot.edit_message_text(self.update.chat.id, self.update.id, text)
|
||||
}
|
||||
|
||||
pub fn edit_message_caption(&self) -> EditMessageCaption {
|
||||
self.bot.edit_message_caption(ChatOrInlineMessage::Chat {
|
||||
chat_id: self.update.chat.id.into(),
|
||||
message_id: self.update.id,
|
||||
})
|
||||
self.bot.edit_message_caption(self.update.chat.id, self.update.id)
|
||||
}
|
||||
|
||||
pub fn delete_message(&self) -> DeleteMessage {
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
)]
|
||||
#![allow(clippy::match_bool)]
|
||||
#![forbid(unsafe_code)]
|
||||
#![cfg_attr(all(feature = "nightly", doctest), feature(external_doc))]
|
||||
|
||||
pub use bot::{Bot, BotBuilder};
|
||||
pub use dispatching::repls::{
|
||||
|
@ -61,3 +62,7 @@ pub mod types;
|
|||
pub mod utils;
|
||||
|
||||
extern crate teloxide_macros;
|
||||
|
||||
#[cfg(all(feature = "nightly", doctest))]
|
||||
#[doc(include = "../README.md")]
|
||||
enum ReadmeDocTests {}
|
||||
|
|
|
@ -9,7 +9,7 @@ pub use crate::{
|
|||
Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx,
|
||||
},
|
||||
error_handlers::{LoggingErrorHandler, OnError},
|
||||
requests::{Request, ResponseResult},
|
||||
requests::{respond, Request, ResponseResult},
|
||||
types::{Message, Update},
|
||||
Bot, RequestError,
|
||||
};
|
||||
|
|
83
src/requests/all/edit_inline_message_caption.rs
Normal file
83
src/requests/all/edit_inline_message_caption.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{InlineKeyboardMarkup, ParseMode, True},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to edit captions of messages sent via the bot.
|
||||
///
|
||||
/// On success, [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagecaption).
|
||||
///
|
||||
/// [`True`]: crate::types::True
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct EditInlineMessageCaption {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
inline_message_id: String,
|
||||
caption: Option<String>,
|
||||
parse_mode: Option<ParseMode>,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Request for EditInlineMessageCaption {
|
||||
type Output = True;
|
||||
|
||||
async fn send(&self) -> ResponseResult<True> {
|
||||
net::request_json(self.bot.client(), self.bot.token(), "editMessageCaption", &self).await
|
||||
}
|
||||
}
|
||||
|
||||
impl EditInlineMessageCaption {
|
||||
pub(crate) fn new<I>(bot: Bot, inline_message_id: I) -> Self
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
let inline_message_id = inline_message_id.into();
|
||||
Self { bot, inline_message_id, caption: None, parse_mode: None, reply_markup: None }
|
||||
}
|
||||
|
||||
/// Identifier of the inline message.
|
||||
pub fn inline_message_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.inline_message_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// New caption of the message.
|
||||
pub fn caption<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.caption = Some(val.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show
|
||||
/// [bold, italic, fixed-width text or inline URLs] in the media caption.
|
||||
///
|
||||
/// [Markdown]: crate::types::ParseMode::Markdown
|
||||
/// [HTML]: crate::types::ParseMode::HTML
|
||||
/// [bold, italic, fixed-width text or inline URLs]:
|
||||
/// crate::types::ParseMode
|
||||
pub fn parse_mode(mut self, val: ParseMode) -> Self {
|
||||
self.parse_mode = Some(val);
|
||||
self
|
||||
}
|
||||
|
||||
/// A JSON-serialized object for an [inline keyboard].
|
||||
///
|
||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
||||
pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self {
|
||||
self.reply_markup = Some(val);
|
||||
self
|
||||
}
|
||||
}
|
77
src/requests/all/edit_inline_message_live_location.rs
Normal file
77
src/requests/all/edit_inline_message_live_location.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{InlineKeyboardMarkup, True},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to edit live location messages sent via the bot.
|
||||
///
|
||||
/// A location can be edited until its live_period expires or editing is
|
||||
/// explicitly disabled by a call to stopMessageLiveLocation. On success,
|
||||
/// [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagelivelocation).
|
||||
///
|
||||
/// [`True`]: crate::types::True
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct EditInlineMessageLiveLocation {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
inline_message_id: String,
|
||||
latitude: f32,
|
||||
longitude: f32,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Request for EditInlineMessageLiveLocation {
|
||||
type Output = True;
|
||||
|
||||
async fn send(&self) -> ResponseResult<True> {
|
||||
net::request_json(self.bot.client(), self.bot.token(), "editMessageLiveLocation", &self)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl EditInlineMessageLiveLocation {
|
||||
pub(crate) fn new<I>(bot: Bot, inline_message_id: I, latitude: f32, longitude: f32) -> Self
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
let inline_message_id = inline_message_id.into();
|
||||
Self { bot, inline_message_id, latitude, longitude, reply_markup: None }
|
||||
}
|
||||
|
||||
/// Identifier of the inline message.
|
||||
pub fn inline_message_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.inline_message_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Latitude of new location.
|
||||
pub fn latitude(mut self, val: f32) -> Self {
|
||||
self.latitude = val;
|
||||
self
|
||||
}
|
||||
|
||||
/// Longitude of new location.
|
||||
pub fn longitude(mut self, val: f32) -> Self {
|
||||
self.longitude = val;
|
||||
self
|
||||
}
|
||||
|
||||
/// A JSON-serialized object for a new [inline keyboard].
|
||||
///
|
||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
||||
pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self {
|
||||
self.reply_markup = Some(val);
|
||||
self
|
||||
}
|
||||
}
|
78
src/requests/all/edit_inline_message_media.rs
Normal file
78
src/requests/all/edit_inline_message_media.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
use crate::{
|
||||
net,
|
||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||
types::{InlineKeyboardMarkup, InputMedia, True},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to edit animation, audio, document, photo, or video
|
||||
/// messages sent via the bot.
|
||||
///
|
||||
/// If a message is a part of a message album, then it can be edited only to a
|
||||
/// photo or a video. Otherwise, message type can be changed arbitrarily. When
|
||||
/// this method is used, new file can't be uploaded. Use previously
|
||||
/// uploaded file via its `file_id` or specify a URL. On success, [`True`] is
|
||||
/// returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagemedia).
|
||||
///
|
||||
/// [`True`]: crate::types::True
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EditInlineMessageMedia {
|
||||
bot: Bot,
|
||||
inline_message_id: String,
|
||||
media: InputMedia,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Request for EditInlineMessageMedia {
|
||||
type Output = True;
|
||||
|
||||
async fn send(&self) -> ResponseResult<True> {
|
||||
net::request_multipart(
|
||||
self.bot.client(),
|
||||
self.bot.token(),
|
||||
"editMessageMedia",
|
||||
FormBuilder::new()
|
||||
.add_text("media", &self.media)
|
||||
.add_text("reply_markup", &self.reply_markup)
|
||||
.add_text("inline_message_id", &self.inline_message_id)
|
||||
.build(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl EditInlineMessageMedia {
|
||||
pub(crate) fn new<I>(bot: Bot, inline_message_id: I, media: InputMedia) -> Self
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
let inline_message_id = inline_message_id.into();
|
||||
Self { bot, inline_message_id, media, reply_markup: None }
|
||||
}
|
||||
|
||||
/// Identifier of the inline message.
|
||||
pub fn inline_message_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.inline_message_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// A JSON-serialized object for a new media content of the message.
|
||||
pub fn media(mut self, val: InputMedia) -> Self {
|
||||
self.media = val;
|
||||
self
|
||||
}
|
||||
|
||||
/// A JSON-serialized object for a new [inline keyboard].
|
||||
///
|
||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
||||
pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self {
|
||||
self.reply_markup = Some(val);
|
||||
self
|
||||
}
|
||||
}
|
62
src/requests/all/edit_inline_message_reply_markup.rs
Normal file
62
src/requests/all/edit_inline_message_reply_markup.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{InlineKeyboardMarkup, True},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to edit only the reply markup of messages sent via the bot.
|
||||
///
|
||||
/// On success, [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagereplymarkup).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct EditInlineMessageReplyMarkup {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
inline_message_id: String,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Request for EditInlineMessageReplyMarkup {
|
||||
type Output = True;
|
||||
|
||||
async fn send(&self) -> ResponseResult<True> {
|
||||
net::request_json(self.bot.client(), self.bot.token(), "editMessageReplyMarkup", &self)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl EditInlineMessageReplyMarkup {
|
||||
pub(crate) fn new<I>(bot: Bot, inline_message_id: I) -> Self
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
let inline_message_id = inline_message_id.into();
|
||||
Self { bot, inline_message_id, reply_markup: None }
|
||||
}
|
||||
|
||||
/// Identifier of the inline message.
|
||||
pub fn inline_message_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.inline_message_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// A JSON-serialized object for an [inline keyboard].
|
||||
///
|
||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
||||
pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self {
|
||||
self.reply_markup = Some(val);
|
||||
self
|
||||
}
|
||||
}
|
98
src/requests/all/edit_inline_message_text.rs
Normal file
98
src/requests/all/edit_inline_message_text.rs
Normal file
|
@ -0,0 +1,98 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{InlineKeyboardMarkup, Message, ParseMode},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to edit text and game messages sent via the bot.
|
||||
///
|
||||
/// On success, [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagetext).
|
||||
///
|
||||
/// [`True`]: crate::types::True
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct EditInlineMessageText {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
inline_message_id: String,
|
||||
text: String,
|
||||
parse_mode: Option<ParseMode>,
|
||||
disable_web_page_preview: Option<bool>,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Request for EditInlineMessageText {
|
||||
type Output = Message;
|
||||
|
||||
async fn send(&self) -> ResponseResult<Message> {
|
||||
net::request_json(self.bot.client(), self.bot.token(), "editMessageText", &self).await
|
||||
}
|
||||
}
|
||||
|
||||
impl EditInlineMessageText {
|
||||
pub(crate) fn new<I, T>(bot: Bot, inline_message_id: I, text: T) -> Self
|
||||
where
|
||||
I: Into<String>,
|
||||
T: Into<String>,
|
||||
{
|
||||
let inline_message_id = inline_message_id.into();
|
||||
let text = text.into();
|
||||
Self {
|
||||
bot,
|
||||
inline_message_id,
|
||||
text,
|
||||
parse_mode: None,
|
||||
disable_web_page_preview: None,
|
||||
reply_markup: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Identifier of the inline message.
|
||||
pub fn inline_message_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.inline_message_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// New text of the message.
|
||||
pub fn text<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.text = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show [bold,
|
||||
/// italic, fixed-width text or inline URLs] in your bot's message.
|
||||
///
|
||||
/// [Markdown]: https://core.telegram.org/bots/api#markdown-style
|
||||
/// [HTML]: https://core.telegram.org/bots/api#html-style
|
||||
/// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options
|
||||
pub fn parse_mode(mut self, val: ParseMode) -> Self {
|
||||
self.parse_mode = Some(val);
|
||||
self
|
||||
}
|
||||
|
||||
/// Disables link previews for links in this message.
|
||||
pub fn disable_web_page_preview(mut self, val: bool) -> Self {
|
||||
self.disable_web_page_preview = Some(val);
|
||||
self
|
||||
}
|
||||
|
||||
/// A JSON-serialized object for an [inline keyboard].
|
||||
///
|
||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
||||
pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self {
|
||||
self.reply_markup = Some(val);
|
||||
self
|
||||
}
|
||||
}
|
|
@ -3,26 +3,24 @@ use serde::Serialize;
|
|||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message, ParseMode},
|
||||
types::{ChatId, InlineKeyboardMarkup, Message, ParseMode},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to edit captions of messages.
|
||||
/// Use this method to edit captions of messages sent by the bot.
|
||||
///
|
||||
/// On success, if edited message is sent by the bot, the edited [`Message`] is
|
||||
/// returned, otherwise [`True`] is returned.
|
||||
/// On success, the edited [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagecaption).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct EditMessageCaption {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
#[serde(flatten)]
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
chat_id: ChatId,
|
||||
message_id: i32,
|
||||
caption: Option<String>,
|
||||
parse_mode: Option<ParseMode>,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
|
@ -38,12 +36,27 @@ impl Request for EditMessageCaption {
|
|||
}
|
||||
|
||||
impl EditMessageCaption {
|
||||
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self {
|
||||
Self { bot, chat_or_inline_message, caption: None, parse_mode: None, reply_markup: None }
|
||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, message_id: i32) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
let chat_id = chat_id.into();
|
||||
Self { bot, chat_id, message_id, caption: None, parse_mode: None, reply_markup: None }
|
||||
}
|
||||
|
||||
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
||||
self.chat_or_inline_message = val;
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`)
|
||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Identifier of the message to edit
|
||||
pub fn message_id(mut self, val: i32) -> Self {
|
||||
self.message_id = val;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -3,28 +3,26 @@ use serde::Serialize;
|
|||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message},
|
||||
types::{ChatId, InlineKeyboardMarkup, Message},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to edit live location messages.
|
||||
///
|
||||
/// A location can be edited until its live_period expires or editing is
|
||||
/// explicitly disabled by a call to stopMessageLiveLocation. On success, if the
|
||||
/// edited message was sent by the bot, the edited [`Message`] is returned,
|
||||
/// otherwise [`True`] is returned.
|
||||
/// explicitly disabled by a call to stopMessageLiveLocation. On success, the
|
||||
/// edited [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagelivelocation).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct EditMessageLiveLocation {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
#[serde(flatten)]
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
chat_id: ChatId,
|
||||
message_id: i32,
|
||||
latitude: f32,
|
||||
longitude: f32,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
|
@ -41,17 +39,33 @@ impl Request for EditMessageLiveLocation {
|
|||
}
|
||||
|
||||
impl EditMessageLiveLocation {
|
||||
pub(crate) fn new(
|
||||
pub(crate) fn new<C>(
|
||||
bot: Bot,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
chat_id: C,
|
||||
message_id: i32,
|
||||
latitude: f32,
|
||||
longitude: f32,
|
||||
) -> Self {
|
||||
Self { bot, chat_or_inline_message, latitude, longitude, reply_markup: None }
|
||||
) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
let chat_id = chat_id.into();
|
||||
Self { bot, chat_id, message_id, latitude, longitude, reply_markup: None }
|
||||
}
|
||||
|
||||
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
||||
self.chat_or_inline_message = val;
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`)
|
||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Identifier of the message to edit
|
||||
pub fn message_id(mut self, val: i32) -> Self {
|
||||
self.message_id = val;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
net,
|
||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, InputMedia, Message},
|
||||
types::{ChatId, InlineKeyboardMarkup, InputMedia, Message},
|
||||
Bot,
|
||||
};
|
||||
|
||||
|
@ -9,20 +9,17 @@ use crate::{
|
|||
/// messages.
|
||||
///
|
||||
/// If a message is a part of a message album, then it can be edited only to a
|
||||
/// photo or a video. Otherwise, message type can be changed arbitrarily. When
|
||||
/// inline message is edited, new file can't be uploaded. Use previously
|
||||
/// uploaded file via its `file_id` or specify a URL. On success, if the edited
|
||||
/// message was sent by the bot, the edited [`Message`] is returned,
|
||||
/// otherwise [`True`] is returned.
|
||||
/// photo or a video. Otherwise, message type can be changed arbitrarily. On
|
||||
/// success, the edited [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagemedia).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EditMessageMedia {
|
||||
bot: Bot,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
chat_id: ChatId,
|
||||
message_id: i32,
|
||||
media: InputMedia,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
}
|
||||
|
@ -32,22 +29,13 @@ impl Request for EditMessageMedia {
|
|||
type Output = Message;
|
||||
|
||||
async fn send(&self) -> ResponseResult<Message> {
|
||||
let mut params = FormBuilder::new();
|
||||
|
||||
match &self.chat_or_inline_message {
|
||||
ChatOrInlineMessage::Chat { chat_id, message_id } => {
|
||||
params = params.add_text("chat_id", chat_id).add_text("message_id", message_id);
|
||||
}
|
||||
ChatOrInlineMessage::Inline { inline_message_id } => {
|
||||
params = params.add_text("inline_message_id", inline_message_id);
|
||||
}
|
||||
}
|
||||
|
||||
net::request_multipart(
|
||||
self.bot.client(),
|
||||
self.bot.token(),
|
||||
"editMessageMedia",
|
||||
params
|
||||
FormBuilder::new()
|
||||
.add_text("chat_id", &self.chat_id)
|
||||
.add_text("message_id", &self.message_id)
|
||||
.add_text("media", &self.media)
|
||||
.add_text("reply_markup", &self.reply_markup)
|
||||
.build(),
|
||||
|
@ -57,16 +45,27 @@ impl Request for EditMessageMedia {
|
|||
}
|
||||
|
||||
impl EditMessageMedia {
|
||||
pub(crate) fn new(
|
||||
bot: Bot,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
media: InputMedia,
|
||||
) -> Self {
|
||||
Self { bot, chat_or_inline_message, media, reply_markup: None }
|
||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, message_id: i32, media: InputMedia) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
let chat_id = chat_id.into();
|
||||
Self { bot, chat_id, message_id, media, reply_markup: None }
|
||||
}
|
||||
|
||||
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
||||
self.chat_or_inline_message = val;
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`)
|
||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Identifier of the message to edit
|
||||
pub fn message_id(mut self, val: i32) -> Self {
|
||||
self.message_id = val;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -3,26 +3,24 @@ use serde::Serialize;
|
|||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message},
|
||||
types::{ChatId, InlineKeyboardMarkup, Message},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to edit only the reply markup of messages.
|
||||
///
|
||||
/// On success, if edited message is sent by the bot, the edited [`Message`] is
|
||||
/// returned, otherwise [`True`] is returned.
|
||||
/// On success, the edited [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagereplymarkup).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct EditMessageReplyMarkup {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
#[serde(flatten)]
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
chat_id: ChatId,
|
||||
message_id: i32,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
}
|
||||
|
||||
|
@ -37,12 +35,27 @@ impl Request for EditMessageReplyMarkup {
|
|||
}
|
||||
|
||||
impl EditMessageReplyMarkup {
|
||||
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self {
|
||||
Self { bot, chat_or_inline_message, reply_markup: None }
|
||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, message_id: i32) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
let chat_id = chat_id.into();
|
||||
Self { bot, chat_id, message_id, reply_markup: None }
|
||||
}
|
||||
|
||||
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
||||
self.chat_or_inline_message = val;
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`)
|
||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Identifier of the message to edit
|
||||
pub fn message_id(mut self, val: i32) -> Self {
|
||||
self.message_id = val;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -3,26 +3,24 @@ use serde::Serialize;
|
|||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message, ParseMode},
|
||||
types::{ChatId, InlineKeyboardMarkup, Message, ParseMode},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to edit text and game messages.
|
||||
///
|
||||
/// On success, if edited message is sent by the bot, the edited [`Message`] is
|
||||
/// returned, otherwise [`True`] is returned.
|
||||
/// On success, the edited [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagetext).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct EditMessageText {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
#[serde(flatten)]
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
chat_id: ChatId,
|
||||
message_id: i32,
|
||||
text: String,
|
||||
parse_mode: Option<ParseMode>,
|
||||
disable_web_page_preview: Option<bool>,
|
||||
|
@ -39,22 +37,37 @@ impl Request for EditMessageText {
|
|||
}
|
||||
|
||||
impl EditMessageText {
|
||||
pub(crate) fn new<T>(bot: Bot, chat_or_inline_message: ChatOrInlineMessage, text: T) -> Self
|
||||
pub(crate) fn new<C, T>(bot: Bot, chat_id: C, message_id: i32, text: T) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
T: Into<String>,
|
||||
{
|
||||
let chat_id = chat_id.into();
|
||||
let text = text.into();
|
||||
Self {
|
||||
bot,
|
||||
chat_or_inline_message,
|
||||
text: text.into(),
|
||||
chat_id,
|
||||
message_id,
|
||||
text,
|
||||
parse_mode: None,
|
||||
disable_web_page_preview: None,
|
||||
reply_markup: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
||||
self.chat_or_inline_message = val;
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`)
|
||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Identifier of the message to edit
|
||||
pub fn message_id(mut self, val: i32) -> Self {
|
||||
self.message_id = val;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use serde::Serialize;
|
|||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatOrInlineMessage, GameHighScore},
|
||||
types::{GameHighScore, TargetMessage},
|
||||
Bot,
|
||||
};
|
||||
|
||||
|
@ -18,14 +18,13 @@ use crate::{
|
|||
/// the user and his neighbors are not among them. Please note that this
|
||||
/// behavior is subject to change.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#getgamehighscores).
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
/// [The official docs](https://core.telegram.org/bots/api#getgamehighscores)
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct GetGameHighScores {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
#[serde(flatten)]
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
target: TargetMessage,
|
||||
user_id: i32,
|
||||
}
|
||||
|
||||
|
@ -39,12 +38,20 @@ impl Request for GetGameHighScores {
|
|||
}
|
||||
|
||||
impl GetGameHighScores {
|
||||
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage, user_id: i32) -> Self {
|
||||
Self { bot, chat_or_inline_message, user_id }
|
||||
pub(crate) fn new<T>(bot: Bot, target: T, user_id: i32) -> Self
|
||||
where
|
||||
T: Into<TargetMessage>,
|
||||
{
|
||||
let target = target.into();
|
||||
Self { bot, target, user_id }
|
||||
}
|
||||
|
||||
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
||||
self.chat_or_inline_message = val;
|
||||
/// Target message, either chat id and message id or inline message id.
|
||||
pub fn target<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<TargetMessage>,
|
||||
{
|
||||
self.target = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,11 @@ mod delete_chat_sticker_set;
|
|||
mod delete_message;
|
||||
mod delete_sticker_from_set;
|
||||
mod delete_webhook;
|
||||
mod edit_inline_message_caption;
|
||||
mod edit_inline_message_live_location;
|
||||
mod edit_inline_message_media;
|
||||
mod edit_inline_message_reply_markup;
|
||||
mod edit_inline_message_text;
|
||||
mod edit_message_caption;
|
||||
mod edit_message_live_location;
|
||||
mod edit_message_media;
|
||||
|
@ -62,6 +67,7 @@ mod set_my_commands;
|
|||
mod set_sticker_position_in_set;
|
||||
mod set_sticker_set_thumb;
|
||||
mod set_webhook;
|
||||
mod stop_inline_message_live_location;
|
||||
mod stop_message_live_location;
|
||||
mod stop_poll;
|
||||
mod unban_chat_member;
|
||||
|
@ -79,6 +85,11 @@ pub use delete_chat_sticker_set::*;
|
|||
pub use delete_message::*;
|
||||
pub use delete_sticker_from_set::*;
|
||||
pub use delete_webhook::*;
|
||||
pub use edit_inline_message_caption::*;
|
||||
pub use edit_inline_message_live_location::*;
|
||||
pub use edit_inline_message_media::*;
|
||||
pub use edit_inline_message_reply_markup::*;
|
||||
pub use edit_inline_message_text::*;
|
||||
pub use edit_message_caption::*;
|
||||
pub use edit_message_live_location::*;
|
||||
pub use edit_message_media::*;
|
||||
|
@ -133,6 +144,7 @@ pub use set_sticker_position_in_set::*;
|
|||
pub use set_sticker_set_thumb::*;
|
||||
pub use set_webhook::*;
|
||||
pub use std::pin::Pin;
|
||||
pub use stop_inline_message_live_location::*;
|
||||
pub use stop_message_live_location::*;
|
||||
pub use stop_poll::*;
|
||||
pub use unban_chat_member::*;
|
||||
|
|
|
@ -3,7 +3,7 @@ use serde::Serialize;
|
|||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatOrInlineMessage, Message},
|
||||
types::{Message, TargetMessage},
|
||||
Bot,
|
||||
};
|
||||
|
||||
|
@ -24,7 +24,7 @@ pub struct SetGameScore {
|
|||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
#[serde(flatten)]
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
target: TargetMessage,
|
||||
user_id: i32,
|
||||
score: i32,
|
||||
force: Option<bool>,
|
||||
|
@ -41,24 +41,20 @@ impl Request for SetGameScore {
|
|||
}
|
||||
|
||||
impl SetGameScore {
|
||||
pub(crate) fn new(
|
||||
bot: Bot,
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
user_id: i32,
|
||||
score: i32,
|
||||
) -> Self {
|
||||
Self {
|
||||
bot,
|
||||
chat_or_inline_message,
|
||||
user_id,
|
||||
score,
|
||||
force: None,
|
||||
disable_edit_message: None,
|
||||
}
|
||||
pub(crate) fn new<T>(bot: Bot, target: T, user_id: i32, score: i32) -> Self
|
||||
where
|
||||
T: Into<TargetMessage>,
|
||||
{
|
||||
let target = target.into();
|
||||
Self { bot, target, user_id, score, force: None, disable_edit_message: None }
|
||||
}
|
||||
|
||||
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
||||
self.chat_or_inline_message = val;
|
||||
/// Target message, either chat id and message id or inline message id.
|
||||
pub fn target<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<TargetMessage>,
|
||||
{
|
||||
self.target = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
|
|
62
src/requests/all/stop_inline_message_live_location.rs
Normal file
62
src/requests/all/stop_inline_message_live_location.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{InlineKeyboardMarkup, Message},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to stop updating a live location message (sent via the bot)
|
||||
/// before `live_period` expires.
|
||||
///
|
||||
/// On success, [`True`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#stopmessagelivelocation).
|
||||
///
|
||||
/// [`True`]: crate::types::True
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct StopInlineMessageLiveLocation {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
inline_message_id: String,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Request for StopInlineMessageLiveLocation {
|
||||
type Output = Message;
|
||||
|
||||
async fn send(&self) -> ResponseResult<Message> {
|
||||
net::request_json(self.bot.client(), self.bot.token(), "stopMessageLiveLocation", &self)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl StopInlineMessageLiveLocation {
|
||||
pub(crate) fn new<I>(bot: Bot, inline_message_id: I) -> Self
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
let inline_message_id = inline_message_id.into();
|
||||
Self { bot, inline_message_id, reply_markup: None }
|
||||
}
|
||||
|
||||
/// Identifier of the inline message.
|
||||
pub fn inline_message_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.inline_message_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// A JSON-serialized object for a new [inline keyboard].
|
||||
///
|
||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
||||
pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self {
|
||||
self.reply_markup = Some(val);
|
||||
self
|
||||
}
|
||||
}
|
|
@ -3,27 +3,25 @@ use serde::Serialize;
|
|||
use crate::{
|
||||
net,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message},
|
||||
types::{ChatId, InlineKeyboardMarkup, Message},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// Use this method to stop updating a live location message before
|
||||
/// `live_period` expires.
|
||||
///
|
||||
/// On success, if the message was sent by the bot, the sent [`Message`] is
|
||||
/// returned, otherwise [`True`] is returned.
|
||||
/// On success, the sent [`Message`] is returned.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#stopmessagelivelocation).
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
/// [`True`]: crate::types::True
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct StopMessageLiveLocation {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
#[serde(flatten)]
|
||||
chat_or_inline_message: ChatOrInlineMessage,
|
||||
chat_id: ChatId,
|
||||
message_id: i32,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
}
|
||||
|
||||
|
@ -38,12 +36,27 @@ impl Request for StopMessageLiveLocation {
|
|||
}
|
||||
|
||||
impl StopMessageLiveLocation {
|
||||
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self {
|
||||
Self { bot, chat_or_inline_message, reply_markup: None }
|
||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, message_id: i32) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
let chat_id = chat_id.into();
|
||||
Self { bot, chat_id, message_id, reply_markup: None }
|
||||
}
|
||||
|
||||
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
||||
self.chat_or_inline_message = val;
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`)
|
||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = val.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Identifier of the message to edit
|
||||
pub fn message_id(mut self, val: i32) -> Self {
|
||||
self.message_id = val;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,11 @@ pub use all::*;
|
|||
/// A type that is returned after making a request to Telegram.
|
||||
pub type ResponseResult<T> = Result<T, crate::RequestError>;
|
||||
|
||||
/// A shortcut for `ResponseResult::Ok(val)`.
|
||||
pub fn respond<T>(val: T) -> ResponseResult<T> {
|
||||
ResponseResult::Ok(val)
|
||||
}
|
||||
|
||||
/// Designates an API request.
|
||||
#[async_trait::async_trait]
|
||||
pub trait Request {
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
use crate::types::ChatId;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A chat message or inline message.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[non_exhaustive]
|
||||
pub enum ChatOrInlineMessage {
|
||||
Chat { chat_id: ChatId, message_id: i32 },
|
||||
Inline { inline_message_id: i32 },
|
||||
}
|
|
@ -10,7 +10,6 @@ pub use chat::*;
|
|||
pub use chat_action::*;
|
||||
pub use chat_id::*;
|
||||
pub use chat_member::*;
|
||||
pub use chat_or_inline_message::*;
|
||||
pub use chat_permissions::*;
|
||||
pub use chat_photo::*;
|
||||
pub use chosen_inline_result::*;
|
||||
|
@ -83,6 +82,7 @@ pub use sticker::*;
|
|||
pub use sticker_set::*;
|
||||
pub use sticker_type::*;
|
||||
pub use successful_payment::*;
|
||||
pub use target_message::*;
|
||||
pub use unit_false::*;
|
||||
pub use unit_true::*;
|
||||
pub use update::*;
|
||||
|
@ -104,7 +104,6 @@ mod chat;
|
|||
mod chat_action;
|
||||
mod chat_id;
|
||||
mod chat_member;
|
||||
mod chat_or_inline_message;
|
||||
mod chat_permissions;
|
||||
mod chat_photo;
|
||||
mod chosen_inline_result;
|
||||
|
@ -150,6 +149,7 @@ mod sticker;
|
|||
mod sticker_set;
|
||||
mod sticker_type;
|
||||
mod successful_payment;
|
||||
mod target_message;
|
||||
mod unit_false;
|
||||
mod unit_true;
|
||||
mod update;
|
||||
|
|
17
src/types/target_message.rs
Normal file
17
src/types/target_message.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use crate::types::ChatId;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A message in chat or inline message.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum TargetMessage {
|
||||
Common { chat_id: ChatId, message_id: i32 },
|
||||
Inline { inline_message_id: String },
|
||||
}
|
||||
|
||||
impl From<String> for TargetMessage {
|
||||
fn from(inline_message_id: String) -> Self {
|
||||
Self::Inline { inline_message_id }
|
||||
}
|
||||
}
|
|
@ -18,6 +18,21 @@ fn parse_command_with_args() {
|
|||
assert_eq!(actual, expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_command_with_non_string_arg() {
|
||||
#[command(rename = "lowercase")]
|
||||
#[derive(BotCommand, Debug, PartialEq)]
|
||||
enum DefaultCommands {
|
||||
Start(i32),
|
||||
Help,
|
||||
}
|
||||
|
||||
let data = "/start -50";
|
||||
let expected = DefaultCommands::Start("-50".parse().unwrap());
|
||||
let actual = DefaultCommands::parse(data, "").unwrap();
|
||||
assert_eq!(actual, expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn attribute_prefix() {
|
||||
#[command(rename = "lowercase")]
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#![cfg(feature = "redis_storage")]
|
||||
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
future::Future,
|
||||
|
@ -8,7 +6,6 @@ use std::{
|
|||
use teloxide::dispatching::dialogue::{RedisStorage, Serializer, Storage};
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg(feature = "redis_storage")]
|
||||
async fn test_redis_json() {
|
||||
let storage = RedisStorage::open(
|
||||
"redis://127.0.0.1:7777",
|
||||
|
@ -19,7 +16,6 @@ async fn test_redis_json() {
|
|||
test_redis(storage).await;
|
||||
}
|
||||
|
||||
#[cfg(feature = "bincode_serializer")]
|
||||
#[tokio::test]
|
||||
async fn test_redis_bincode() {
|
||||
let storage = RedisStorage::open(
|
||||
|
@ -31,7 +27,6 @@ async fn test_redis_bincode() {
|
|||
test_redis(storage).await;
|
||||
}
|
||||
|
||||
#[cfg(feature = "cbor_serializer")]
|
||||
#[tokio::test]
|
||||
async fn test_redis_cbor() {
|
||||
let storage = RedisStorage::open(
|
||||
|
|
Loading…
Reference in a new issue