mirror of
https://github.com/teloxide/teloxide.git
synced 2025-03-24 23:57:38 +01:00
Integrate teloxide-core
This commit is contained in:
parent
f33428be03
commit
6102a02ed4
209 changed files with 326 additions and 23551 deletions
|
@ -7,10 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
## [unreleased]
|
## [unreleased]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- Integrate [teloxide-core].
|
||||||
- Allow arbitrary error types to be returned from (sub)transitions ([issue 242](https://github.com/teloxide/teloxide/issues/242)).
|
- 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(())`.
|
- The `respond` function, a shortcut for `ResponseResult::Ok(())`.
|
||||||
- The `sqlite-storage` feature -- enables SQLite support.
|
- The `sqlite-storage` feature -- enables SQLite support.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- `UpdateWithCx::answer_str`
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Hide `SubtransitionOutputType` from the docs.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Allow `bot_name` be `N`, where `N: Into<String> + ...` in `commands_repl` & `commands_repl_with_listener`.
|
- 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 methods' (namely `edit_message_live_location`, `stop_message_live_location`, `edit_message_text`,
|
||||||
|
|
|
@ -36,7 +36,7 @@ macros = ["teloxide-macros"]
|
||||||
nightly = [] # currently used for `README.md` tests and building docs for `docsrs` to add `This is supported on feature="..." only.`
|
nightly = [] # currently used for `README.md` tests and building docs for `docsrs` to add `This is supported on feature="..." only.`
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
teloxide-core = "0.1"
|
teloxide-core = { git = "https://github.com/teloxide/teloxide-core.git", rev = "b465da5f1650893cc033d995343858371505eaf1", features = ["full"] }
|
||||||
|
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
1733
src/bot/api.rs
1733
src/bot/api.rs
File diff suppressed because it is too large
Load diff
|
@ -1,67 +0,0 @@
|
||||||
use tokio::io::AsyncWrite;
|
|
||||||
|
|
||||||
#[cfg(feature = "unstable-stream")]
|
|
||||||
use ::{bytes::Bytes, tokio::stream::Stream};
|
|
||||||
|
|
||||||
#[cfg(feature = "unstable-stream")]
|
|
||||||
use crate::net::download_file_stream;
|
|
||||||
use crate::{bot::Bot, net::download_file, DownloadError};
|
|
||||||
|
|
||||||
impl Bot {
|
|
||||||
/// Download a file from Telegram into `destination`.
|
|
||||||
///
|
|
||||||
/// `path` can be obtained from [`Bot::get_file`].
|
|
||||||
///
|
|
||||||
/// To download as a stream of chunks, see [`Bot::download_file_stream`].
|
|
||||||
///
|
|
||||||
/// ## Examples
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// use teloxide::types::File as TgFile;
|
|
||||||
/// use tokio::fs::File;
|
|
||||||
/// # use teloxide::RequestError;
|
|
||||||
/// use teloxide::{requests::Request, Bot};
|
|
||||||
///
|
|
||||||
/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
/// let bot = Bot::new("TOKEN");
|
|
||||||
/// let mut file = File::create("/home/waffle/Pictures/test.png").await?;
|
|
||||||
///
|
|
||||||
/// let TgFile { file_path, .. } = bot.get_file("*file_id*").send().await?;
|
|
||||||
/// bot.download_file(&file_path, &mut file).await?;
|
|
||||||
/// # Ok(()) }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Bot::get_file`]: crate::Bot::get_file
|
|
||||||
/// [`Bot::download_file_stream`]: crate::Bot::download_file_stream
|
|
||||||
pub async fn download_file<D>(
|
|
||||||
&self,
|
|
||||||
path: &str,
|
|
||||||
destination: &mut D,
|
|
||||||
) -> Result<(), DownloadError>
|
|
||||||
where
|
|
||||||
D: AsyncWrite + Unpin,
|
|
||||||
{
|
|
||||||
download_file(&self.client, &self.token, path, destination).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Download a file from Telegram.
|
|
||||||
///
|
|
||||||
/// `path` can be obtained from the [`Bot::get_file`].
|
|
||||||
///
|
|
||||||
/// To download into [`AsyncWrite`] (e.g. [`tokio::fs::File`]), see
|
|
||||||
/// [`Bot::download_file`].
|
|
||||||
///
|
|
||||||
/// [`Bot::get_file`]: crate::bot::Bot::get_file
|
|
||||||
/// [`AsyncWrite`]: tokio::io::AsyncWrite
|
|
||||||
/// [`tokio::fs::File`]: tokio::fs::File
|
|
||||||
/// [`Bot::download_file`]: crate::Bot::download_file
|
|
||||||
#[cfg(feature = "unstable-stream")]
|
|
||||||
// FIXME(waffle): use `docsrs` here when issue with combine is resolved <https://github.com/teloxide/teloxide/pull/305#issuecomment-716172103>
|
|
||||||
#[cfg_attr(all(teloxide_docsrs, feature = "nightly"), doc(cfg(feature = "unstable-stream")))]
|
|
||||||
pub async fn download_file_stream(
|
|
||||||
&self,
|
|
||||||
path: &str,
|
|
||||||
) -> Result<impl Stream<Item = Result<Bytes, reqwest::Error>>, reqwest::Error> {
|
|
||||||
download_file_stream(&self.client, &self.token, path).await
|
|
||||||
}
|
|
||||||
}
|
|
252
src/bot/mod.rs
252
src/bot/mod.rs
|
@ -1,252 +0,0 @@
|
||||||
use crate::types::ParseMode;
|
|
||||||
use reqwest::{
|
|
||||||
header::{HeaderMap, CONNECTION},
|
|
||||||
Client, ClientBuilder,
|
|
||||||
};
|
|
||||||
use std::{sync::Arc, time::Duration};
|
|
||||||
|
|
||||||
mod api;
|
|
||||||
mod download;
|
|
||||||
|
|
||||||
pub(crate) const TELOXIDE_TOKEN: &str = "TELOXIDE_TOKEN";
|
|
||||||
pub(crate) const TELOXIDE_PROXY: &str = "TELOXIDE_PROXY";
|
|
||||||
|
|
||||||
/// A requests sender.
|
|
||||||
///
|
|
||||||
/// No need to put it into [`Arc`], because it's already in.
|
|
||||||
///
|
|
||||||
/// [`Arc`]: std::sync::Arc
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Bot {
|
|
||||||
token: Arc<str>,
|
|
||||||
client: Client,
|
|
||||||
parse_mode: Option<ParseMode>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bot {
|
|
||||||
/// Creates new [`BotBuilder`] see it's [docs] for more
|
|
||||||
///
|
|
||||||
/// [docs]: BotBuilder
|
|
||||||
#[must_use]
|
|
||||||
pub fn builder() -> BotBuilder {
|
|
||||||
BotBuilder::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new `Bot` with the `TELOXIDE_TOKEN` & `TELOXIDE_PROXY`
|
|
||||||
/// environmental variables (a bot's token & a proxy) and the default
|
|
||||||
/// [`reqwest::Client`].
|
|
||||||
///
|
|
||||||
/// This function passes the value of `TELOXIDE_PROXY` into
|
|
||||||
/// [`reqwest::Proxy::all`], if it exists, otherwise returns the default
|
|
||||||
/// client.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// - 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
|
|
||||||
/// [`reqwest::Proxy::all`]: https://docs.rs/reqwest/latest/reqwest/struct.Proxy.html#method.all
|
|
||||||
#[must_use]
|
|
||||||
pub fn from_env() -> Self {
|
|
||||||
BotBuilder::new().build()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new `Bot` with the `TELOXIDE_TOKEN` environmental variable (a
|
|
||||||
/// bot's token) and your [`reqwest::Client`].
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// If cannot get the `TELOXIDE_TOKEN` environmental variable.
|
|
||||||
///
|
|
||||||
/// # Caution
|
|
||||||
/// Your custom client might not be configured correctly to be able to work
|
|
||||||
/// in long time durations, see [issue 223].
|
|
||||||
///
|
|
||||||
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
|
||||||
/// [issue 223]: https://github.com/teloxide/teloxide/issues/223
|
|
||||||
#[deprecated = "Deprecated in favour of BotBuilder because the later provides more options \
|
|
||||||
(notably default parse_mode)"]
|
|
||||||
pub fn from_env_with_client(client: Client) -> Self {
|
|
||||||
#[allow(deprecated)]
|
|
||||||
Self::with_client(&get_env(TELOXIDE_TOKEN), client)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new `Bot` with the specified token and the default
|
|
||||||
/// [`reqwest::Client`].
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// If it cannot create [`reqwest::Client`].
|
|
||||||
///
|
|
||||||
/// [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html
|
|
||||||
#[deprecated = "Deprecated in favour of BotBuilder because the later provides more options \
|
|
||||||
(notably default parse_mode)"]
|
|
||||||
pub fn new<S>(token: S) -> Self
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
{
|
|
||||||
#[allow(deprecated)]
|
|
||||||
Self::with_client(token, build_sound_bot())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new `Bot` with the specified token and your
|
|
||||||
/// [`reqwest::Client`].
|
|
||||||
///
|
|
||||||
/// # Caution
|
|
||||||
/// Your custom client might not be configured correctly to be able to work
|
|
||||||
/// in long time durations, see [issue 223].
|
|
||||||
///
|
|
||||||
/// [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html
|
|
||||||
/// [issue 223]: https://github.com/teloxide/teloxide/issues/223
|
|
||||||
#[deprecated = "Deprecated in favour of BotBuilder because the later provides more options \
|
|
||||||
(notably default parse_mode)"]
|
|
||||||
pub fn with_client<S>(token: S, client: Client) -> Self
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
token: Into::<Arc<str>>::into(Into::<String>::into(token)),
|
|
||||||
client,
|
|
||||||
parse_mode: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a builder with safe settings.
|
|
||||||
///
|
|
||||||
/// By "safe settings" I mean that a client will be able to work in long time
|
|
||||||
/// durations, see the [issue 223].
|
|
||||||
///
|
|
||||||
/// [issue 223]: https://github.com/teloxide/teloxide/issues/223
|
|
||||||
pub(crate) fn sound_bot() -> ClientBuilder {
|
|
||||||
let mut headers = HeaderMap::new();
|
|
||||||
headers.insert(CONNECTION, "keep-alive".parse().unwrap());
|
|
||||||
|
|
||||||
let connect_timeout = Duration::from_secs(5);
|
|
||||||
let timeout = 10;
|
|
||||||
|
|
||||||
ClientBuilder::new()
|
|
||||||
.connect_timeout(connect_timeout)
|
|
||||||
.timeout(Duration::from_secs(connect_timeout.as_secs() + timeout + 2))
|
|
||||||
.tcp_nodelay(true)
|
|
||||||
.default_headers(headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn build_sound_bot() -> Client {
|
|
||||||
sound_bot().build().expect("creating reqwest::Client")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_env(env: &'static str) -> String {
|
|
||||||
std::env::var(env).unwrap_or_else(|_| panic!("Cannot get the {} env variable", env))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bot {
|
|
||||||
// TODO: const fn
|
|
||||||
pub fn token(&self) -> &str {
|
|
||||||
&self.token
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: const fn
|
|
||||||
pub fn client(&self) -> &Client {
|
|
||||||
&self.client
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A builder of [`Bot`], supporting some extra settings.
|
|
||||||
///
|
|
||||||
/// [`Bot`]: crate::Bot
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct BotBuilder {
|
|
||||||
token: Option<String>,
|
|
||||||
client: Option<Client>,
|
|
||||||
parse_mode: Option<ParseMode>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BotBuilder {
|
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Specifies a custom HTTPS client. Otherwise, the default will be used.
|
|
||||||
///
|
|
||||||
/// # Caution
|
|
||||||
/// - Your custom client might not be configured correctly to be able to
|
|
||||||
/// work
|
|
||||||
/// in long time durations, see [issue 223].
|
|
||||||
///
|
|
||||||
/// - If this method is used, the `TELOXIDE_PROXY` environmental variable
|
|
||||||
/// won't be extracted in [`BotBuilder::build`].
|
|
||||||
///
|
|
||||||
/// [issue 223]: https://github.com/teloxide/teloxide/issues/223
|
|
||||||
/// [`BotBuilder::build`]: crate::BotBuilder::build
|
|
||||||
#[must_use]
|
|
||||||
pub fn client(mut self, client: Client) -> Self {
|
|
||||||
self.client = Some(client);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Specified a custom token.
|
|
||||||
///
|
|
||||||
/// Otherwise, a token will be extracted from the `TELOXIDE_TOKEN`
|
|
||||||
/// environmental variable.
|
|
||||||
#[must_use]
|
|
||||||
pub fn token<S>(mut self, token: S) -> Self
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
{
|
|
||||||
self.token = Some(token.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Specifies [`ParseMode`], which will be used during all calls to:
|
|
||||||
///
|
|
||||||
/// - [`send_message`]
|
|
||||||
/// - [`send_photo`]
|
|
||||||
/// - [`send_video`]
|
|
||||||
/// - [`send_audio`]
|
|
||||||
/// - [`send_document`]
|
|
||||||
/// - [`send_animation`]
|
|
||||||
/// - [`send_voice`]
|
|
||||||
/// - [`send_poll`]
|
|
||||||
/// - [`edit_message_text`]
|
|
||||||
/// - [`edit_message_caption`]
|
|
||||||
///
|
|
||||||
/// [`send_message`]: crate::Bot::send_message
|
|
||||||
/// [`send_photo`]: crate::Bot::send_photo
|
|
||||||
/// [`send_video`]: crate::Bot::send_video
|
|
||||||
/// [`send_audio`]: crate::Bot::send_audio
|
|
||||||
/// [`send_document`]: crate::Bot::send_document
|
|
||||||
/// [`send_animation`]: crate::Bot::send_animation
|
|
||||||
/// [`send_voice`]: crate::Bot::send_voice
|
|
||||||
/// [`send_poll`]: crate::Bot::send_poll
|
|
||||||
/// [`edit_message_text`]: crate::Bot::edit_message_text
|
|
||||||
/// [`edit_message_caption`]: crate::Bot::edit_message_caption
|
|
||||||
#[must_use]
|
|
||||||
pub fn parse_mode(mut self, parse_mode: ParseMode) -> Self {
|
|
||||||
self.parse_mode = Some(parse_mode);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds [`Bot`].
|
|
||||||
///
|
|
||||||
/// 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. If
|
|
||||||
/// `TELOXIDE_PROXY` is unspecified, it'll use no proxy.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// - 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
|
|
||||||
///
|
|
||||||
/// [`Bot`]: crate::Bot
|
|
||||||
/// [`reqwest::Proxy::all`]: https://docs.rs/reqwest/latest/reqwest/struct.Proxy.html#method.all
|
|
||||||
#[must_use]
|
|
||||||
pub fn build(self) -> Bot {
|
|
||||||
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: self.parse_mode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,6 +11,7 @@ use tokio::sync::mpsc;
|
||||||
|
|
||||||
use lockfree::map::Map;
|
use lockfree::map::Map;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use teloxide_core::requests::Requester;
|
||||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||||
|
|
||||||
/// A dispatcher of dialogues.
|
/// A dispatcher of dialogues.
|
||||||
|
@ -23,7 +24,7 @@ use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||||
///
|
///
|
||||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
/// [`DispatcherHandler`]: crate::dispatching::DispatcherHandler
|
/// [`DispatcherHandler`]: crate::dispatching::DispatcherHandler
|
||||||
pub struct DialogueDispatcher<D, S, H, Upd> {
|
pub struct DialogueDispatcher<R, D, S, H, Upd> {
|
||||||
storage: Arc<S>,
|
storage: Arc<S>,
|
||||||
handler: Arc<H>,
|
handler: Arc<H>,
|
||||||
_phantom: PhantomData<Mutex<D>>,
|
_phantom: PhantomData<Mutex<D>>,
|
||||||
|
@ -34,12 +35,12 @@ pub struct DialogueDispatcher<D, S, H, Upd> {
|
||||||
/// A value is the TX part of an unbounded asynchronous MPSC channel. A
|
/// A value is the TX part of an unbounded asynchronous MPSC channel. A
|
||||||
/// handler that executes updates from the same chat ID sequentially
|
/// handler that executes updates from the same chat ID sequentially
|
||||||
/// handles the RX part.
|
/// handles the RX part.
|
||||||
senders: Arc<Map<i64, mpsc::UnboundedSender<UpdateWithCx<Upd>>>>,
|
senders: Arc<Map<i64, mpsc::UnboundedSender<UpdateWithCx<R, Upd>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D, H, Upd> DialogueDispatcher<D, InMemStorage<D>, H, Upd>
|
impl<R, D, H, Upd> DialogueDispatcher<R, D, InMemStorage<D>, H, Upd>
|
||||||
where
|
where
|
||||||
H: DialogueDispatcherHandler<Upd, D, Infallible> + Send + Sync + 'static,
|
H: DialogueDispatcherHandler<R, Upd, D, Infallible> + Send + Sync + 'static,
|
||||||
Upd: GetChatId + Send + 'static,
|
Upd: GetChatId + Send + 'static,
|
||||||
D: Default + Send + 'static,
|
D: Default + Send + 'static,
|
||||||
{
|
{
|
||||||
|
@ -58,9 +59,9 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D, S, H, Upd> DialogueDispatcher<D, S, H, Upd>
|
impl<R, D, S, H, Upd> DialogueDispatcher<R, D, S, H, Upd>
|
||||||
where
|
where
|
||||||
H: DialogueDispatcherHandler<Upd, D, S::Error> + Send + Sync + 'static,
|
H: DialogueDispatcherHandler<R, Upd, D, S::Error> + Send + Sync + 'static,
|
||||||
Upd: GetChatId + Send + 'static,
|
Upd: GetChatId + Send + 'static,
|
||||||
D: Default + Send + 'static,
|
D: Default + Send + 'static,
|
||||||
S: Storage<D> + Send + Sync + 'static,
|
S: Storage<D> + Send + Sync + 'static,
|
||||||
|
@ -78,14 +79,17 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn new_tx(&self) -> mpsc::UnboundedSender<UpdateWithCx<Upd>> {
|
fn new_tx(&self) -> mpsc::UnboundedSender<UpdateWithCx<R, Upd>>
|
||||||
|
where
|
||||||
|
R: Requester + Send + 'static,
|
||||||
|
{
|
||||||
let (tx, rx) = mpsc::unbounded_channel();
|
let (tx, rx) = mpsc::unbounded_channel();
|
||||||
|
|
||||||
let storage = Arc::clone(&self.storage);
|
let storage = Arc::clone(&self.storage);
|
||||||
let handler = Arc::clone(&self.handler);
|
let handler = Arc::clone(&self.handler);
|
||||||
let senders = Arc::clone(&self.senders);
|
let senders = Arc::clone(&self.senders);
|
||||||
|
|
||||||
tokio::spawn(UnboundedReceiverStream::new(rx).for_each(move |cx: UpdateWithCx<Upd>| {
|
tokio::spawn(UnboundedReceiverStream::new(rx).for_each(move |cx: UpdateWithCx<R, Upd>| {
|
||||||
let storage = Arc::clone(&storage);
|
let storage = Arc::clone(&storage);
|
||||||
let handler = Arc::clone(&handler);
|
let handler = Arc::clone(&handler);
|
||||||
let senders = Arc::clone(&senders);
|
let senders = Arc::clone(&senders);
|
||||||
|
@ -124,17 +128,21 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D, S, H, Upd> DispatcherHandler<Upd> for DialogueDispatcher<D, S, H, Upd>
|
impl<R, D, S, H, Upd> DispatcherHandler<R, Upd> for DialogueDispatcher<R, D, S, H, Upd>
|
||||||
where
|
where
|
||||||
H: DialogueDispatcherHandler<Upd, D, S::Error> + Send + Sync + 'static,
|
H: DialogueDispatcherHandler<R, Upd, D, S::Error> + Send + Sync + 'static,
|
||||||
Upd: GetChatId + Send + 'static,
|
Upd: GetChatId + Send + 'static,
|
||||||
D: Default + Send + 'static,
|
D: Default + Send + 'static,
|
||||||
S: Storage<D> + Send + Sync + 'static,
|
S: Storage<D> + Send + Sync + 'static,
|
||||||
S::Error: Send + 'static,
|
S::Error: Send + 'static,
|
||||||
|
R: Requester + Send,
|
||||||
{
|
{
|
||||||
fn handle(self, updates: mpsc::UnboundedReceiver<UpdateWithCx<Upd>>) -> BoxFuture<'static, ()>
|
fn handle(
|
||||||
|
self,
|
||||||
|
updates: mpsc::UnboundedReceiver<UpdateWithCx<R, Upd>>,
|
||||||
|
) -> BoxFuture<'static, ()>
|
||||||
where
|
where
|
||||||
UpdateWithCx<Upd>: 'static,
|
UpdateWithCx<R, Upd>: 'static,
|
||||||
{
|
{
|
||||||
let this = Arc::new(self);
|
let this = Arc::new(self);
|
||||||
|
|
||||||
|
|
|
@ -8,24 +8,32 @@ use std::{future::Future, sync::Arc};
|
||||||
/// overview](crate::dispatching::dialogue).
|
/// overview](crate::dispatching::dialogue).
|
||||||
///
|
///
|
||||||
/// [`DialogueDispatcher`]: crate::dispatching::dialogue::DialogueDispatcher
|
/// [`DialogueDispatcher`]: crate::dispatching::dialogue::DialogueDispatcher
|
||||||
pub trait DialogueDispatcherHandler<Upd, D, E> {
|
pub trait DialogueDispatcherHandler<R, Upd, D, E> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn handle(
|
fn handle(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
cx: DialogueWithCx<Upd, D, E>,
|
cx: DialogueWithCx<R, Upd, D, E>,
|
||||||
) -> BoxFuture<'static, DialogueStage<D>>
|
) -> BoxFuture<'static, DialogueStage<D>>
|
||||||
where
|
where
|
||||||
DialogueWithCx<Upd, D, E>: Send + 'static;
|
DialogueWithCx<R, Upd, D, E>: Send + 'static,
|
||||||
|
R: Send,
|
||||||
|
Upd: Send,
|
||||||
|
D: Send,
|
||||||
|
E: Send;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Upd, D, E, F, Fut> DialogueDispatcherHandler<Upd, D, E> for F
|
impl<R, Upd, D, E, F, Fut> DialogueDispatcherHandler<R, Upd, D, E> for F
|
||||||
where
|
where
|
||||||
F: Fn(DialogueWithCx<Upd, D, E>) -> Fut + Send + Sync + 'static,
|
F: Fn(DialogueWithCx<R, Upd, D, E>) -> Fut + Send + Sync + 'static,
|
||||||
Fut: Future<Output = DialogueStage<D>> + Send + 'static,
|
Fut: Future<Output = DialogueStage<D>> + Send + 'static,
|
||||||
{
|
{
|
||||||
fn handle(self: Arc<Self>, cx: DialogueWithCx<Upd, D, E>) -> BoxFuture<'static, Fut::Output>
|
fn handle(self: Arc<Self>, cx: DialogueWithCx<R, Upd, D, E>) -> BoxFuture<'static, Fut::Output>
|
||||||
where
|
where
|
||||||
DialogueWithCx<Upd, D, E>: Send + 'static,
|
DialogueWithCx<R, Upd, D, E>: Send + 'static,
|
||||||
|
R: Send,
|
||||||
|
Upd: Send,
|
||||||
|
D: Send,
|
||||||
|
E: Send,
|
||||||
{
|
{
|
||||||
Box::pin(async move { self(cx).await })
|
Box::pin(async move { self(cx).await })
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::dispatching::{dialogue::GetChatId, UpdateWithCx};
|
use crate::dispatching::{dialogue::GetChatId, UpdateWithCx};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use teloxide_core::requests::Requester;
|
||||||
|
|
||||||
/// A context of a [`DialogueDispatcher`]'s message handler.
|
/// A context of a [`DialogueDispatcher`]'s message handler.
|
||||||
///
|
///
|
||||||
|
@ -8,21 +9,22 @@ use std::fmt::Debug;
|
||||||
///
|
///
|
||||||
/// [`DialogueDispatcher`]: crate::dispatching::dialogue::DialogueDispatcher
|
/// [`DialogueDispatcher`]: crate::dispatching::dialogue::DialogueDispatcher
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DialogueWithCx<Upd, D, E> {
|
pub struct DialogueWithCx<R, Upd, D, E> {
|
||||||
pub cx: UpdateWithCx<Upd>,
|
pub cx: UpdateWithCx<R, Upd>,
|
||||||
pub dialogue: Result<D, E>,
|
pub dialogue: Result<D, E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Upd, D, E> DialogueWithCx<Upd, D, E> {
|
impl<Upd, R, D, E> DialogueWithCx<R, Upd, D, E> {
|
||||||
/// Creates a new instance with the provided fields.
|
/// Creates a new instance with the provided fields.
|
||||||
pub fn new(cx: UpdateWithCx<Upd>, dialogue: D) -> Self {
|
pub fn new(cx: UpdateWithCx<R, Upd>, dialogue: D) -> Self {
|
||||||
Self { cx, dialogue: Ok(dialogue) }
|
Self { cx, dialogue: Ok(dialogue) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Upd, D, E> GetChatId for DialogueWithCx<Upd, D, E>
|
impl<Upd, R, D, E> GetChatId for DialogueWithCx<R, Upd, D, E>
|
||||||
where
|
where
|
||||||
Upd: GetChatId,
|
Upd: GetChatId,
|
||||||
|
R: Requester,
|
||||||
{
|
{
|
||||||
fn chat_id(&self) -> i64 {
|
fn chat_id(&self) -> i64 {
|
||||||
self.cx.update.chat_id()
|
self.cx.update.chat_id()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::types::Message;
|
use teloxide_core::types::Message;
|
||||||
|
|
||||||
/// Something that has a chat ID.
|
/// Something that has a chat ID.
|
||||||
pub trait GetChatId {
|
pub trait GetChatId {
|
||||||
|
|
|
@ -91,14 +91,13 @@ where
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let dialogue =
|
let dialogue =
|
||||||
self.serializer.serialize(&dialogue).map_err(RedisStorageError::SerdeError)?;
|
self.serializer.serialize(&dialogue).map_err(RedisStorageError::SerdeError)?;
|
||||||
Ok(self
|
self.conn
|
||||||
.conn
|
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.getset::<_, Vec<u8>, Option<Vec<u8>>>(chat_id, dialogue)
|
.getset::<_, Vec<u8>, Option<Vec<u8>>>(chat_id, dialogue)
|
||||||
.await?
|
.await?
|
||||||
.map(|d| self.serializer.deserialize(&d).map_err(RedisStorageError::SerdeError))
|
.map(|d| self.serializer.deserialize(&d).map_err(RedisStorageError::SerdeError))
|
||||||
.transpose()?)
|
.transpose()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(sqlx::FromRow)]
|
#[derive(sqlx::FromRow)]
|
||||||
struct DialogueDBRow {
|
struct DialogueDbRow {
|
||||||
dialogue: Vec<u8>,
|
dialogue: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ async fn get_dialogue(
|
||||||
chat_id: i64,
|
chat_id: i64,
|
||||||
) -> Result<Option<Box<Vec<u8>>>, sqlx::Error> {
|
) -> Result<Option<Box<Vec<u8>>>, sqlx::Error> {
|
||||||
Ok(
|
Ok(
|
||||||
match sqlx::query_as::<_, DialogueDBRow>(
|
match sqlx::query_as::<_, DialogueDbRow>(
|
||||||
"SELECT dialogue FROM teloxide_dialogues WHERE chat_id = ?",
|
"SELECT dialogue FROM teloxide_dialogues WHERE chat_id = ?",
|
||||||
)
|
)
|
||||||
.bind(chat_id)
|
.bind(chat_id)
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
use crate::{
|
use crate::dispatching::{dialogue::DialogueStage, UpdateWithCx};
|
||||||
dispatching::{dialogue::DialogueStage, UpdateWithCx},
|
|
||||||
types::Message,
|
|
||||||
};
|
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
|
use teloxide_core::types::Message;
|
||||||
|
|
||||||
/// Represents a transition function of a dialogue FSM.
|
/// Represents a transition function of a dialogue FSM.
|
||||||
pub trait Transition: Sized {
|
pub trait Transition: Sized {
|
||||||
type Aux;
|
type Aux;
|
||||||
type Error;
|
type Error;
|
||||||
|
type Requester;
|
||||||
|
|
||||||
/// Turns itself into another state, depending on the input message.
|
/// Turns itself into another state, depending on the input message.
|
||||||
///
|
///
|
||||||
/// `aux` will be passed to each subtransition function.
|
/// `aux` will be passed to each subtransition function.
|
||||||
fn react(
|
fn react(
|
||||||
self,
|
self,
|
||||||
cx: TransitionIn,
|
cx: TransitionIn<Self::Requester>,
|
||||||
aux: Self::Aux,
|
aux: Self::Aux,
|
||||||
) -> BoxFuture<'static, TransitionOut<Self, Self::Error>>;
|
) -> BoxFuture<'static, TransitionOut<Self, Self::Error>>;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +28,7 @@ where
|
||||||
type Aux;
|
type Aux;
|
||||||
type Dialogue;
|
type Dialogue;
|
||||||
type Error;
|
type Error;
|
||||||
|
type Requester;
|
||||||
|
|
||||||
/// Turns itself into another state, depending on the input message.
|
/// Turns itself into another state, depending on the input message.
|
||||||
///
|
///
|
||||||
|
@ -36,7 +36,7 @@ where
|
||||||
/// message's text.
|
/// message's text.
|
||||||
fn react(
|
fn react(
|
||||||
self,
|
self,
|
||||||
cx: TransitionIn,
|
cx: TransitionIn<Self::Requester>,
|
||||||
aux: Self::Aux,
|
aux: Self::Aux,
|
||||||
) -> BoxFuture<'static, TransitionOut<Self::Dialogue, Self::Error>>;
|
) -> BoxFuture<'static, TransitionOut<Self::Dialogue, Self::Error>>;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ where
|
||||||
/// A type returned from a FSM subtransition function.
|
/// A type returned from a FSM subtransition function.
|
||||||
///
|
///
|
||||||
/// Now it is used only inside `#[teloxide(subtransition)]` for type inference.
|
/// Now it is used only inside `#[teloxide(subtransition)]` for type inference.
|
||||||
|
#[doc(hidden)]
|
||||||
pub trait SubtransitionOutputType {
|
pub trait SubtransitionOutputType {
|
||||||
type Output;
|
type Output;
|
||||||
type Error;
|
type Error;
|
||||||
|
@ -55,7 +56,7 @@ impl<D, E> SubtransitionOutputType for TransitionOut<D, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An input passed into a FSM (sub)transition function.
|
/// An input passed into a FSM (sub)transition function.
|
||||||
pub type TransitionIn = UpdateWithCx<Message>;
|
pub type TransitionIn<R> = UpdateWithCx<R, Message>;
|
||||||
|
|
||||||
/// A type returned from a FSM (sub)transition function.
|
/// A type returned from a FSM (sub)transition function.
|
||||||
pub type TransitionOut<D, E = crate::RequestError> = Result<DialogueStage<D>, E>;
|
pub type TransitionOut<D, E = crate::RequestError> = Result<DialogueStage<D>, E>;
|
||||||
|
|
|
@ -3,34 +3,37 @@ use crate::{
|
||||||
update_listeners, update_listeners::UpdateListener, DispatcherHandler, UpdateWithCx,
|
update_listeners, update_listeners::UpdateListener, DispatcherHandler, UpdateWithCx,
|
||||||
},
|
},
|
||||||
error_handlers::{ErrorHandler, LoggingErrorHandler},
|
error_handlers::{ErrorHandler, LoggingErrorHandler},
|
||||||
|
};
|
||||||
|
use futures::StreamExt;
|
||||||
|
use std::{fmt::Debug, sync::Arc};
|
||||||
|
use teloxide_core::{
|
||||||
|
requests::Requester,
|
||||||
types::{
|
types::{
|
||||||
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll, PollAnswer,
|
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll, PollAnswer,
|
||||||
PreCheckoutQuery, ShippingQuery, UpdateKind,
|
PreCheckoutQuery, ShippingQuery, UpdateKind,
|
||||||
},
|
},
|
||||||
Bot,
|
|
||||||
};
|
};
|
||||||
use futures::StreamExt;
|
|
||||||
use std::{fmt::Debug, sync::Arc};
|
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
type Tx<Upd> = Option<mpsc::UnboundedSender<UpdateWithCx<Upd>>>;
|
type Tx<Upd, R> = Option<mpsc::UnboundedSender<UpdateWithCx<Upd, R>>>;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros {
|
mod macros {
|
||||||
/// Pushes an update to a queue.
|
/// Pushes an update to a queue.
|
||||||
macro_rules! send {
|
macro_rules! send {
|
||||||
($bot:expr, $tx:expr, $update:expr, $variant:expr) => {
|
($requester:expr, $tx:expr, $update:expr, $variant:expr) => {
|
||||||
send($bot, $tx, $update, stringify!($variant));
|
send($requester, $tx, $update, stringify!($variant));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send<'a, Upd>(bot: &'a Bot, tx: &'a Tx<Upd>, update: Upd, variant: &'static str)
|
fn send<'a, R, Upd>(requester: &'a R, tx: &'a Tx<R, Upd>, update: Upd, variant: &'static str)
|
||||||
where
|
where
|
||||||
Upd: Debug,
|
Upd: Debug,
|
||||||
|
R: Requester + Clone,
|
||||||
{
|
{
|
||||||
if let Some(tx) = tx {
|
if let Some(tx) = tx {
|
||||||
if let Err(error) = tx.send(UpdateWithCx { bot: bot.clone(), update }) {
|
if let Err(error) = tx.send(UpdateWithCx { requester: requester.clone(), update }) {
|
||||||
log::error!(
|
log::error!(
|
||||||
"The RX part of the {} channel is closed, but an update is received.\nError:{}\n",
|
"The RX part of the {} channel is closed, but an update is received.\nError:{}\n",
|
||||||
variant,
|
variant,
|
||||||
|
@ -44,28 +47,31 @@ where
|
||||||
///
|
///
|
||||||
/// See the [module-level documentation](crate::dispatching) for the design
|
/// See the [module-level documentation](crate::dispatching) for the design
|
||||||
/// overview.
|
/// overview.
|
||||||
pub struct Dispatcher {
|
pub struct Dispatcher<R> {
|
||||||
bot: Bot,
|
requester: R,
|
||||||
|
|
||||||
messages_queue: Tx<Message>,
|
messages_queue: Tx<R, Message>,
|
||||||
edited_messages_queue: Tx<Message>,
|
edited_messages_queue: Tx<R, Message>,
|
||||||
channel_posts_queue: Tx<Message>,
|
channel_posts_queue: Tx<R, Message>,
|
||||||
edited_channel_posts_queue: Tx<Message>,
|
edited_channel_posts_queue: Tx<R, Message>,
|
||||||
inline_queries_queue: Tx<InlineQuery>,
|
inline_queries_queue: Tx<R, InlineQuery>,
|
||||||
chosen_inline_results_queue: Tx<ChosenInlineResult>,
|
chosen_inline_results_queue: Tx<R, ChosenInlineResult>,
|
||||||
callback_queries_queue: Tx<CallbackQuery>,
|
callback_queries_queue: Tx<R, CallbackQuery>,
|
||||||
shipping_queries_queue: Tx<ShippingQuery>,
|
shipping_queries_queue: Tx<R, ShippingQuery>,
|
||||||
pre_checkout_queries_queue: Tx<PreCheckoutQuery>,
|
pre_checkout_queries_queue: Tx<R, PreCheckoutQuery>,
|
||||||
polls_queue: Tx<Poll>,
|
polls_queue: Tx<R, Poll>,
|
||||||
poll_answers_queue: Tx<PollAnswer>,
|
poll_answers_queue: Tx<R, PollAnswer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dispatcher {
|
impl<R> Dispatcher<R>
|
||||||
/// Constructs a new dispatcher with the specified `bot`.
|
where
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
/// Constructs a new dispatcher with the specified `requester`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(bot: Bot) -> Self {
|
pub fn new(requester: R) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bot,
|
requester,
|
||||||
messages_queue: None,
|
messages_queue: None,
|
||||||
edited_messages_queue: None,
|
edited_messages_queue: None,
|
||||||
channel_posts_queue: None,
|
channel_posts_queue: None,
|
||||||
|
@ -81,10 +87,12 @@ impl Dispatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn new_tx<H, Upd>(&self, h: H) -> Tx<Upd>
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
|
fn new_tx<H, Upd>(&self, h: H) -> Tx<R, Upd>
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<Upd> + Send + 'static,
|
H: DispatcherHandler<R, Upd> + Send + 'static,
|
||||||
Upd: Send + 'static,
|
Upd: Send + 'static,
|
||||||
|
R: Send + 'static,
|
||||||
{
|
{
|
||||||
let (tx, rx) = mpsc::unbounded_channel();
|
let (tx, rx) = mpsc::unbounded_channel();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
@ -97,7 +105,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn messages_handler<H>(mut self, h: H) -> Self
|
pub fn messages_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<Message> + 'static + Send,
|
H: DispatcherHandler<R, Message> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.messages_queue = self.new_tx(h);
|
self.messages_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -106,7 +114,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn edited_messages_handler<H>(mut self, h: H) -> Self
|
pub fn edited_messages_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<Message> + 'static + Send,
|
H: DispatcherHandler<R, Message> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.edited_messages_queue = self.new_tx(h);
|
self.edited_messages_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -115,7 +123,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn channel_posts_handler<H>(mut self, h: H) -> Self
|
pub fn channel_posts_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<Message> + 'static + Send,
|
H: DispatcherHandler<R, Message> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.channel_posts_queue = self.new_tx(h);
|
self.channel_posts_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -124,7 +132,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn edited_channel_posts_handler<H>(mut self, h: H) -> Self
|
pub fn edited_channel_posts_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<Message> + 'static + Send,
|
H: DispatcherHandler<R, Message> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.edited_channel_posts_queue = self.new_tx(h);
|
self.edited_channel_posts_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -133,7 +141,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn inline_queries_handler<H>(mut self, h: H) -> Self
|
pub fn inline_queries_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<InlineQuery> + 'static + Send,
|
H: DispatcherHandler<R, InlineQuery> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.inline_queries_queue = self.new_tx(h);
|
self.inline_queries_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -142,7 +150,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn chosen_inline_results_handler<H>(mut self, h: H) -> Self
|
pub fn chosen_inline_results_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<ChosenInlineResult> + 'static + Send,
|
H: DispatcherHandler<R, ChosenInlineResult> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.chosen_inline_results_queue = self.new_tx(h);
|
self.chosen_inline_results_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -151,7 +159,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn callback_queries_handler<H>(mut self, h: H) -> Self
|
pub fn callback_queries_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<CallbackQuery> + 'static + Send,
|
H: DispatcherHandler<R, CallbackQuery> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.callback_queries_queue = self.new_tx(h);
|
self.callback_queries_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -160,7 +168,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn shipping_queries_handler<H>(mut self, h: H) -> Self
|
pub fn shipping_queries_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<ShippingQuery> + 'static + Send,
|
H: DispatcherHandler<R, ShippingQuery> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.shipping_queries_queue = self.new_tx(h);
|
self.shipping_queries_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -169,7 +177,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn pre_checkout_queries_handler<H>(mut self, h: H) -> Self
|
pub fn pre_checkout_queries_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<PreCheckoutQuery> + 'static + Send,
|
H: DispatcherHandler<R, PreCheckoutQuery> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.pre_checkout_queries_queue = self.new_tx(h);
|
self.pre_checkout_queries_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -178,7 +186,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn polls_handler<H>(mut self, h: H) -> Self
|
pub fn polls_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<Poll> + 'static + Send,
|
H: DispatcherHandler<R, Poll> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.polls_queue = self.new_tx(h);
|
self.polls_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -187,7 +195,7 @@ impl Dispatcher {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn poll_answers_handler<H>(mut self, h: H) -> Self
|
pub fn poll_answers_handler<H>(mut self, h: H) -> Self
|
||||||
where
|
where
|
||||||
H: DispatcherHandler<PollAnswer> + 'static + Send,
|
H: DispatcherHandler<R, PollAnswer> + 'static + Send,
|
||||||
{
|
{
|
||||||
self.poll_answers_queue = self.new_tx(h);
|
self.poll_answers_queue = self.new_tx(h);
|
||||||
self
|
self
|
||||||
|
@ -197,9 +205,13 @@ impl Dispatcher {
|
||||||
///
|
///
|
||||||
/// The default parameters are a long polling update listener and log all
|
/// The default parameters are a long polling update listener and log all
|
||||||
/// errors produced by this listener).
|
/// errors produced by this listener).
|
||||||
pub async fn dispatch(&self) {
|
pub async fn dispatch(&self)
|
||||||
|
where
|
||||||
|
R: Requester + Clone,
|
||||||
|
<R as Requester>::GetUpdatesFaultTolerant: Send,
|
||||||
|
{
|
||||||
self.dispatch_with_listener(
|
self.dispatch_with_listener(
|
||||||
update_listeners::polling_default(self.bot.clone()),
|
update_listeners::polling_default(self.requester.clone()),
|
||||||
LoggingErrorHandler::with_custom_text("An error from the update listener"),
|
LoggingErrorHandler::with_custom_text("An error from the update listener"),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
@ -215,6 +227,7 @@ impl Dispatcher {
|
||||||
UListener: UpdateListener<ListenerE> + 'a,
|
UListener: UpdateListener<ListenerE> + 'a,
|
||||||
Eh: ErrorHandler<ListenerE> + 'a,
|
Eh: ErrorHandler<ListenerE> + 'a,
|
||||||
ListenerE: Debug,
|
ListenerE: Debug,
|
||||||
|
R: Requester + Clone,
|
||||||
{
|
{
|
||||||
let update_listener = Box::pin(update_listener);
|
let update_listener = Box::pin(update_listener);
|
||||||
|
|
||||||
|
@ -235,11 +248,16 @@ impl Dispatcher {
|
||||||
|
|
||||||
match update.kind {
|
match update.kind {
|
||||||
UpdateKind::Message(message) => {
|
UpdateKind::Message(message) => {
|
||||||
send!(&self.bot, &self.messages_queue, message, UpdateKind::Message);
|
send!(
|
||||||
|
&self.requester,
|
||||||
|
&self.messages_queue,
|
||||||
|
message,
|
||||||
|
UpdateKind::Message
|
||||||
|
);
|
||||||
}
|
}
|
||||||
UpdateKind::EditedMessage(message) => {
|
UpdateKind::EditedMessage(message) => {
|
||||||
send!(
|
send!(
|
||||||
&self.bot,
|
&self.requester,
|
||||||
&self.edited_messages_queue,
|
&self.edited_messages_queue,
|
||||||
message,
|
message,
|
||||||
UpdateKind::EditedMessage
|
UpdateKind::EditedMessage
|
||||||
|
@ -247,7 +265,7 @@ impl Dispatcher {
|
||||||
}
|
}
|
||||||
UpdateKind::ChannelPost(post) => {
|
UpdateKind::ChannelPost(post) => {
|
||||||
send!(
|
send!(
|
||||||
&self.bot,
|
&self.requester,
|
||||||
&self.channel_posts_queue,
|
&self.channel_posts_queue,
|
||||||
post,
|
post,
|
||||||
UpdateKind::ChannelPost
|
UpdateKind::ChannelPost
|
||||||
|
@ -255,7 +273,7 @@ impl Dispatcher {
|
||||||
}
|
}
|
||||||
UpdateKind::EditedChannelPost(post) => {
|
UpdateKind::EditedChannelPost(post) => {
|
||||||
send!(
|
send!(
|
||||||
&self.bot,
|
&self.requester,
|
||||||
&self.edited_channel_posts_queue,
|
&self.edited_channel_posts_queue,
|
||||||
post,
|
post,
|
||||||
UpdateKind::EditedChannelPost
|
UpdateKind::EditedChannelPost
|
||||||
|
@ -263,7 +281,7 @@ impl Dispatcher {
|
||||||
}
|
}
|
||||||
UpdateKind::InlineQuery(query) => {
|
UpdateKind::InlineQuery(query) => {
|
||||||
send!(
|
send!(
|
||||||
&self.bot,
|
&self.requester,
|
||||||
&self.inline_queries_queue,
|
&self.inline_queries_queue,
|
||||||
query,
|
query,
|
||||||
UpdateKind::InlineQuery
|
UpdateKind::InlineQuery
|
||||||
|
@ -271,7 +289,7 @@ impl Dispatcher {
|
||||||
}
|
}
|
||||||
UpdateKind::ChosenInlineResult(result) => {
|
UpdateKind::ChosenInlineResult(result) => {
|
||||||
send!(
|
send!(
|
||||||
&self.bot,
|
&self.requester,
|
||||||
&self.chosen_inline_results_queue,
|
&self.chosen_inline_results_queue,
|
||||||
result,
|
result,
|
||||||
UpdateKind::ChosenInlineResult
|
UpdateKind::ChosenInlineResult
|
||||||
|
@ -279,7 +297,7 @@ impl Dispatcher {
|
||||||
}
|
}
|
||||||
UpdateKind::CallbackQuery(query) => {
|
UpdateKind::CallbackQuery(query) => {
|
||||||
send!(
|
send!(
|
||||||
&self.bot,
|
&self.requester,
|
||||||
&self.callback_queries_queue,
|
&self.callback_queries_queue,
|
||||||
query,
|
query,
|
||||||
UpdateKind::CallbackQuer
|
UpdateKind::CallbackQuer
|
||||||
|
@ -287,7 +305,7 @@ impl Dispatcher {
|
||||||
}
|
}
|
||||||
UpdateKind::ShippingQuery(query) => {
|
UpdateKind::ShippingQuery(query) => {
|
||||||
send!(
|
send!(
|
||||||
&self.bot,
|
&self.requester,
|
||||||
&self.shipping_queries_queue,
|
&self.shipping_queries_queue,
|
||||||
query,
|
query,
|
||||||
UpdateKind::ShippingQuery
|
UpdateKind::ShippingQuery
|
||||||
|
@ -295,18 +313,18 @@ impl Dispatcher {
|
||||||
}
|
}
|
||||||
UpdateKind::PreCheckoutQuery(query) => {
|
UpdateKind::PreCheckoutQuery(query) => {
|
||||||
send!(
|
send!(
|
||||||
&self.bot,
|
&self.requester,
|
||||||
&self.pre_checkout_queries_queue,
|
&self.pre_checkout_queries_queue,
|
||||||
query,
|
query,
|
||||||
UpdateKind::PreCheckoutQuery
|
UpdateKind::PreCheckoutQuery
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
UpdateKind::Poll(poll) => {
|
UpdateKind::Poll(poll) => {
|
||||||
send!(&self.bot, &self.polls_queue, poll, UpdateKind::Poll);
|
send!(&self.requester, &self.polls_queue, poll, UpdateKind::Poll);
|
||||||
}
|
}
|
||||||
UpdateKind::PollAnswer(answer) => {
|
UpdateKind::PollAnswer(answer) => {
|
||||||
send!(
|
send!(
|
||||||
&self.bot,
|
&self.requester,
|
||||||
&self.poll_answers_queue,
|
&self.poll_answers_queue,
|
||||||
answer,
|
answer,
|
||||||
UpdateKind::PollAnswer
|
UpdateKind::PollAnswer
|
||||||
|
|
|
@ -9,21 +9,21 @@ use futures::future::BoxFuture;
|
||||||
/// overview.
|
/// overview.
|
||||||
///
|
///
|
||||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
pub trait DispatcherHandler<Upd> {
|
pub trait DispatcherHandler<R, Upd> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn handle(self, updates: DispatcherHandlerRx<Upd>) -> BoxFuture<'static, ()>
|
fn handle(self, updates: DispatcherHandlerRx<R, Upd>) -> BoxFuture<'static, ()>
|
||||||
where
|
where
|
||||||
UpdateWithCx<Upd>: Send + 'static;
|
UpdateWithCx<R, Upd>: Send + 'static;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Upd, F, Fut> DispatcherHandler<Upd> for F
|
impl<R, Upd, F, Fut> DispatcherHandler<R, Upd> for F
|
||||||
where
|
where
|
||||||
F: FnOnce(DispatcherHandlerRx<Upd>) -> Fut + Send + 'static,
|
F: FnOnce(DispatcherHandlerRx<R, Upd>) -> Fut + Send + 'static,
|
||||||
Fut: Future<Output = ()> + Send + 'static,
|
Fut: Future<Output = ()> + Send + 'static,
|
||||||
{
|
{
|
||||||
fn handle(self, updates: DispatcherHandlerRx<Upd>) -> BoxFuture<'static, ()>
|
fn handle(self, updates: DispatcherHandlerRx<R, Upd>) -> BoxFuture<'static, ()>
|
||||||
where
|
where
|
||||||
UpdateWithCx<Upd>: Send + 'static,
|
UpdateWithCx<R, Upd>: Send + 'static,
|
||||||
{
|
{
|
||||||
Box::pin(async move { self(updates).await })
|
Box::pin(async move { self(updates).await })
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{prelude::UpdateWithCx, types::Message, utils::command::BotCommand};
|
use crate::{dispatching::UpdateWithCx, utils::command::BotCommand};
|
||||||
use futures::{stream::BoxStream, Stream, StreamExt};
|
use futures::{stream::BoxStream, Stream, StreamExt};
|
||||||
|
use teloxide_core::types::Message;
|
||||||
|
|
||||||
/// An extension trait to be used with [`DispatcherHandlerRx`].
|
/// An extension trait to be used with [`DispatcherHandlerRx`].
|
||||||
///
|
///
|
||||||
|
@ -7,37 +8,41 @@ use futures::{stream::BoxStream, Stream, StreamExt};
|
||||||
/// overview.
|
/// overview.
|
||||||
///
|
///
|
||||||
/// [`DispatcherHandlerRx`]: crate::dispatching::DispatcherHandlerRx
|
/// [`DispatcherHandlerRx`]: crate::dispatching::DispatcherHandlerRx
|
||||||
pub trait DispatcherHandlerRxExt {
|
pub trait DispatcherHandlerRxExt<R> {
|
||||||
/// Extracts only text messages from this stream of arbitrary messages.
|
/// Extracts only text messages from this stream of arbitrary messages.
|
||||||
fn text_messages(self) -> BoxStream<'static, (UpdateWithCx<Message>, String)>
|
fn text_messages(self) -> BoxStream<'static, (UpdateWithCx<R, Message>, String)>
|
||||||
where
|
where
|
||||||
Self: Stream<Item = UpdateWithCx<Message>>;
|
Self: Stream<Item = UpdateWithCx<R, Message>>,
|
||||||
|
R: Send + 'static;
|
||||||
|
|
||||||
/// Extracts only commands with their arguments from this stream of
|
/// Extracts only commands with their arguments from this stream of
|
||||||
/// arbitrary messages.
|
/// arbitrary messages.
|
||||||
fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<Message>, C)>
|
fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<R, Message>, C)>
|
||||||
where
|
where
|
||||||
Self: Stream<Item = UpdateWithCx<Message>>,
|
Self: Stream<Item = UpdateWithCx<R, Message>>,
|
||||||
C: BotCommand,
|
C: BotCommand,
|
||||||
N: Into<String> + Send;
|
N: Into<String> + Send,
|
||||||
|
R: Send + 'static;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DispatcherHandlerRxExt for T
|
impl<R, T> DispatcherHandlerRxExt<R> for T
|
||||||
where
|
where
|
||||||
T: Send + 'static,
|
T: Send + 'static,
|
||||||
{
|
{
|
||||||
fn text_messages(self) -> BoxStream<'static, (UpdateWithCx<Message>, String)>
|
fn text_messages(self) -> BoxStream<'static, (UpdateWithCx<R, Message>, String)>
|
||||||
where
|
where
|
||||||
Self: Stream<Item = UpdateWithCx<Message>>,
|
Self: Stream<Item = UpdateWithCx<R, Message>>,
|
||||||
|
R: Send + 'static,
|
||||||
{
|
{
|
||||||
self.filter_map(|cx| async move { cx.update.text_owned().map(|text| (cx, text)) }).boxed()
|
self.filter_map(|cx| async move { cx.update.text_owned().map(|text| (cx, text)) }).boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<Message>, C)>
|
fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<R, Message>, C)>
|
||||||
where
|
where
|
||||||
Self: Stream<Item = UpdateWithCx<Message>>,
|
Self: Stream<Item = UpdateWithCx<R, Message>>,
|
||||||
C: BotCommand,
|
C: BotCommand,
|
||||||
N: Into<String> + Send,
|
N: Into<String> + Send,
|
||||||
|
R: Send + 'static,
|
||||||
{
|
{
|
||||||
let bot_name = bot_name.into();
|
let bot_name = bot_name.into();
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,9 @@ pub use dispatcher::Dispatcher;
|
||||||
pub use dispatcher_handler::DispatcherHandler;
|
pub use dispatcher_handler::DispatcherHandler;
|
||||||
pub use dispatcher_handler_rx_ext::DispatcherHandlerRxExt;
|
pub use dispatcher_handler_rx_ext::DispatcherHandlerRxExt;
|
||||||
use tokio::sync::mpsc::UnboundedReceiver;
|
use tokio::sync::mpsc::UnboundedReceiver;
|
||||||
pub use update_with_cx::UpdateWithCx;
|
pub use update_with_cx::{UpdateWithCx, UpdateWithCxRequesterType};
|
||||||
|
|
||||||
/// A type of a stream, consumed by [`Dispatcher`]'s handlers.
|
/// A type of a stream, consumed by [`Dispatcher`]'s handlers.
|
||||||
///
|
///
|
||||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
pub type DispatcherHandlerRx<Upd> = UnboundedReceiver<UpdateWithCx<Upd>>;
|
pub type DispatcherHandlerRx<R, Upd> = UnboundedReceiver<UpdateWithCx<R, Upd>>;
|
||||||
|
|
|
@ -4,12 +4,11 @@ use crate::{
|
||||||
DispatcherHandlerRxExt, UpdateWithCx,
|
DispatcherHandlerRxExt, UpdateWithCx,
|
||||||
},
|
},
|
||||||
error_handlers::{LoggingErrorHandler, OnError},
|
error_handlers::{LoggingErrorHandler, OnError},
|
||||||
types::Message,
|
|
||||||
utils::command::BotCommand,
|
utils::command::BotCommand,
|
||||||
Bot,
|
|
||||||
};
|
};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use std::{fmt::Debug, future::Future, sync::Arc};
|
use std::{fmt::Debug, future::Future, sync::Arc};
|
||||||
|
use teloxide_core::{requests::Requester, types::Message};
|
||||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||||
|
|
||||||
/// A [REPL] for commands.
|
/// A [REPL] for commands.
|
||||||
|
@ -23,22 +22,24 @@ use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||||
///
|
///
|
||||||
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
|
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
|
||||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
pub async fn commands_repl<Cmd, H, Fut, HandlerE, N>(bot: Bot, bot_name: N, handler: H)
|
pub async fn commands_repl<R, Cmd, H, Fut, HandlerE, N>(requester: R, bot_name: N, handler: H)
|
||||||
where
|
where
|
||||||
Cmd: BotCommand + Send + 'static,
|
Cmd: BotCommand + Send + 'static,
|
||||||
H: Fn(UpdateWithCx<Message>, Cmd) -> Fut + Send + Sync + 'static,
|
H: Fn(UpdateWithCx<R, Message>, Cmd) -> Fut + Send + Sync + 'static,
|
||||||
Fut: Future<Output = Result<(), HandlerE>> + Send + 'static,
|
Fut: Future<Output = Result<(), HandlerE>> + Send + 'static,
|
||||||
Result<(), HandlerE>: OnError<HandlerE>,
|
Result<(), HandlerE>: OnError<HandlerE>,
|
||||||
HandlerE: Debug + Send,
|
HandlerE: Debug + Send,
|
||||||
N: Into<String> + Send + 'static,
|
N: Into<String> + Send + 'static,
|
||||||
|
R: Requester + Send + Clone + 'static,
|
||||||
|
<R as Requester>::GetUpdatesFaultTolerant: Send,
|
||||||
{
|
{
|
||||||
let cloned_bot = bot.clone();
|
let cloned_requester = requester.clone();
|
||||||
|
|
||||||
commands_repl_with_listener(
|
commands_repl_with_listener(
|
||||||
bot,
|
requester,
|
||||||
bot_name,
|
bot_name,
|
||||||
handler,
|
handler,
|
||||||
update_listeners::polling_default(cloned_bot),
|
update_listeners::polling_default(cloned_requester),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
@ -55,25 +56,26 @@ where
|
||||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
/// [`commands_repl`]: crate::dispatching::repls::commands_repl()
|
/// [`commands_repl`]: crate::dispatching::repls::commands_repl()
|
||||||
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
|
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
|
||||||
pub async fn commands_repl_with_listener<'a, Cmd, H, Fut, L, ListenerE, HandlerE, N>(
|
pub async fn commands_repl_with_listener<'a, R, Cmd, H, Fut, L, ListenerE, HandlerE, N>(
|
||||||
bot: Bot,
|
requester: R,
|
||||||
bot_name: N,
|
bot_name: N,
|
||||||
handler: H,
|
handler: H,
|
||||||
listener: L,
|
listener: L,
|
||||||
) where
|
) where
|
||||||
Cmd: BotCommand + Send + 'static,
|
Cmd: BotCommand + Send + 'static,
|
||||||
H: Fn(UpdateWithCx<Message>, Cmd) -> Fut + Send + Sync + 'static,
|
H: Fn(UpdateWithCx<R, Message>, Cmd) -> Fut + Send + Sync + 'static,
|
||||||
Fut: Future<Output = Result<(), HandlerE>> + Send + 'static,
|
Fut: Future<Output = Result<(), HandlerE>> + Send + 'static,
|
||||||
L: UpdateListener<ListenerE> + Send + 'a,
|
L: UpdateListener<ListenerE> + Send + 'a,
|
||||||
ListenerE: Debug + Send + 'a,
|
ListenerE: Debug + Send + 'a,
|
||||||
Result<(), HandlerE>: OnError<HandlerE>,
|
Result<(), HandlerE>: OnError<HandlerE>,
|
||||||
HandlerE: Debug + Send,
|
HandlerE: Debug + Send,
|
||||||
N: Into<String> + Send + 'static,
|
N: Into<String> + Send + 'static,
|
||||||
|
R: Requester + Clone + Send + 'static,
|
||||||
{
|
{
|
||||||
let handler = Arc::new(handler);
|
let handler = Arc::new(handler);
|
||||||
|
|
||||||
Dispatcher::new(bot)
|
Dispatcher::<R>::new(requester)
|
||||||
.messages_handler(move |rx: DispatcherHandlerRx<Message>| {
|
.messages_handler(move |rx: DispatcherHandlerRx<R, Message>| {
|
||||||
UnboundedReceiverStream::new(rx).commands::<Cmd, N>(bot_name).for_each_concurrent(
|
UnboundedReceiverStream::new(rx).commands::<Cmd, N>(bot_name).for_each_concurrent(
|
||||||
None,
|
None,
|
||||||
move |(cx, cmd)| {
|
move |(cx, cmd)| {
|
||||||
|
|
|
@ -6,10 +6,9 @@ use crate::{
|
||||||
Dispatcher, UpdateWithCx,
|
Dispatcher, UpdateWithCx,
|
||||||
},
|
},
|
||||||
error_handlers::LoggingErrorHandler,
|
error_handlers::LoggingErrorHandler,
|
||||||
types::Message,
|
|
||||||
Bot,
|
|
||||||
};
|
};
|
||||||
use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc};
|
use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc};
|
||||||
|
use teloxide_core::{requests::Requester, types::Message};
|
||||||
|
|
||||||
/// A [REPL] for dialogues.
|
/// A [REPL] for dialogues.
|
||||||
///
|
///
|
||||||
|
@ -24,15 +23,22 @@ use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc};
|
||||||
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
|
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
|
||||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
|
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
|
||||||
pub async fn dialogues_repl<'a, H, D, Fut>(bot: Bot, handler: H)
|
pub async fn dialogues_repl<'a, R, H, D, Fut>(requester: R, handler: H)
|
||||||
where
|
where
|
||||||
H: Fn(UpdateWithCx<Message>, D) -> Fut + Send + Sync + 'static,
|
H: Fn(UpdateWithCx<R, Message>, D) -> Fut + Send + Sync + 'static,
|
||||||
D: Default + Send + 'static,
|
D: Default + Send + 'static,
|
||||||
Fut: Future<Output = DialogueStage<D>> + Send + 'static,
|
Fut: Future<Output = DialogueStage<D>> + Send + 'static,
|
||||||
|
R: Requester + Send + Clone + 'static,
|
||||||
|
<R as Requester>::GetUpdatesFaultTolerant: Send,
|
||||||
{
|
{
|
||||||
let cloned_bot = bot.clone();
|
let cloned_requester = requester.clone();
|
||||||
|
|
||||||
dialogues_repl_with_listener(bot, handler, update_listeners::polling_default(cloned_bot)).await;
|
dialogues_repl_with_listener(
|
||||||
|
requester,
|
||||||
|
handler,
|
||||||
|
update_listeners::polling_default(cloned_requester),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like [`dialogues_repl`], but with a custom [`UpdateListener`].
|
/// Like [`dialogues_repl`], but with a custom [`UpdateListener`].
|
||||||
|
@ -49,22 +55,23 @@ where
|
||||||
/// [`dialogues_repl`]: crate::dispatching::repls::dialogues_repl()
|
/// [`dialogues_repl`]: crate::dispatching::repls::dialogues_repl()
|
||||||
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
|
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
|
||||||
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
|
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
|
||||||
pub async fn dialogues_repl_with_listener<'a, H, D, Fut, L, ListenerE>(
|
pub async fn dialogues_repl_with_listener<'a, R, H, D, Fut, L, ListenerE>(
|
||||||
bot: Bot,
|
requester: R,
|
||||||
handler: H,
|
handler: H,
|
||||||
listener: L,
|
listener: L,
|
||||||
) where
|
) where
|
||||||
H: Fn(UpdateWithCx<Message>, D) -> Fut + Send + Sync + 'static,
|
H: Fn(UpdateWithCx<R, Message>, D) -> Fut + Send + Sync + 'static,
|
||||||
D: Default + Send + 'static,
|
D: Default + Send + 'static,
|
||||||
Fut: Future<Output = DialogueStage<D>> + Send + 'static,
|
Fut: Future<Output = DialogueStage<D>> + Send + 'static,
|
||||||
L: UpdateListener<ListenerE> + Send + 'a,
|
L: UpdateListener<ListenerE> + Send + 'a,
|
||||||
ListenerE: Debug + Send + 'a,
|
ListenerE: Debug + Send + 'a,
|
||||||
|
R: Requester + Send + Clone + 'static,
|
||||||
{
|
{
|
||||||
let handler = Arc::new(handler);
|
let handler = Arc::new(handler);
|
||||||
|
|
||||||
Dispatcher::new(bot)
|
Dispatcher::new(requester)
|
||||||
.messages_handler(DialogueDispatcher::new(
|
.messages_handler(DialogueDispatcher::new(
|
||||||
move |DialogueWithCx { cx, dialogue }: DialogueWithCx<Message, D, Infallible>| {
|
move |DialogueWithCx { cx, dialogue }: DialogueWithCx<R, Message, D, Infallible>| {
|
||||||
let handler = Arc::clone(&handler);
|
let handler = Arc::clone(&handler);
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
|
|
|
@ -4,11 +4,10 @@ use crate::{
|
||||||
UpdateWithCx,
|
UpdateWithCx,
|
||||||
},
|
},
|
||||||
error_handlers::{LoggingErrorHandler, OnError},
|
error_handlers::{LoggingErrorHandler, OnError},
|
||||||
types::Message,
|
|
||||||
Bot,
|
|
||||||
};
|
};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use std::{fmt::Debug, future::Future, sync::Arc};
|
use std::{fmt::Debug, future::Future, sync::Arc};
|
||||||
|
use teloxide_core::{requests::Requester, types::Message};
|
||||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||||
|
|
||||||
/// A [REPL] for messages.
|
/// A [REPL] for messages.
|
||||||
|
@ -22,15 +21,18 @@ use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||||
///
|
///
|
||||||
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
|
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
|
||||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
pub async fn repl<H, Fut, E>(bot: Bot, handler: H)
|
pub async fn repl<R, H, Fut, E>(requester: R, handler: H)
|
||||||
where
|
where
|
||||||
H: Fn(UpdateWithCx<Message>) -> Fut + Send + Sync + 'static,
|
H: Fn(UpdateWithCx<R, Message>) -> Fut + Send + Sync + 'static,
|
||||||
Fut: Future<Output = Result<(), E>> + Send + 'static,
|
Fut: Future<Output = Result<(), E>> + Send + 'static,
|
||||||
Result<(), E>: OnError<E>,
|
Result<(), E>: OnError<E>,
|
||||||
E: Debug + Send,
|
E: Debug + Send,
|
||||||
|
R: Requester + Send + Clone + 'static,
|
||||||
|
<R as Requester>::GetUpdatesFaultTolerant: Send,
|
||||||
{
|
{
|
||||||
let cloned_bot = bot.clone();
|
let cloned_requester = requester.clone();
|
||||||
repl_with_listener(bot, handler, update_listeners::polling_default(cloned_bot)).await;
|
repl_with_listener(requester, handler, update_listeners::polling_default(cloned_requester))
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like [`repl`], but with a custom [`UpdateListener`].
|
/// Like [`repl`], but with a custom [`UpdateListener`].
|
||||||
|
@ -45,19 +47,23 @@ where
|
||||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
/// [`repl`]: crate::dispatching::repls::repl()
|
/// [`repl`]: crate::dispatching::repls::repl()
|
||||||
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
|
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
|
||||||
pub async fn repl_with_listener<'a, H, Fut, E, L, ListenerE>(bot: Bot, handler: H, listener: L)
|
pub async fn repl_with_listener<'a, R, H, Fut, E, L, ListenerE>(
|
||||||
where
|
requester: R,
|
||||||
H: Fn(UpdateWithCx<Message>) -> Fut + Send + Sync + 'static,
|
handler: H,
|
||||||
|
listener: L,
|
||||||
|
) where
|
||||||
|
H: Fn(UpdateWithCx<R, Message>) -> Fut + Send + Sync + 'static,
|
||||||
Fut: Future<Output = Result<(), E>> + Send + 'static,
|
Fut: Future<Output = Result<(), E>> + Send + 'static,
|
||||||
L: UpdateListener<ListenerE> + Send + 'a,
|
L: UpdateListener<ListenerE> + Send + 'a,
|
||||||
ListenerE: Debug,
|
ListenerE: Debug,
|
||||||
Result<(), E>: OnError<E>,
|
Result<(), E>: OnError<E>,
|
||||||
E: Debug + Send,
|
E: Debug + Send,
|
||||||
|
R: Requester + Clone + Send + 'static,
|
||||||
{
|
{
|
||||||
let handler = Arc::new(handler);
|
let handler = Arc::new(handler);
|
||||||
|
|
||||||
Dispatcher::new(bot)
|
Dispatcher::new(requester)
|
||||||
.messages_handler(|rx: DispatcherHandlerRx<Message>| {
|
.messages_handler(|rx: DispatcherHandlerRx<R, Message>| {
|
||||||
UnboundedReceiverStream::new(rx).for_each_concurrent(None, move |message| {
|
UnboundedReceiverStream::new(rx).for_each_concurrent(None, move |message| {
|
||||||
let handler = Arc::clone(&handler);
|
let handler = Arc::clone(&handler);
|
||||||
|
|
||||||
|
|
|
@ -105,14 +105,11 @@
|
||||||
|
|
||||||
use futures::{stream, Stream, StreamExt};
|
use futures::{stream, Stream, StreamExt};
|
||||||
|
|
||||||
use crate::{
|
|
||||||
bot::Bot,
|
|
||||||
requests::Request,
|
|
||||||
types::{AllowedUpdate, Update},
|
|
||||||
RequestError,
|
|
||||||
};
|
|
||||||
|
|
||||||
use std::{convert::TryInto, time::Duration};
|
use std::{convert::TryInto, time::Duration};
|
||||||
|
use teloxide_core::{
|
||||||
|
requests::{HasPayload, Request, Requester},
|
||||||
|
types::{AllowedUpdate, SemiparsedVec, Update},
|
||||||
|
};
|
||||||
|
|
||||||
/// A generic update listener.
|
/// A generic update listener.
|
||||||
pub trait UpdateListener<E>: Stream<Item = Result<Update, E>> {
|
pub trait UpdateListener<E>: Stream<Item = Result<Update, E>> {
|
||||||
|
@ -123,8 +120,12 @@ impl<S, E> UpdateListener<E> for S where S: Stream<Item = Result<Update, E>> {}
|
||||||
/// Returns a long polling update listener with `timeout` of 10 seconds.
|
/// Returns a long polling update listener with `timeout` of 10 seconds.
|
||||||
///
|
///
|
||||||
/// See also: [`polling`](polling).
|
/// See also: [`polling`](polling).
|
||||||
pub fn polling_default(bot: Bot) -> impl UpdateListener<RequestError> {
|
pub fn polling_default<R, E>(requester: R) -> impl UpdateListener<E>
|
||||||
polling(bot, Some(Duration::from_secs(10)), None, None)
|
where
|
||||||
|
R: Requester<Err = E>,
|
||||||
|
<R as Requester>::GetUpdatesFaultTolerant: Send,
|
||||||
|
{
|
||||||
|
polling(requester, Some(Duration::from_secs(10)), None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a long/short polling update listener with some additional options.
|
/// Returns a long/short polling update listener with some additional options.
|
||||||
|
@ -139,25 +140,31 @@ pub fn polling_default(bot: Bot) -> impl UpdateListener<RequestError> {
|
||||||
/// See also: [`polling_default`](polling_default).
|
/// See also: [`polling_default`](polling_default).
|
||||||
///
|
///
|
||||||
/// [`GetUpdates`]: crate::requests::GetUpdates
|
/// [`GetUpdates`]: crate::requests::GetUpdates
|
||||||
pub fn polling(
|
pub fn polling<R, E>(
|
||||||
bot: Bot,
|
requester: R,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
limit: Option<u8>,
|
limit: Option<u8>,
|
||||||
allowed_updates: Option<Vec<AllowedUpdate>>,
|
allowed_updates: Option<Vec<AllowedUpdate>>,
|
||||||
) -> impl UpdateListener<RequestError> {
|
) -> impl UpdateListener<E>
|
||||||
|
where
|
||||||
|
R: Requester<Err = E>,
|
||||||
|
<R as Requester>::GetUpdatesFaultTolerant: Send,
|
||||||
|
{
|
||||||
let timeout = timeout.map(|t| t.as_secs().try_into().expect("timeout is too big"));
|
let timeout = timeout.map(|t| t.as_secs().try_into().expect("timeout is too big"));
|
||||||
|
|
||||||
stream::unfold(
|
stream::unfold(
|
||||||
(allowed_updates, bot, 0),
|
(allowed_updates, requester, 0),
|
||||||
move |(mut allowed_updates, bot, mut offset)| async move {
|
move |(mut allowed_updates, bot, mut offset)| async move {
|
||||||
let mut req = bot.get_updates().offset(offset);
|
let mut req = bot.get_updates_fault_tolerant();
|
||||||
req.timeout = timeout;
|
let payload = &mut req.payload_mut().0;
|
||||||
req.limit = limit;
|
payload.offset = Some(offset);
|
||||||
req.allowed_updates = allowed_updates.take();
|
payload.timeout = timeout;
|
||||||
|
payload.limit = limit;
|
||||||
|
payload.allowed_updates = allowed_updates.take();
|
||||||
|
|
||||||
let updates = match req.send().await {
|
let updates = match req.send().await {
|
||||||
Err(err) => vec![Err(err)],
|
Err(err) => vec![Err(err)],
|
||||||
Ok(updates) => {
|
Ok(SemiparsedVec(updates)) => {
|
||||||
// Set offset to the last update's id + 1
|
// Set offset to the last update's id + 1
|
||||||
if let Some(upd) = updates.last() {
|
if let Some(upd) = updates.last() {
|
||||||
let id: i32 = match upd {
|
let id: i32 = match upd {
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
use crate::{
|
use crate::dispatching::dialogue::GetChatId;
|
||||||
dispatching::dialogue::GetChatId,
|
use teloxide_core::{
|
||||||
requests::{
|
payloads::SendMessageSetters,
|
||||||
DeleteMessage, EditMessageCaption, EditMessageText, ForwardMessage, PinChatMessage,
|
requests::{Request, Requester},
|
||||||
Request, ResponseResult, SendAnimation, SendAudio, SendContact, SendDice, SendDocument,
|
|
||||||
SendLocation, SendMediaGroup, SendMessage, SendPhoto, SendSticker, SendVenue, SendVideo,
|
|
||||||
SendVideoNote, SendVoice,
|
|
||||||
},
|
|
||||||
types::{ChatId, InputFile, InputMedia, Message},
|
types::{ChatId, InputFile, InputMedia, Message},
|
||||||
Bot,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A [`Dispatcher`]'s handler's context of a bot and an update.
|
/// A [`Dispatcher`]'s handler's context of a bot and an update.
|
||||||
|
@ -17,12 +12,12 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UpdateWithCx<Upd> {
|
pub struct UpdateWithCx<R, Upd> {
|
||||||
pub bot: Bot,
|
pub requester: R,
|
||||||
pub update: Upd,
|
pub update: Upd,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Upd> GetChatId for UpdateWithCx<Upd>
|
impl<Upd, R> GetChatId for UpdateWithCx<R, Upd>
|
||||||
where
|
where
|
||||||
Upd: GetChatId,
|
Upd: GetChatId,
|
||||||
{
|
{
|
||||||
|
@ -31,121 +26,136 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpdateWithCx<Message> {
|
#[doc(hidden)]
|
||||||
|
// Now it is used only inside `#[teloxide(subtransition)]` for type inference.
|
||||||
|
pub trait UpdateWithCxRequesterType {
|
||||||
|
type Requester;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R, Upd> UpdateWithCxRequesterType for UpdateWithCx<R, Upd> {
|
||||||
|
type Requester = R;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> UpdateWithCx<R, Message>
|
||||||
|
where
|
||||||
|
R: Requester,
|
||||||
|
{
|
||||||
/// A shortcut for `.answer(text).send().await`.
|
/// A shortcut for `.answer(text).send().await`.
|
||||||
pub async fn answer_str<T>(&self, text: T) -> ResponseResult<Message>
|
#[deprecated(note = "Use .answer(text).await instead")]
|
||||||
|
pub async fn answer_str<T>(&self, text: T) -> Result<Message, R::Err>
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
|
R::SendMessage: std::future::Future,
|
||||||
{
|
{
|
||||||
self.answer(text).send().await
|
self.answer(text).send().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer<T>(&self, text: T) -> SendMessage
|
pub fn answer<T>(&self, text: T) -> R::SendMessage
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
{
|
{
|
||||||
self.bot.send_message(self.chat_id(), text)
|
self.requester.send_message(self.chat_id(), text)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reply_to<T>(&self, text: T) -> SendMessage
|
pub fn reply_to<T>(&self, text: T) -> R::SendMessage
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
{
|
{
|
||||||
self.bot.send_message(self.chat_id(), text).reply_to_message_id(self.update.id)
|
self.requester.send_message(self.chat_id(), text).reply_to_message_id(self.update.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_photo(&self, photo: InputFile) -> SendPhoto {
|
pub fn answer_photo(&self, photo: InputFile) -> R::SendPhoto {
|
||||||
self.bot.send_photo(self.update.chat.id, photo)
|
self.requester.send_photo(self.update.chat.id, photo)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_audio(&self, audio: InputFile) -> SendAudio {
|
pub fn answer_audio(&self, audio: InputFile) -> R::SendAudio {
|
||||||
self.bot.send_audio(self.update.chat.id, audio)
|
self.requester.send_audio(self.update.chat.id, audio)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_animation(&self, animation: InputFile) -> SendAnimation {
|
pub fn answer_animation(&self, animation: InputFile) -> R::SendAnimation {
|
||||||
self.bot.send_animation(self.update.chat.id, animation)
|
self.requester.send_animation(self.update.chat.id, animation)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_document(&self, document: InputFile) -> SendDocument {
|
pub fn answer_document(&self, document: InputFile) -> R::SendDocument {
|
||||||
self.bot.send_document(self.update.chat.id, document)
|
self.requester.send_document(self.update.chat.id, document)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_video(&self, video: InputFile) -> SendVideo {
|
pub fn answer_video(&self, video: InputFile) -> R::SendVideo {
|
||||||
self.bot.send_video(self.update.chat.id, video)
|
self.requester.send_video(self.update.chat.id, video)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_voice(&self, voice: InputFile) -> SendVoice {
|
pub fn answer_voice(&self, voice: InputFile) -> R::SendVoice {
|
||||||
self.bot.send_voice(self.update.chat.id, voice)
|
self.requester.send_voice(self.update.chat.id, voice)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_media_group<T>(&self, media_group: T) -> SendMediaGroup
|
pub fn answer_media_group<T>(&self, media_group: T) -> R::SendMediaGroup
|
||||||
where
|
where
|
||||||
T: Into<Vec<InputMedia>>,
|
T: IntoIterator<Item = InputMedia>,
|
||||||
{
|
{
|
||||||
self.bot.send_media_group(self.update.chat.id, media_group)
|
self.requester.send_media_group(self.update.chat.id, media_group)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_location(&self, latitude: f32, longitude: f32) -> SendLocation {
|
pub fn answer_location(&self, latitude: f64, longitude: f64) -> R::SendLocation {
|
||||||
self.bot.send_location(self.update.chat.id, latitude, longitude)
|
self.requester.send_location(self.update.chat.id, latitude, longitude)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_venue<T, U>(
|
pub fn answer_venue<T, U>(
|
||||||
&self,
|
&self,
|
||||||
latitude: f32,
|
latitude: f64,
|
||||||
longitude: f32,
|
longitude: f64,
|
||||||
title: T,
|
title: T,
|
||||||
address: U,
|
address: U,
|
||||||
) -> SendVenue
|
) -> R::SendVenue
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
{
|
{
|
||||||
self.bot.send_venue(self.update.chat.id, latitude, longitude, title, address)
|
self.requester.send_venue(self.update.chat.id, latitude, longitude, title, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_video_note(&self, video_note: InputFile) -> SendVideoNote {
|
pub fn answer_video_note(&self, video_note: InputFile) -> R::SendVideoNote {
|
||||||
self.bot.send_video_note(self.update.chat.id, video_note)
|
self.requester.send_video_note(self.update.chat.id, video_note)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_contact<T, U>(&self, phone_number: T, first_name: U) -> SendContact
|
pub fn answer_contact<T, U>(&self, phone_number: T, first_name: U) -> R::SendContact
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
{
|
{
|
||||||
self.bot.send_contact(self.chat_id(), phone_number, first_name)
|
self.requester.send_contact(self.chat_id(), phone_number, first_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_sticker(&self, sticker: InputFile) -> SendSticker {
|
pub fn answer_sticker(&self, sticker: InputFile) -> R::SendSticker {
|
||||||
self.bot.send_sticker(self.update.chat.id, sticker)
|
self.requester.send_sticker(self.update.chat.id, sticker)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn forward_to<T>(&self, chat_id: T) -> ForwardMessage
|
pub fn forward_to<T>(&self, chat_id: T) -> R::ForwardMessage
|
||||||
where
|
where
|
||||||
T: Into<ChatId>,
|
T: Into<ChatId>,
|
||||||
{
|
{
|
||||||
self.bot.forward_message(chat_id, self.update.chat.id, self.update.id)
|
self.requester.forward_message(chat_id, self.update.chat.id, self.update.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edit_message_text<T>(&self, text: T) -> EditMessageText
|
pub fn edit_message_text<T>(&self, text: T) -> R::EditMessageText
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
{
|
{
|
||||||
self.bot.edit_message_text(self.update.chat.id, self.update.id, text)
|
self.requester.edit_message_text(self.update.chat.id, self.update.id, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edit_message_caption(&self) -> EditMessageCaption {
|
pub fn edit_message_caption(&self) -> R::EditMessageCaption {
|
||||||
self.bot.edit_message_caption(self.update.chat.id, self.update.id)
|
self.requester.edit_message_caption(self.update.chat.id, self.update.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_message(&self) -> DeleteMessage {
|
pub fn delete_message(&self) -> R::DeleteMessage {
|
||||||
self.bot.delete_message(self.update.chat.id, self.update.id)
|
self.requester.delete_message(self.update.chat.id, self.update.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pin_message(&self) -> PinChatMessage {
|
pub fn pin_message(&self) -> R::PinChatMessage {
|
||||||
self.bot.pin_chat_message(self.update.chat.id, self.update.id)
|
self.requester.pin_chat_message(self.update.chat.id, self.update.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_dice(&self) -> SendDice {
|
pub fn answer_dice(&self) -> R::SendDice {
|
||||||
self.bot.send_dice(self.update.chat.id)
|
self.requester.send_dice(self.update.chat.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
515
src/errors.rs
515
src/errors.rs
|
@ -1,515 +0,0 @@
|
||||||
use derive_more::From;
|
|
||||||
use reqwest::StatusCode;
|
|
||||||
use serde::Deserialize;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
/// An error caused by downloading a file.
|
|
||||||
#[derive(Debug, Error, From)]
|
|
||||||
pub enum DownloadError {
|
|
||||||
#[error("A network error: {0}")]
|
|
||||||
NetworkError(#[source] reqwest::Error),
|
|
||||||
|
|
||||||
#[error("An I/O error: {0}")]
|
|
||||||
Io(#[source] std::io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An error caused by sending a request to Telegram.
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum RequestError {
|
|
||||||
#[error("A Telegram's error #{status_code}: {kind:?}")]
|
|
||||||
ApiError { status_code: StatusCode, kind: ApiErrorKind },
|
|
||||||
|
|
||||||
/// The group has been migrated to a supergroup with the specified
|
|
||||||
/// identifier.
|
|
||||||
#[error("The group has been migrated to a supergroup with ID #{0}")]
|
|
||||||
MigrateToChatId(i64),
|
|
||||||
|
|
||||||
/// In case of exceeding flood control, the number of seconds left to wait
|
|
||||||
/// before the request can be repeated.
|
|
||||||
#[error("Retry after {0} seconds")]
|
|
||||||
RetryAfter(i32),
|
|
||||||
|
|
||||||
#[error("A network error: {0}")]
|
|
||||||
NetworkError(#[source] reqwest::Error),
|
|
||||||
|
|
||||||
#[error("An error while parsing JSON: {0}")]
|
|
||||||
InvalidJson(#[source] serde_json::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A kind of an API error.
|
|
||||||
///
|
|
||||||
/// If you receive [`ApiErrorKind::Unknown`], please [open an issue] with
|
|
||||||
/// the description of the error.
|
|
||||||
///
|
|
||||||
/// [`ApiErrorKind::Unknown`]: crate::ApiErrorKind::Unknown
|
|
||||||
/// [open an issue]: https://github.com/teloxide/teloxide/issues/new
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Hash, Eq, Clone)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum ApiErrorKind {
|
|
||||||
Known(KnownApiErrorKind),
|
|
||||||
Unknown(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A kind of a known API error.
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Copy, Hash, Eq, Clone)]
|
|
||||||
pub enum KnownApiErrorKind {
|
|
||||||
/// Occurs when the bot tries to send message to user who blocked the bot.
|
|
||||||
#[serde(rename = "Forbidden: bot was blocked by the user")]
|
|
||||||
BotBlocked,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to modify a message without modification content.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`EditMessageText`]
|
|
||||||
///
|
|
||||||
/// [`EditMessageText`]: crate::requests::EditMessageText
|
|
||||||
#[serde(rename = "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 the message")]
|
|
||||||
MessageNotModified,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to forward or delete a message which was deleted.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`ForwardMessage`]
|
|
||||||
/// 2. [`DeleteMessage`]
|
|
||||||
///
|
|
||||||
/// [`ForwardMessage`]: crate::requests::ForwardMessage
|
|
||||||
/// [`DeleteMessage`]: crate::requests::DeleteMessage
|
|
||||||
#[serde(rename = "Bad Request: MESSAGE_ID_INVALID")]
|
|
||||||
MessageIdInvalid,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to forward a message which does not exists.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`ForwardMessage`]
|
|
||||||
///
|
|
||||||
/// [`ForwardMessage`]: crate::requests::ForwardMessage
|
|
||||||
#[serde(rename = "Bad Request: message to forward not found")]
|
|
||||||
MessageToForwardNotFound,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to delete a message which does not exists.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`DeleteMessage`]
|
|
||||||
///
|
|
||||||
/// [`DeleteMessage`]: crate::requests::DeleteMessage
|
|
||||||
#[serde(rename = "Bad Request: message to delete not found")]
|
|
||||||
MessageToDeleteNotFound,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send a text message without text.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Bad Request: message text is empty")]
|
|
||||||
MessageTextIsEmpty,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to edit a message after long time.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`EditMessageText`]
|
|
||||||
///
|
|
||||||
/// [`EditMessageText`]: crate::requests::EditMessageText
|
|
||||||
#[serde(rename = "Bad Request: message can't be edited")]
|
|
||||||
MessageCantBeEdited,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to delete a someone else's message in group where
|
|
||||||
/// it does not have enough rights.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`DeleteMessage`]
|
|
||||||
///
|
|
||||||
/// [`DeleteMessage`]: crate::requests::DeleteMessage
|
|
||||||
#[serde(rename = "Bad Request: message can't be deleted")]
|
|
||||||
MessageCantBeDeleted,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to edit a message which does not exists.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`EditMessageText`]
|
|
||||||
///
|
|
||||||
/// [`EditMessageText`]: crate::requests::EditMessageText
|
|
||||||
#[serde(rename = "Bad Request: message to edit not found")]
|
|
||||||
MessageToEditNotFound,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to reply to a message which does not exists.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Bad Request: reply message not found")]
|
|
||||||
MessageToReplyNotFound,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to
|
|
||||||
#[serde(rename = "Bad Request: message identifier is not specified")]
|
|
||||||
MessageIdentifierNotSpecified,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send a message with text size greater then
|
|
||||||
/// 4096 symbols.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Bad Request: message is too long")]
|
|
||||||
MessageIsTooLong,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send media group with more than 10 items.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMediaGroup`]
|
|
||||||
///
|
|
||||||
/// [`SendMediaGroup`]: crate::requests::SendMediaGroup
|
|
||||||
#[serde(rename = "Bad Request: Too much messages to send as an album")]
|
|
||||||
ToMuchMessages,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to stop poll that has already been stopped.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendPoll`]
|
|
||||||
///
|
|
||||||
/// [`SendPoll`]: crate::requests::SendPoll
|
|
||||||
#[serde(rename = "Bad Request: poll has already been closed")]
|
|
||||||
PollHasAlreadyClosed,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send poll with less than 2 options.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendPoll`]
|
|
||||||
///
|
|
||||||
/// [`SendPoll`]: crate::requests::SendPoll
|
|
||||||
#[serde(rename = "Bad Request: poll must have at least 2 option")]
|
|
||||||
PollMustHaveMoreOptions,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send poll with more than 10 options.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendPoll`]
|
|
||||||
///
|
|
||||||
/// [`SendPoll`]: crate::requests::SendPoll
|
|
||||||
#[serde(rename = "Bad Request: poll can't have more than 10 options")]
|
|
||||||
PollCantHaveMoreOptions,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send poll with empty option (without text).
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendPoll`]
|
|
||||||
///
|
|
||||||
/// [`SendPoll`]: crate::requests::SendPoll
|
|
||||||
#[serde(rename = "Bad Request: poll options must be non-empty")]
|
|
||||||
PollOptionsMustBeNonEmpty,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send poll with empty question (without text).
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendPoll`]
|
|
||||||
///
|
|
||||||
/// [`SendPoll`]: crate::requests::SendPoll
|
|
||||||
#[serde(rename = "Bad Request: poll question must be non-empty")]
|
|
||||||
PollQuestionMustBeNonEmpty,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send poll with total size of options more than
|
|
||||||
/// 100 symbols.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendPoll`]
|
|
||||||
///
|
|
||||||
/// [`SendPoll`]: crate::requests::SendPoll
|
|
||||||
#[serde(rename = "Bad Request: poll options length must not exceed 100")]
|
|
||||||
PollOptionsLengthTooLong,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send poll with question size more than 255
|
|
||||||
/// symbols.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendPoll`]
|
|
||||||
///
|
|
||||||
/// [`SendPoll`]: crate::requests::SendPoll
|
|
||||||
#[serde(rename = "Bad Request: poll question length must not exceed 255")]
|
|
||||||
PollQuestionLengthTooLong,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to stop poll with message without poll.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`StopPoll`]
|
|
||||||
///
|
|
||||||
/// [`StopPoll`]: crate::requests::StopPoll
|
|
||||||
#[serde(rename = "Bad Request: message with poll to stop not found")]
|
|
||||||
MessageWithPollNotFound,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to stop poll with message without poll.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`StopPoll`]
|
|
||||||
///
|
|
||||||
/// [`StopPoll`]: crate::requests::StopPoll
|
|
||||||
#[serde(rename = "Bad Request: message is not a poll")]
|
|
||||||
MessageIsNotAPoll,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send a message to chat in which it is not a
|
|
||||||
/// member.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Bad Request: chat not found")]
|
|
||||||
ChatNotFound,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send method with unknown user_id.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`getUserProfilePhotos`]
|
|
||||||
///
|
|
||||||
/// [`getUserProfilePhotos`]:
|
|
||||||
/// crate::requests::GetUserProfilePhotos
|
|
||||||
#[serde(rename = "Bad Request: user not found")]
|
|
||||||
UserNotFound,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send [`SetChatDescription`] with same text as
|
|
||||||
/// in the current description.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SetChatDescription`]
|
|
||||||
///
|
|
||||||
/// [`SetChatDescription`]: crate::requests::SetChatDescription
|
|
||||||
#[serde(rename = "Bad Request: chat description is not modified")]
|
|
||||||
ChatDescriptionIsNotModified,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to answer to query after timeout expire.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`AnswerCallbackQuery`]
|
|
||||||
///
|
|
||||||
/// [`AnswerCallbackQuery`]: crate::requests::AnswerCallbackQuery
|
|
||||||
#[serde(rename = "Bad Request: query is too old and response timeout expired or query id is \
|
|
||||||
invalid")]
|
|
||||||
InvalidQueryID,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send InlineKeyboardMarkup with invalid button
|
|
||||||
/// url.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Bad Request: BUTTON_URL_INVALID")]
|
|
||||||
ButtonURLInvalid,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send button with data size more than 64 bytes.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Bad Request: BUTTON_DATA_INVALID")]
|
|
||||||
ButtonDataInvalid,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send button with data size == 0.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Bad Request: can't parse inline keyboard button: Text buttons are \
|
|
||||||
unallowed in the inline keyboard")]
|
|
||||||
TextButtonsAreUnallowed,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to get file by wrong file id.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`GetFile`]
|
|
||||||
///
|
|
||||||
/// [`GetFile`]: crate::requests::GetFile
|
|
||||||
#[serde(rename = "Bad Request: wrong file id")]
|
|
||||||
WrongFileID,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to do some with group which was deactivated.
|
|
||||||
#[serde(rename = "Bad Request: group is deactivated")]
|
|
||||||
GroupDeactivated,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to set chat photo from file ID
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SetChatPhoto`]
|
|
||||||
///
|
|
||||||
/// [`SetChatPhoto`]: crate::requests::SetChatPhoto
|
|
||||||
#[serde(rename = "Bad Request: Photo should be uploaded as an InputFile")]
|
|
||||||
PhotoAsInputFileRequired,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to add sticker to stickerset by invalid name.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`AddStickerToSet`]
|
|
||||||
///
|
|
||||||
/// [`AddStickerToSet`]: crate::requests::AddStickerToSet
|
|
||||||
#[serde(rename = "Bad Request: STICKERSET_INVALID")]
|
|
||||||
InvalidStickersSet,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to pin a message without rights to pin in this
|
|
||||||
/// chat.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`PinChatMessage`]
|
|
||||||
///
|
|
||||||
/// [`PinChatMessage`]: crate::requests::PinChatMessage
|
|
||||||
#[serde(rename = "Bad Request: not enough rights to pin a message")]
|
|
||||||
NotEnoughRightsToPinMessage,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to use method in group which is allowed only in a
|
|
||||||
/// supergroup or channel.
|
|
||||||
#[serde(rename = "Bad Request: method is available only for supergroups and channel")]
|
|
||||||
MethodNotAvailableInPrivateChats,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to demote chat creator.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`PromoteChatMember`]
|
|
||||||
///
|
|
||||||
/// [`PromoteChatMember`]: crate::requests::PromoteChatMember
|
|
||||||
#[serde(rename = "Bad Request: can't demote chat creator")]
|
|
||||||
CantDemoteChatCreator,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to restrict self in group chats.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`RestrictChatMember`]
|
|
||||||
///
|
|
||||||
/// [`RestrictChatMember`]: crate::requests::RestrictChatMember
|
|
||||||
#[serde(rename = "Bad Request: can't restrict self")]
|
|
||||||
CantRestrictSelf,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to restrict chat member without rights to
|
|
||||||
/// restrict in this chat.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`RestrictChatMember`]
|
|
||||||
///
|
|
||||||
/// [`RestrictChatMember`]: crate::requests::RestrictChatMember
|
|
||||||
#[serde(rename = "Bad Request: not enough rights to restrict/unrestrict chat member")]
|
|
||||||
NotEnoughRightsToRestrict,
|
|
||||||
|
|
||||||
/// Occurs when bot tries set webhook to protocol other than HTTPS.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SetWebhook`]
|
|
||||||
///
|
|
||||||
/// [`SetWebhook`]: crate::requests::SetWebhook
|
|
||||||
#[serde(rename = "Bad Request: bad webhook: HTTPS url must be provided for webhook")]
|
|
||||||
WebhookRequireHTTPS,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to set webhook to port other than 80, 88, 443 or
|
|
||||||
/// 8443.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SetWebhook`]
|
|
||||||
///
|
|
||||||
/// [`SetWebhook`]: crate::requests::SetWebhook
|
|
||||||
#[serde(rename = "Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 \
|
|
||||||
or 8443")]
|
|
||||||
BadWebhookPort,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to set webhook to unknown host.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SetWebhook`]
|
|
||||||
///
|
|
||||||
/// [`SetWebhook`]: crate::requests::SetWebhook
|
|
||||||
#[serde(rename = "Bad Request: bad webhook: Failed to resolve host: Name or service not known")]
|
|
||||||
UnknownHost,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to set webhook to invalid URL.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SetWebhook`]
|
|
||||||
///
|
|
||||||
/// [`SetWebhook`]: crate::requests::SetWebhook
|
|
||||||
#[serde(rename = "Bad Request: can't parse URL")]
|
|
||||||
CantParseUrl,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send message with unfinished entities.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Bad Request: can't parse entities")]
|
|
||||||
CantParseEntities,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to use getUpdates while webhook is active.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`GetUpdates`]
|
|
||||||
///
|
|
||||||
/// [`GetUpdates`]: crate::requests::GetUpdates
|
|
||||||
#[serde(rename = "can't use getUpdates method while webhook is active")]
|
|
||||||
CantGetUpdates,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to do some in group where bot was kicked.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Unauthorized: bot was kicked from a chat")]
|
|
||||||
BotKicked,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send message to deactivated user.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Unauthorized: user is deactivated")]
|
|
||||||
UserDeactivated,
|
|
||||||
|
|
||||||
/// Occurs when you tries to initiate conversation with a user.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Unauthorized: bot can't initiate conversation with a user")]
|
|
||||||
CantInitiateConversation,
|
|
||||||
|
|
||||||
/// Occurs when you tries to send message to bot.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Unauthorized: bot can't send messages to bots")]
|
|
||||||
CantTalkWithBots,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to send button with invalid http url.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`SendMessage`]
|
|
||||||
///
|
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
|
||||||
#[serde(rename = "Bad Request: wrong HTTP URL")]
|
|
||||||
WrongHTTPurl,
|
|
||||||
|
|
||||||
/// Occurs when bot tries GetUpdate before the timeout. Make sure that only
|
|
||||||
/// one Updater is running.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`GetUpdates`]
|
|
||||||
///
|
|
||||||
/// [`GetUpdates`]: crate::requests::GetUpdates
|
|
||||||
#[serde(rename = "Conflict: terminated by other getUpdates request; make sure that only one \
|
|
||||||
bot instance is running")]
|
|
||||||
TerminatedByOtherGetUpdates,
|
|
||||||
|
|
||||||
/// Occurs when bot tries to get file by invalid file id.
|
|
||||||
///
|
|
||||||
/// May happen in methods:
|
|
||||||
/// 1. [`GetFile`]
|
|
||||||
///
|
|
||||||
/// [`GetFile`]: crate::requests::GetFile
|
|
||||||
#[serde(rename = "Bad Request: invalid file id")]
|
|
||||||
FileIdInvalid,
|
|
||||||
}
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -51,25 +51,22 @@
|
||||||
// FIXME(waffle): use `docsrs` here when issue with combine is resolved <https://github.com/teloxide/teloxide/pull/305#issuecomment-716172103>
|
// FIXME(waffle): use `docsrs` here when issue with combine is resolved <https://github.com/teloxide/teloxide/pull/305#issuecomment-716172103>
|
||||||
#![cfg_attr(all(teloxide_docsrs, feature = "nightly"), feature(doc_cfg))]
|
#![cfg_attr(all(teloxide_docsrs, feature = "nightly"), feature(doc_cfg))]
|
||||||
|
|
||||||
pub use bot::{Bot, BotBuilder};
|
|
||||||
pub use dispatching::repls::{
|
pub use dispatching::repls::{
|
||||||
commands_repl, commands_repl_with_listener, dialogues_repl, dialogues_repl_with_listener, repl,
|
commands_repl, commands_repl_with_listener, dialogues_repl, dialogues_repl_with_listener, repl,
|
||||||
repl_with_listener,
|
repl_with_listener,
|
||||||
};
|
};
|
||||||
pub use errors::{ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError};
|
pub use teloxide_core::{ApiError, DownloadError, RequestError};
|
||||||
|
|
||||||
mod errors;
|
mod logging;
|
||||||
mod net;
|
|
||||||
|
|
||||||
mod bot;
|
|
||||||
pub mod dispatching;
|
pub mod dispatching;
|
||||||
pub mod error_handlers;
|
pub mod error_handlers;
|
||||||
mod logging;
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
pub mod requests;
|
|
||||||
pub mod types;
|
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
pub use teloxide_core as core;
|
||||||
|
|
||||||
|
use teloxide_core::requests::ResponseResult;
|
||||||
#[cfg(feature = "macros")]
|
#[cfg(feature = "macros")]
|
||||||
// FIXME(waffle): use `docsrs` here when issue with combine is resolved <https://github.com/teloxide/teloxide/pull/305#issuecomment-716172103>
|
// FIXME(waffle): use `docsrs` here when issue with combine is resolved <https://github.com/teloxide/teloxide/pull/305#issuecomment-716172103>
|
||||||
#[cfg_attr(all(teloxide_docsrs, feature = "nightly"), doc(cfg(feature = "macros")))]
|
#[cfg_attr(all(teloxide_docsrs, feature = "nightly"), doc(cfg(feature = "macros")))]
|
||||||
|
@ -78,3 +75,8 @@ pub use teloxide_macros::teloxide;
|
||||||
#[cfg(all(feature = "nightly", doctest))]
|
#[cfg(all(feature = "nightly", doctest))]
|
||||||
#[doc(include = "../README.md")]
|
#[doc(include = "../README.md")]
|
||||||
enum ReadmeDocTests {}
|
enum ReadmeDocTests {}
|
||||||
|
|
||||||
|
/// A shortcut for `ResponseResult::Ok(val)`.
|
||||||
|
pub fn respond<T>(val: T) -> ResponseResult<T> {
|
||||||
|
ResponseResult::Ok(val)
|
||||||
|
}
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
use reqwest::Client;
|
|
||||||
use tokio::io::{AsyncWrite, AsyncWriteExt};
|
|
||||||
|
|
||||||
use crate::errors::DownloadError;
|
|
||||||
|
|
||||||
use super::TELEGRAM_API_URL;
|
|
||||||
|
|
||||||
pub async fn download_file<D>(
|
|
||||||
client: &Client,
|
|
||||||
token: &str,
|
|
||||||
path: &str,
|
|
||||||
destination: &mut D,
|
|
||||||
) -> Result<(), DownloadError>
|
|
||||||
where
|
|
||||||
D: AsyncWrite + Unpin,
|
|
||||||
{
|
|
||||||
let mut res = client
|
|
||||||
.get(&super::file_url(TELEGRAM_API_URL, token, path))
|
|
||||||
.send()
|
|
||||||
.await?
|
|
||||||
.error_for_status()?;
|
|
||||||
|
|
||||||
while let Some(chunk) = res.chunk().await? {
|
|
||||||
destination.write_all(&chunk).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "unstable-stream")]
|
|
||||||
// FIXME(waffle): use `docsrs` here when issue with combine is resolved <https://github.com/teloxide/teloxide/pull/305#issuecomment-716172103>
|
|
||||||
#[cfg_attr(all(teloxide_docsrs, feature = "nightly"), doc(cfg(feature = "unstable-stream")))]
|
|
||||||
pub async fn download_file_stream(
|
|
||||||
client: &Client,
|
|
||||||
token: &str,
|
|
||||||
path: &str,
|
|
||||||
) -> Result<impl Stream<Item = reqwest::Result<Bytes>>, reqwest::Error> {
|
|
||||||
let res = client
|
|
||||||
.get(&super::file_url(TELEGRAM_API_URL, token, path))
|
|
||||||
.send()
|
|
||||||
.await?
|
|
||||||
.error_for_status()?;
|
|
||||||
|
|
||||||
Ok(futures::stream::unfold(res, |mut res| async {
|
|
||||||
match res.chunk().await {
|
|
||||||
Err(err) => Some((Err(err), res)),
|
|
||||||
Ok(Some(c)) => Some((Ok(c), res)),
|
|
||||||
Ok(None) => None,
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
#[cfg(feature = "unstable-stream")]
|
|
||||||
// FIXME(waffle): use `docsrs` here when issue with combine is resolved <https://github.com/teloxide/teloxide/pull/305#issuecomment-716172103>
|
|
||||||
#[cfg_attr(all(teloxide_docsrs, feature = "nightly"), doc(cfg(feature = "unstable-stream")))]
|
|
||||||
pub use download::download_file_stream;
|
|
||||||
|
|
||||||
pub use self::{
|
|
||||||
download::download_file,
|
|
||||||
request::{request_json, request_multipart},
|
|
||||||
telegram_response::TelegramResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod download;
|
|
||||||
mod request;
|
|
||||||
mod telegram_response;
|
|
||||||
|
|
||||||
const TELEGRAM_API_URL: &str = "https://api.telegram.org";
|
|
||||||
|
|
||||||
/// Creates URL for making HTTPS requests. See the [Telegram documentation].
|
|
||||||
///
|
|
||||||
/// [Telegram documentation]: https://core.telegram.org/bots/api#making-requests
|
|
||||||
fn method_url(base: &str, token: &str, method_name: &str) -> String {
|
|
||||||
format!("{url}/bot{token}/{method}", url = base, token = token, method = method_name,)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates URL for downloading a file. See the [Telegram documentation].
|
|
||||||
///
|
|
||||||
/// [Telegram documentation]: https://core.telegram.org/bots/api#file
|
|
||||||
fn file_url(base: &str, token: &str, file_path: &str) -> String {
|
|
||||||
format!("{url}/file/bot{token}/{file}", url = base, token = token, file = file_path,)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn method_url_test() {
|
|
||||||
let url = method_url(
|
|
||||||
TELEGRAM_API_URL,
|
|
||||||
"535362388:AAF7-g0gYncWnm5IyfZlpPRqRRv6kNAGlao",
|
|
||||||
"methodName",
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
url,
|
|
||||||
"https://api.telegram.org/bot535362388:AAF7-g0gYncWnm5IyfZlpPRqRRv6kNAGlao/methodName"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn file_url_test() {
|
|
||||||
let url = file_url(
|
|
||||||
TELEGRAM_API_URL,
|
|
||||||
"535362388:AAF7-g0gYncWnm5IyfZlpPRqRRv6kNAGlao",
|
|
||||||
"AgADAgADyqoxG2g8aEsu_KjjVsGF4-zetw8ABAEAAwIAA20AA_8QAwABFgQ",
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
url,
|
|
||||||
"https://api.telegram.org/file/bot535362388:AAF7-g0gYncWnm5IyfZlpPRqRRv6kNAGlao/AgADAgADyqoxG2g8aEsu_KjjVsGF4-zetw8ABAEAAwIAA20AA_8QAwABFgQ"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
use reqwest::{multipart::Form, Client, Response};
|
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
|
||||||
|
|
||||||
use crate::{requests::ResponseResult, RequestError};
|
|
||||||
|
|
||||||
use super::{TelegramResponse, TELEGRAM_API_URL};
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
const DELAY_ON_SERVER_ERROR: Duration = Duration::from_secs(10);
|
|
||||||
|
|
||||||
pub async fn request_multipart<T>(
|
|
||||||
client: &Client,
|
|
||||||
token: &str,
|
|
||||||
method_name: &str,
|
|
||||||
params: Form,
|
|
||||||
) -> ResponseResult<T>
|
|
||||||
where
|
|
||||||
T: DeserializeOwned,
|
|
||||||
{
|
|
||||||
let response = client
|
|
||||||
.post(&super::method_url(TELEGRAM_API_URL, token, method_name))
|
|
||||||
.multipart(params)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
.map_err(RequestError::NetworkError)?;
|
|
||||||
|
|
||||||
process_response(response).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn request_json<T, P>(
|
|
||||||
client: &Client,
|
|
||||||
token: &str,
|
|
||||||
method_name: &str,
|
|
||||||
params: &P,
|
|
||||||
) -> ResponseResult<T>
|
|
||||||
where
|
|
||||||
T: DeserializeOwned,
|
|
||||||
P: Serialize,
|
|
||||||
{
|
|
||||||
let response = client
|
|
||||||
.post(&super::method_url(TELEGRAM_API_URL, token, method_name))
|
|
||||||
.json(params)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
.map_err(RequestError::NetworkError)?;
|
|
||||||
|
|
||||||
process_response(response).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn process_response<T>(response: Response) -> ResponseResult<T>
|
|
||||||
where
|
|
||||||
T: DeserializeOwned,
|
|
||||||
{
|
|
||||||
if response.status().is_server_error() {
|
|
||||||
tokio::time::sleep(DELAY_ON_SERVER_ERROR).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
serde_json::from_str::<TelegramResponse<T>>(
|
|
||||||
&response.text().await.map_err(RequestError::NetworkError)?,
|
|
||||||
)
|
|
||||||
.map_err(RequestError::InvalidJson)?
|
|
||||||
.into()
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
use reqwest::StatusCode;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
requests::ResponseResult,
|
|
||||||
types::{False, ResponseParameters, True},
|
|
||||||
ApiErrorKind, RequestError,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum TelegramResponse<R> {
|
|
||||||
Ok {
|
|
||||||
/// A dummy field. Used only for deserialization.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
ok: True,
|
|
||||||
|
|
||||||
result: R,
|
|
||||||
},
|
|
||||||
Err {
|
|
||||||
/// A dummy field. Used only for deserialization.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
ok: False,
|
|
||||||
|
|
||||||
#[serde(rename = "description")]
|
|
||||||
kind: ApiErrorKind,
|
|
||||||
error_code: u16,
|
|
||||||
response_parameters: Option<ResponseParameters>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> Into<ResponseResult<R>> for TelegramResponse<R> {
|
|
||||||
fn into(self) -> Result<R, RequestError> {
|
|
||||||
match self {
|
|
||||||
TelegramResponse::Ok { result, .. } => Ok(result),
|
|
||||||
TelegramResponse::Err { kind, error_code, response_parameters, .. } => {
|
|
||||||
if let Some(params) = response_parameters {
|
|
||||||
match params {
|
|
||||||
ResponseParameters::RetryAfter(i) => Err(RequestError::RetryAfter(i)),
|
|
||||||
ResponseParameters::MigrateToChatId(to) => {
|
|
||||||
Err(RequestError::MigrateToChatId(to))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(RequestError::ApiError {
|
|
||||||
kind,
|
|
||||||
status_code: StatusCode::from_u16(error_code).unwrap(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::{errors::KnownApiErrorKind, types::Update};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn terminated_by_other_get_updates() {
|
|
||||||
let expected = ApiErrorKind::Known(KnownApiErrorKind::TerminatedByOtherGetUpdates);
|
|
||||||
if let TelegramResponse::Err{ kind, .. } = serde_json::from_str::<TelegramResponse<Update>>(r#"{"ok":false,"error_code":409,"description":"Conflict: terminated by other getUpdates request; make sure that only one bot instance is running"}"#).unwrap() {
|
|
||||||
assert_eq!(expected, kind);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
panic!("Expected ApiErrorKind::TerminatedByOtherGetUpdates");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,9 +9,16 @@ pub use crate::{
|
||||||
Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx,
|
Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx,
|
||||||
},
|
},
|
||||||
error_handlers::{LoggingErrorHandler, OnError},
|
error_handlers::{LoggingErrorHandler, OnError},
|
||||||
requests::{respond, Request, ResponseResult},
|
respond,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use teloxide_core::prelude::*;
|
||||||
|
|
||||||
|
pub use teloxide_core::{
|
||||||
|
adaptors::AutoSend,
|
||||||
|
requests::{Request, ResponseResult},
|
||||||
types::{Message, Update},
|
types::{Message, Update},
|
||||||
Bot, RequestError,
|
RequestError,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "frunk")]
|
#[cfg(feature = "frunk")]
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::form_builder::FormBuilder,
|
|
||||||
types::{MaskPosition, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
requests::{RequestWithFile, ResponseResult},
|
|
||||||
types::StickerType,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to add a new sticker to a set created by the bot.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#addstickertoset).
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct AddStickerToSet {
|
|
||||||
bot: Bot,
|
|
||||||
user_id: i32,
|
|
||||||
name: String,
|
|
||||||
sticker_type: StickerType,
|
|
||||||
emojis: String,
|
|
||||||
mask_position: Option<MaskPosition>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl RequestWithFile for AddStickerToSet {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> tokio::io::Result<ResponseResult<True>> {
|
|
||||||
let builder =
|
|
||||||
FormBuilder::new().add_text("user_id", &self.user_id).add_text("name", &self.name);
|
|
||||||
|
|
||||||
let builder = match &self.sticker_type {
|
|
||||||
StickerType::Png(file) => builder.add_input_file("png_sticker", &file),
|
|
||||||
StickerType::Tgs(file) => builder.add_input_file("tgs_sticker", &file),
|
|
||||||
}
|
|
||||||
.await?
|
|
||||||
.add_text("emojis", &self.emojis)
|
|
||||||
.add_text("mask_position", &self.mask_position);
|
|
||||||
|
|
||||||
Ok(net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"addStickerToSet",
|
|
||||||
builder.build(),
|
|
||||||
)
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddStickerToSet {
|
|
||||||
pub(crate) fn new<N, E>(
|
|
||||||
bot: Bot,
|
|
||||||
user_id: i32,
|
|
||||||
name: N,
|
|
||||||
sticker_type: StickerType,
|
|
||||||
emojis: E,
|
|
||||||
) -> Self
|
|
||||||
where
|
|
||||||
N: Into<String>,
|
|
||||||
E: Into<String>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
user_id,
|
|
||||||
name: name.into(),
|
|
||||||
sticker_type,
|
|
||||||
emojis: emojis.into(),
|
|
||||||
mask_position: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// User identifier of sticker set owner.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sticker set name.
|
|
||||||
pub fn name<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.name = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sticker_type(mut self, val: StickerType) -> Self {
|
|
||||||
self.sticker_type = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// One or more emoji corresponding to the sticker.
|
|
||||||
pub fn emojis<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.emojis = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A JSON-serialized object for position where the mask should be placed on
|
|
||||||
/// faces.
|
|
||||||
pub fn mask_position(mut self, val: MaskPosition) -> Self {
|
|
||||||
self.mask_position = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::True,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send answers to callback queries sent from [inline
|
|
||||||
/// keyboards].
|
|
||||||
///
|
|
||||||
/// The answer will be displayed to the user as a notification at
|
|
||||||
/// the top of the chat screen or as an alert.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#answercallbackquery).
|
|
||||||
///
|
|
||||||
/// [inline keyboards]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct AnswerCallbackQuery {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
callback_query_id: String,
|
|
||||||
text: Option<String>,
|
|
||||||
show_alert: Option<bool>,
|
|
||||||
url: Option<String>,
|
|
||||||
cache_time: Option<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for AnswerCallbackQuery {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "answerCallbackQuery", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AnswerCallbackQuery {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, callback_query_id: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<String>,
|
|
||||||
{
|
|
||||||
let callback_query_id = callback_query_id.into();
|
|
||||||
Self { bot, callback_query_id, text: None, show_alert: None, url: None, cache_time: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the query to be answered.
|
|
||||||
pub fn callback_query_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.callback_query_id = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Text of the notification. If not specified, nothing will be shown to the
|
|
||||||
/// user, 0-200 characters.
|
|
||||||
pub fn text<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.text = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If `true`, an alert will be shown by the client instead of a
|
|
||||||
/// notification at the top of the chat screen. Defaults to `false`.
|
|
||||||
pub fn show_alert(mut self, val: bool) -> Self {
|
|
||||||
self.show_alert = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// URL that will be opened by the user's client. If you have created a
|
|
||||||
/// [`Game`] and accepted the conditions via [@Botfather], specify the
|
|
||||||
/// URL that opens your game – note that this will only work if the
|
|
||||||
/// query comes from a [`callback_game`] button.
|
|
||||||
///
|
|
||||||
/// Otherwise, you may use links like `t.me/your_bot?start=XXXX` that open
|
|
||||||
/// your bot with a parameter.
|
|
||||||
///
|
|
||||||
/// [@Botfather]: https://t.me/botfather
|
|
||||||
/// [`callback_game`]: crate::types::InlineKeyboardButton
|
|
||||||
/// [`Game`]: crate::types::Game
|
|
||||||
pub fn url<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.url = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The maximum amount of time in seconds that the result of the callback
|
|
||||||
/// query may be cached client-side. Telegram apps will support caching
|
|
||||||
/// starting in version 3.14. Defaults to 0.
|
|
||||||
pub fn cache_time(mut self, val: i32) -> Self {
|
|
||||||
self.cache_time = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,146 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{InlineQueryResult, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send answers to an inline query.
|
|
||||||
///
|
|
||||||
/// No more than **50** results per query are allowed.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#answerinlinequery).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct AnswerInlineQuery {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
inline_query_id: String,
|
|
||||||
results: Vec<InlineQueryResult>,
|
|
||||||
cache_time: Option<i32>,
|
|
||||||
is_personal: Option<bool>,
|
|
||||||
next_offset: Option<String>,
|
|
||||||
switch_pm_text: Option<String>,
|
|
||||||
switch_pm_parameter: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for AnswerInlineQuery {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "answerInlineQuery", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AnswerInlineQuery {
|
|
||||||
pub(crate) fn new<I, R>(bot: Bot, inline_query_id: I, results: R) -> Self
|
|
||||||
where
|
|
||||||
I: Into<String>,
|
|
||||||
R: Into<Vec<InlineQueryResult>>,
|
|
||||||
{
|
|
||||||
let inline_query_id = inline_query_id.into();
|
|
||||||
let results = results.into();
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
inline_query_id,
|
|
||||||
results,
|
|
||||||
cache_time: None,
|
|
||||||
is_personal: None,
|
|
||||||
next_offset: None,
|
|
||||||
switch_pm_text: None,
|
|
||||||
switch_pm_parameter: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the answered query.
|
|
||||||
pub fn inline_query_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.inline_query_id = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A JSON-serialized array of results for the inline query.
|
|
||||||
pub fn results<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<Vec<InlineQueryResult>>,
|
|
||||||
{
|
|
||||||
self.results = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The maximum amount of time in seconds that the result of the inline
|
|
||||||
/// query may be cached on the server.
|
|
||||||
///
|
|
||||||
/// Defaults to 300.
|
|
||||||
pub fn cache_time(mut self, val: i32) -> Self {
|
|
||||||
self.cache_time = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if results may be cached on the server side only for the
|
|
||||||
/// user that sent the query.
|
|
||||||
///
|
|
||||||
/// By default, results may be returned to any user who sends the same
|
|
||||||
/// query.
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
|
||||||
pub fn is_personal(mut self, val: bool) -> Self {
|
|
||||||
self.is_personal = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass the offset that a client should send in the next query with the
|
|
||||||
/// same text to receive more results.
|
|
||||||
///
|
|
||||||
/// Pass an empty string if there are no more results or if you don‘t
|
|
||||||
/// support pagination. Offset length can’t exceed 64 bytes.
|
|
||||||
pub fn next_offset<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.next_offset = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If passed, clients will display a button with specified text that
|
|
||||||
/// switches the user to a private chat with the bot and sends the bot a
|
|
||||||
/// start message with the parameter [`switch_pm_parameter`].
|
|
||||||
///
|
|
||||||
/// [`switch_pm_parameter`]:
|
|
||||||
/// crate::requests::AnswerInlineQuery::switch_pm_parameter
|
|
||||||
pub fn switch_pm_text<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.switch_pm_text = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [Deep-linking] parameter for the /start message sent to the bot when
|
|
||||||
/// user presses the switch button. 1-64 characters, only `A-Z`, `a-z`,
|
|
||||||
/// `0-9`, `_` and `-` are allowed.
|
|
||||||
///
|
|
||||||
/// Example: An inline bot that sends YouTube videos can ask the user to
|
|
||||||
/// connect the bot to their YouTube account to adapt search results
|
|
||||||
/// accordingly. To do this, it displays a ‘Connect your YouTube account’
|
|
||||||
/// button above the results, or even before showing any. The user presses
|
|
||||||
/// the button, switches to a private chat with the bot and, in doing so,
|
|
||||||
/// passes a start parameter that instructs the bot to return an oauth link.
|
|
||||||
/// Once done, the bot can offer a [`switch_inline`] button so that the user
|
|
||||||
/// can easily return to the chat where they wanted to use the bot's
|
|
||||||
/// inline capabilities.
|
|
||||||
///
|
|
||||||
/// [Deep-linking]: https://core.telegram.org/bots#deep-linking
|
|
||||||
/// [`switch_inline`]: crate::types::InlineKeyboardMarkup
|
|
||||||
pub fn switch_pm_parameter<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.switch_pm_parameter = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::True,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Once the user has confirmed their payment and shipping details, the Bot API
|
|
||||||
/// sends the final confirmation in the form of an [`Update`] with the field
|
|
||||||
/// `pre_checkout_query`. Use this method to respond to such pre-checkout
|
|
||||||
/// queries.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
/// The Bot API must receive an answer within 10 seconds after the pre-checkout
|
|
||||||
/// query was sent.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#answerprecheckoutquery).
|
|
||||||
///
|
|
||||||
/// [`Update`]: crate::types::Update
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct AnswerPreCheckoutQuery {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
pre_checkout_query_id: String,
|
|
||||||
ok: bool,
|
|
||||||
error_message: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for AnswerPreCheckoutQuery {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "answerPreCheckoutQuery", &self)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AnswerPreCheckoutQuery {
|
|
||||||
pub(crate) fn new<P>(bot: Bot, pre_checkout_query_id: P, ok: bool) -> Self
|
|
||||||
where
|
|
||||||
P: Into<String>,
|
|
||||||
{
|
|
||||||
let pre_checkout_query_id = pre_checkout_query_id.into();
|
|
||||||
Self { bot, pre_checkout_query_id, ok, error_message: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the query to be answered.
|
|
||||||
pub fn pre_checkout_query_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.pre_checkout_query_id = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Specify `true` if everything is alright (goods are available, etc.) and
|
|
||||||
/// the bot is ready to proceed with the order. Use False if there are any
|
|
||||||
/// problems.
|
|
||||||
pub fn ok(mut self, val: bool) -> Self {
|
|
||||||
self.ok = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Required if ok is `false`. Error message in human readable form that
|
|
||||||
/// explains the reason for failure to proceed with the checkout (e.g.
|
|
||||||
/// "Sorry, somebody just bought the last of our amazing black T-shirts
|
|
||||||
/// while you were busy filling out your payment details. Please choose a
|
|
||||||
/// different color or garment!").
|
|
||||||
///
|
|
||||||
/// Telegram will display this message to the user.
|
|
||||||
pub fn error_message<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.error_message = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ShippingOption, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// If you sent an invoice requesting a shipping address and the parameter
|
|
||||||
/// `is_flexible` was specified, the Bot API will send an [`Update`] with a
|
|
||||||
/// shipping_query field to the bot. Use this method to reply to shipping
|
|
||||||
/// queries.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#answershippingquery).
|
|
||||||
///
|
|
||||||
/// [`Update`]: crate::types::Update
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct AnswerShippingQuery {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
shipping_query_id: String,
|
|
||||||
ok: bool,
|
|
||||||
shipping_options: Option<Vec<ShippingOption>>,
|
|
||||||
error_message: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for AnswerShippingQuery {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "answerShippingQuery", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AnswerShippingQuery {
|
|
||||||
pub(crate) fn new<S>(bot: Bot, shipping_query_id: S, ok: bool) -> Self
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
{
|
|
||||||
let shipping_query_id = shipping_query_id.into();
|
|
||||||
Self { bot, shipping_query_id, ok, shipping_options: None, error_message: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the query to be answered.
|
|
||||||
pub fn shipping_query_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.shipping_query_id = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Specify `true` if delivery to the specified address is possible and
|
|
||||||
/// `false` if there are any problems (for example, if delivery to the
|
|
||||||
/// specified address is not possible).
|
|
||||||
pub fn ok(mut self, val: bool) -> Self {
|
|
||||||
self.ok = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Required if ok is `true`. A JSON-serialized array of available shipping
|
|
||||||
/// options.
|
|
||||||
pub fn shipping_options<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<Vec<ShippingOption>>,
|
|
||||||
{
|
|
||||||
self.shipping_options = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Required if ok is `false`. Error message in human readable form that
|
|
||||||
/// explains why it is impossible to complete the order (e.g. "Sorry,
|
|
||||||
/// delivery to your desired address is unavailable').
|
|
||||||
///
|
|
||||||
/// Telegram will display this message to the user.
|
|
||||||
pub fn error_message<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.error_message = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,134 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, RequestWithFile, ResponseResult},
|
|
||||||
types::{MaskPosition, StickerType, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to create new sticker set owned by a user. The bot will be
|
|
||||||
/// able to edit the created sticker set.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#createnewstickerset).
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct CreateNewStickerSet {
|
|
||||||
bot: Bot,
|
|
||||||
user_id: i32,
|
|
||||||
name: String,
|
|
||||||
title: String,
|
|
||||||
sticker_type: StickerType,
|
|
||||||
emojis: String,
|
|
||||||
contains_masks: Option<bool>,
|
|
||||||
mask_position: Option<MaskPosition>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl RequestWithFile for CreateNewStickerSet {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> tokio::io::Result<ResponseResult<True>> {
|
|
||||||
let builder = FormBuilder::new()
|
|
||||||
.add_text("user_id", &self.user_id)
|
|
||||||
.add_text("name", &self.name)
|
|
||||||
.add_text("title", &self.title);
|
|
||||||
|
|
||||||
let builder = match &self.sticker_type {
|
|
||||||
StickerType::Png(file) => builder.add_input_file("png_sticker", &file),
|
|
||||||
StickerType::Tgs(file) => builder.add_input_file("tgs_sticker", &file),
|
|
||||||
}
|
|
||||||
.await?
|
|
||||||
.add_text("emojis", &self.emojis)
|
|
||||||
.add_text("contains_masks", &self.contains_masks)
|
|
||||||
.add_text("mask_position", &self.mask_position);
|
|
||||||
|
|
||||||
Ok(net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"createNewStickerSet",
|
|
||||||
builder.build(),
|
|
||||||
)
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CreateNewStickerSet {
|
|
||||||
pub(crate) fn new<N, T, E>(
|
|
||||||
bot: Bot,
|
|
||||||
user_id: i32,
|
|
||||||
name: N,
|
|
||||||
title: T,
|
|
||||||
sticker_type: StickerType,
|
|
||||||
emojis: E,
|
|
||||||
) -> Self
|
|
||||||
where
|
|
||||||
N: Into<String>,
|
|
||||||
T: Into<String>,
|
|
||||||
E: Into<String>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
user_id,
|
|
||||||
name: name.into(),
|
|
||||||
title: title.into(),
|
|
||||||
sticker_type,
|
|
||||||
emojis: emojis.into(),
|
|
||||||
contains_masks: None,
|
|
||||||
mask_position: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// User identifier of created sticker set owner.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Short name of sticker set, to be used in `t.me/addstickers/` URLs (e.g.,
|
|
||||||
/// animals). Can contain only english letters, digits and underscores.
|
|
||||||
///
|
|
||||||
/// Must begin with a letter, can't contain consecutive underscores and must
|
|
||||||
/// end in `_by_<bot username>`. `<bot_username>` is case insensitive.
|
|
||||||
/// 1-64 characters.
|
|
||||||
pub fn name<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.name = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sticker set title, 1-64 characters.
|
|
||||||
pub fn title<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.title = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sticker_type(mut self, val: StickerType) -> Self {
|
|
||||||
self.sticker_type = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// One or more emoji corresponding to the sticker.
|
|
||||||
pub fn emojis<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.emojis = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if a set of mask stickers should be created.
|
|
||||||
pub fn contains_masks(mut self, val: bool) -> Self {
|
|
||||||
self.contains_masks = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A JSON-serialized object for position where the mask should be placed on
|
|
||||||
/// faces.
|
|
||||||
pub fn mask_position(mut self, val: MaskPosition) -> Self {
|
|
||||||
self.mask_position = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to delete a chat photo. Photos can't be changed for private
|
|
||||||
/// chats. The bot must be an administrator in the chat for this to work and
|
|
||||||
/// must have the appropriate admin rights.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#deletechatphoto).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct DeleteChatPhoto {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for DeleteChatPhoto {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "deleteChatPhoto", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeleteChatPhoto {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to delete a group sticker set from a supergroup.
|
|
||||||
///
|
|
||||||
/// The bot must be an administrator in the chat for this to work and must have
|
|
||||||
/// the appropriate admin rights. Use the field `can_set_sticker_set` optionally
|
|
||||||
/// returned in [`Bot::get_chat`] requests to check if the bot can use this
|
|
||||||
/// method.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#deletechatstickerset).
|
|
||||||
///
|
|
||||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct DeleteChatStickerSet {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for DeleteChatStickerSet {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "deleteChatStickerSet", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeleteChatStickerSet {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
|
||||||
/// supergroup (in the format `@supergroupusername`).
|
|
||||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ChatId>,
|
|
||||||
{
|
|
||||||
self.chat_id = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to delete a message, including service messages.
|
|
||||||
///
|
|
||||||
/// The limitations are:
|
|
||||||
/// - A message can only be deleted if it was sent less than 48 hours ago.
|
|
||||||
/// - Bots can delete outgoing messages in private chats, groups, and
|
|
||||||
/// supergroups.
|
|
||||||
/// - Bots can delete incoming messages in private chats.
|
|
||||||
/// - Bots granted can_post_messages permissions can delete outgoing messages
|
|
||||||
/// in channels.
|
|
||||||
/// - If the bot is an administrator of a group, it can delete any message
|
|
||||||
/// there.
|
|
||||||
/// - If the bot has can_delete_messages permission in a supergroup or a
|
|
||||||
/// channel, it can delete any message there.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#deletemessage).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct DeleteMessage {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
message_id: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for DeleteMessage {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "deleteMessage", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeleteMessage {
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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 delete.
|
|
||||||
pub fn message_id(mut self, val: i32) -> Self {
|
|
||||||
self.message_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::True,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to delete a sticker from a set created by the bot.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#deletestickerfromset).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct DeleteStickerFromSet {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
sticker: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for DeleteStickerFromSet {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "deleteStickerFromSet", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeleteStickerFromSet {
|
|
||||||
pub(crate) fn new<S>(bot: Bot, sticker: S) -> Self
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
{
|
|
||||||
let sticker = sticker.into();
|
|
||||||
Self { bot, sticker }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// File identifier of the sticker.
|
|
||||||
pub fn sticker<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.sticker = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::True,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to remove webhook integration if you decide to switch back
|
|
||||||
/// to [Bot::get_updates].
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#deletewebhook).
|
|
||||||
///
|
|
||||||
/// [Bot::get_updates]: crate::Bot::get_updates
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct DeleteWebhook {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for DeleteWebhook {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "deleteWebhook", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeleteWebhook {
|
|
||||||
pub(crate) fn new(bot: Bot) -> Self {
|
|
||||||
Self { bot }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, InlineKeyboardMarkup, Message, ParseMode},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to edit captions of messages sent by the bot.
|
|
||||||
///
|
|
||||||
/// On success, the edited [`Message`] is returned.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagecaption).
|
|
||||||
///
|
|
||||||
/// [`Message`]: crate::types::Message
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct EditMessageCaption {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
message_id: i32,
|
|
||||||
caption: Option<String>,
|
|
||||||
parse_mode: Option<ParseMode>,
|
|
||||||
reply_markup: Option<InlineKeyboardMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for EditMessageCaption {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "editMessageCaption", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EditMessageCaption {
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
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, the
|
|
||||||
/// edited [`Message`] is returned.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagelivelocation).
|
|
||||||
///
|
|
||||||
/// [`Message`]: crate::types::Message
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct EditMessageLiveLocation {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
message_id: i32,
|
|
||||||
latitude: f32,
|
|
||||||
longitude: f32,
|
|
||||||
reply_markup: Option<InlineKeyboardMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for EditMessageLiveLocation {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "editMessageLiveLocation", &self)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EditMessageLiveLocation {
|
|
||||||
pub(crate) fn new<C>(
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: C,
|
|
||||||
message_id: i32,
|
|
||||||
latitude: f32,
|
|
||||||
longitude: f32,
|
|
||||||
) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id, message_id, latitude, longitude, reply_markup: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
|
||||||
types::{ChatId, InlineKeyboardMarkup, InputMedia, Message},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to edit animation, audio, document, photo, or video
|
|
||||||
/// 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. On
|
|
||||||
/// success, the edited [`Message`] is returned.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagemedia).
|
|
||||||
///
|
|
||||||
/// [`Message`]: crate::types::Message
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct EditMessageMedia {
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
message_id: i32,
|
|
||||||
media: InputMedia,
|
|
||||||
reply_markup: Option<InlineKeyboardMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for EditMessageMedia {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"editMessageMedia",
|
|
||||||
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(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EditMessageMedia {
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, InlineKeyboardMarkup, Message},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to edit only the reply markup of messages.
|
|
||||||
///
|
|
||||||
/// On success, the edited [`Message`] is returned.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagereplymarkup).
|
|
||||||
///
|
|
||||||
/// [`Message`]: crate::types::Message
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct EditMessageReplyMarkup {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
message_id: i32,
|
|
||||||
reply_markup: Option<InlineKeyboardMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for EditMessageReplyMarkup {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "editMessageReplyMarkup", &self)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EditMessageReplyMarkup {
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, InlineKeyboardMarkup, Message, ParseMode},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to edit text and game messages.
|
|
||||||
///
|
|
||||||
/// On success, the edited [`Message`] is returned.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#editmessagetext).
|
|
||||||
///
|
|
||||||
/// [`Message`]: crate::types::Message
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct EditMessageText {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
message_id: i32,
|
|
||||||
text: String,
|
|
||||||
parse_mode: Option<ParseMode>,
|
|
||||||
disable_web_page_preview: Option<bool>,
|
|
||||||
reply_markup: Option<InlineKeyboardMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for EditMessageText {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "editMessageText", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EditMessageText {
|
|
||||||
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_id,
|
|
||||||
message_id,
|
|
||||||
text,
|
|
||||||
parse_mode: None,
|
|
||||||
disable_web_page_preview: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::ChatId,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to generate a new invite link for a chat; any previously
|
|
||||||
/// generated link is revoked.
|
|
||||||
///
|
|
||||||
/// The bot must be an administrator in the chat for this to work and must have
|
|
||||||
/// the appropriate admin rights.
|
|
||||||
///
|
|
||||||
/// ## Note
|
|
||||||
/// Each administrator in a chat generates their own invite links. Bots can't
|
|
||||||
/// use invite links generated by other administrators. If you want your bot to
|
|
||||||
/// work with invite links, it will need to generate its own link using
|
|
||||||
/// [`Bot::export_chat_invite_link`] – after this the link will become available
|
|
||||||
/// to the bot via the [`Bot::get_chat`] method. If your bot needs to generate a
|
|
||||||
/// new invite link replacing its previous one, use
|
|
||||||
/// [`Bot::export_chat_invite_link`] again.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#exportchatinvitelink).
|
|
||||||
///
|
|
||||||
/// [`Bot::export_chat_invite_link`]: crate::Bot::export_chat_invite_link
|
|
||||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct ExportChatInviteLink {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for ExportChatInviteLink {
|
|
||||||
type Output = String;
|
|
||||||
|
|
||||||
/// Returns the new invite link as `String` on success.
|
|
||||||
async fn send(&self) -> ResponseResult<String> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "exportChatInviteLink", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExportChatInviteLink {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, Message},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to forward messages of any kind.
|
|
||||||
///
|
|
||||||
/// [`The official docs`](https://core.telegram.org/bots/api#forwardmessage).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct ForwardMessage {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
from_chat_id: ChatId,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
message_id: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for ForwardMessage {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "forwardMessage", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ForwardMessage {
|
|
||||||
pub(crate) fn new<C, F>(bot: Bot, chat_id: C, from_chat_id: F, message_id: i32) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
F: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
let from_chat_id = from_chat_id.into();
|
|
||||||
Self { bot, chat_id, from_chat_id, message_id, disable_notification: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the chat where the original message was sent (or
|
|
||||||
/// channel username in the format `@channelusername`).
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
|
||||||
pub fn from_chat_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ChatId>,
|
|
||||||
{
|
|
||||||
self.from_chat_id = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Message identifier in the chat specified in [`from_chat_id`].
|
|
||||||
///
|
|
||||||
/// [`from_chat_id`]: ForwardMessage::from_chat_id
|
|
||||||
pub fn message_id(mut self, val: i32) -> Self {
|
|
||||||
self.message_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{Chat, ChatId},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to get up to date information about the chat (current name
|
|
||||||
/// of the user for one-on-one conversations, current username of a user, group
|
|
||||||
/// or channel, etc.).
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getchat).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetChat {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetChat {
|
|
||||||
type Output = Chat;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Chat> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getChat", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetChat {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
|
||||||
/// supergroup or 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, ChatMember},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to get a list of administrators in a chat.
|
|
||||||
///
|
|
||||||
/// If the chat is a group or a supergroup and no administrators were appointed,
|
|
||||||
/// only the creator will be returned.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getchatadministrators).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetChatAdministrators {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetChatAdministrators {
|
|
||||||
type Output = Vec<ChatMember>;
|
|
||||||
|
|
||||||
/// On success, returns an array that contains information about all chat
|
|
||||||
/// administrators except other bots.
|
|
||||||
async fn send(&self) -> ResponseResult<Vec<ChatMember>> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getChatAdministrators", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetChatAdministrators {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
|
||||||
/// supergroup or 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, ChatMember},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to get information about a member of a chat.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getchatmember).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetChatMember {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
user_id: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetChatMember {
|
|
||||||
type Output = ChatMember;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<ChatMember> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getChatMember", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetChatMember {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, user_id: i32) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id, user_id }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
|
||||||
/// supergroup or 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier of the target user.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::ChatId,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to get the number of members in a chat.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getchatmemberscount).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetChatMembersCount {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetChatMembersCount {
|
|
||||||
type Output = i32;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<i32> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getChatMembersCount", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetChatMembersCount {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
|
||||||
/// supergroup or 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::File,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to get basic info about a file and prepare it for
|
|
||||||
/// downloading.
|
|
||||||
///
|
|
||||||
/// For the moment, bots can download files of up to `20MB` in size.
|
|
||||||
///
|
|
||||||
/// The file can then be downloaded via the link
|
|
||||||
/// `https://api.telegram.org/file/bot<token>/<file_path>`, where `<file_path>`
|
|
||||||
/// is taken from the response. It is guaranteed that the link will be valid
|
|
||||||
/// for at least `1` hour. When the link expires, a new one can be requested by
|
|
||||||
/// calling [`GetFile`] again.
|
|
||||||
///
|
|
||||||
/// **Note**: This function may not preserve the original file name and MIME
|
|
||||||
/// type. You should save the file's MIME type and name (if available) when the
|
|
||||||
/// [`File`] object is received.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getfile).
|
|
||||||
///
|
|
||||||
/// [`File`]: crate::types::File
|
|
||||||
/// [`GetFile`]: self::GetFile
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetFile {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
file_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetFile {
|
|
||||||
type Output = File;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<File> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getFile", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetFile {
|
|
||||||
pub(crate) fn new<F>(bot: Bot, file_id: F) -> Self
|
|
||||||
where
|
|
||||||
F: Into<String>,
|
|
||||||
{
|
|
||||||
Self { bot, file_id: file_id.into() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// File identifier to get info about.
|
|
||||||
pub fn file_id<F>(mut self, value: F) -> Self
|
|
||||||
where
|
|
||||||
F: Into<String>,
|
|
||||||
{
|
|
||||||
self.file_id = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{GameHighScore, TargetMessage},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to get data for high score tables.
|
|
||||||
///
|
|
||||||
/// Will return the score of the specified user and several of his neighbors in
|
|
||||||
/// a game.
|
|
||||||
///
|
|
||||||
/// ## Note
|
|
||||||
/// This method will currently return scores for the target user, plus two of
|
|
||||||
/// his closest neighbors on each side. Will also return the top three users if
|
|
||||||
/// 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)
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetGameHighScores {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
#[serde(flatten)]
|
|
||||||
target: TargetMessage,
|
|
||||||
user_id: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetGameHighScores {
|
|
||||||
type Output = Vec<GameHighScore>;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Vec<GameHighScore>> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getGameHighScores", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetGameHighScores {
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Target user id.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::Me,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
/// A simple method for testing your bot's auth token. Requires no parameters.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getme).
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetMe {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetMe {
|
|
||||||
type Output = Me;
|
|
||||||
|
|
||||||
/// Returns basic information about the bot.
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
|
||||||
async fn send(&self) -> ResponseResult<Me> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getMe", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetMe {
|
|
||||||
pub(crate) fn new(bot: Bot) -> Self {
|
|
||||||
Self { bot }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::BotCommand,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to get the current list of the bot's commands.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getmycommands).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetMyCommands {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetMyCommands {
|
|
||||||
type Output = Vec<BotCommand>;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Self::Output> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getMyCommands", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetMyCommands {
|
|
||||||
pub(crate) fn new(bot: Bot) -> Self {
|
|
||||||
Self { bot }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::StickerSet,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to get a sticker set.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getstickerset).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetStickerSet {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetStickerSet {
|
|
||||||
type Output = StickerSet;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<StickerSet> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getStickerSet", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetStickerSet {
|
|
||||||
pub(crate) fn new<N>(bot: Bot, name: N) -> Self
|
|
||||||
where
|
|
||||||
N: Into<String>,
|
|
||||||
{
|
|
||||||
let name = name.into();
|
|
||||||
Self { bot, name }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Name of the sticker set.
|
|
||||||
pub fn name<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.name = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,122 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{AllowedUpdate, Update},
|
|
||||||
Bot, RequestError,
|
|
||||||
};
|
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
/// Use this method to receive incoming updates using long polling ([wiki]).
|
|
||||||
///
|
|
||||||
/// **Notes:**
|
|
||||||
/// 1. This method will not work if an outgoing webhook is set up.
|
|
||||||
/// 2. In order to avoid getting duplicate updates,
|
|
||||||
/// recalculate offset after each server response.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getupdates).
|
|
||||||
///
|
|
||||||
/// [wiki]: https://en.wikipedia.org/wiki/Push_technology#Long_polling
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetUpdates {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
pub(crate) offset: Option<i32>,
|
|
||||||
pub(crate) limit: Option<u8>,
|
|
||||||
pub(crate) timeout: Option<u32>,
|
|
||||||
pub(crate) allowed_updates: Option<Vec<AllowedUpdate>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetUpdates {
|
|
||||||
type Output = Vec<Result<Update, (Value, serde_json::Error)>>;
|
|
||||||
|
|
||||||
/// Deserialize to `Vec<serde_json::Result<Update>>` instead of
|
|
||||||
/// `Vec<Update>`, because we want to parse the rest of updates even if our
|
|
||||||
/// library hasn't parsed one.
|
|
||||||
async fn send(&self) -> ResponseResult<Vec<Result<Update, (Value, serde_json::Error)>>> {
|
|
||||||
let value: Value =
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getUpdates", &self).await?;
|
|
||||||
|
|
||||||
match value {
|
|
||||||
Value::Array(array) => Ok(array
|
|
||||||
.into_iter()
|
|
||||||
.map(|value| Update::try_parse(&value).map_err(|error| (value, error)))
|
|
||||||
.collect()),
|
|
||||||
_ => Err(RequestError::InvalidJson(
|
|
||||||
serde_json::from_value::<Vec<Update>>(value)
|
|
||||||
.expect_err("get_update must return Value::Array"),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetUpdates {
|
|
||||||
pub(crate) fn new(bot: Bot) -> Self {
|
|
||||||
Self { bot, offset: None, limit: None, timeout: None, allowed_updates: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Identifier of the first update to be returned.
|
|
||||||
///
|
|
||||||
/// Must be greater by one than the highest among the identifiers of
|
|
||||||
/// previously received updates. By default, updates starting with the
|
|
||||||
/// earliest unconfirmed update are returned. An update is considered
|
|
||||||
/// confirmed as soon as [`GetUpdates`] is called with an [`offset`]
|
|
||||||
/// higher than its [`id`]. The negative offset can be specified to
|
|
||||||
/// retrieve updates starting from `-offset` update from the end of the
|
|
||||||
/// updates queue. All previous updates will forgotten.
|
|
||||||
///
|
|
||||||
/// [`GetUpdates`]: self::GetUpdates
|
|
||||||
/// [`offset`]: self::GetUpdates::offset
|
|
||||||
/// [`id`]: crate::types::Update::id
|
|
||||||
pub fn offset(mut self, value: i32) -> Self {
|
|
||||||
self.offset = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Limits the number of updates to be retrieved.
|
|
||||||
///
|
|
||||||
/// Values between `1`—`100` are accepted. Defaults to `100`.
|
|
||||||
pub fn limit(mut self, value: u8) -> Self {
|
|
||||||
self.limit = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Timeout in seconds for long polling.
|
|
||||||
///
|
|
||||||
/// Defaults to `0`, i.e. usual short polling. Should be positive, short
|
|
||||||
/// polling should be used for testing purposes only.
|
|
||||||
pub fn timeout(mut self, value: u32) -> Self {
|
|
||||||
self.timeout = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List the types of updates you want your bot to receive.
|
|
||||||
///
|
|
||||||
/// For example, specify [[`Message`], [`EditedChannelPost`],
|
|
||||||
/// [`CallbackQuery`]] to only receive updates of these types.
|
|
||||||
/// See [`AllowedUpdate`] for a complete list of available update types.
|
|
||||||
///
|
|
||||||
/// Specify an empty list to receive all updates regardless of type
|
|
||||||
/// (default). If not specified, the previous setting will be used.
|
|
||||||
///
|
|
||||||
/// **Note:**
|
|
||||||
/// This parameter doesn't affect updates created before the call to the
|
|
||||||
/// [`Bot::get_updates`], so unwanted updates may be received for a short
|
|
||||||
/// period of time.
|
|
||||||
///
|
|
||||||
/// [`Message`]: self::AllowedUpdate::Message
|
|
||||||
/// [`EditedChannelPost`]: self::AllowedUpdate::EditedChannelPost
|
|
||||||
/// [`CallbackQuery`]: self::AllowedUpdate::CallbackQuery
|
|
||||||
/// [`AllowedUpdate`]: self::AllowedUpdate
|
|
||||||
/// [`Bot::get_updates`]: crate::Bot::get_updates
|
|
||||||
pub fn allowed_updates<T>(mut self, value: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<Vec<AllowedUpdate>>,
|
|
||||||
{
|
|
||||||
self.allowed_updates = Some(value.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::UserProfilePhotos,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to get a list of profile pictures for a user.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getuserprofilephotos).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetUserProfilePhotos {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
user_id: i32,
|
|
||||||
offset: Option<i32>,
|
|
||||||
limit: Option<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetUserProfilePhotos {
|
|
||||||
type Output = UserProfilePhotos;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<UserProfilePhotos> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getUserProfilePhotos", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetUserProfilePhotos {
|
|
||||||
pub(crate) fn new(bot: Bot, user_id: i32) -> Self {
|
|
||||||
Self { bot, user_id, offset: None, limit: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier of the target user.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sequential number of the first photo to be returned. By default, all
|
|
||||||
/// photos are returned.
|
|
||||||
pub fn offset(mut self, val: i32) -> Self {
|
|
||||||
self.offset = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Limits the number of photos to be retrieved. Values between 1—100 are
|
|
||||||
/// accepted.
|
|
||||||
///
|
|
||||||
/// Defaults to 100.
|
|
||||||
pub fn limit(mut self, val: i32) -> Self {
|
|
||||||
self.limit = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::WebhookInfo,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to get current webhook status.
|
|
||||||
///
|
|
||||||
/// If the bot is using [`Bot::get_updates`], will return an object with the url
|
|
||||||
/// field empty.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getwebhookinfo).
|
|
||||||
///
|
|
||||||
/// [`Bot::get_updates`]: crate::Bot::get_updates
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct GetWebhookInfo {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for GetWebhookInfo {
|
|
||||||
type Output = WebhookInfo;
|
|
||||||
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
|
||||||
async fn send(&self) -> ResponseResult<WebhookInfo> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getWebhookInfo", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetWebhookInfo {
|
|
||||||
pub(crate) fn new(bot: Bot) -> Self {
|
|
||||||
Self { bot }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to kick a user from a group, a supergroup or a channel.
|
|
||||||
///
|
|
||||||
/// In the case of supergroups and channels, the user will not be able to return
|
|
||||||
/// to the group on their own using invite links, etc., unless [unbanned] first.
|
|
||||||
/// The bot must be an administrator in the chat for this to work and must have
|
|
||||||
/// the appropriate admin rights.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#kickchatmember).
|
|
||||||
///
|
|
||||||
/// [unbanned]: crate::Bot::unban_chat_member
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct KickChatMember {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
user_id: i32,
|
|
||||||
until_date: Option<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for KickChatMember {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "kickChatMember", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KickChatMember {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, user_id: i32) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id, user_id, until_date: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target group or username of the target
|
|
||||||
/// supergroup or 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier of the target user.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
|
||||||
pub fn until_date(mut self, val: i32) -> Self {
|
|
||||||
self.until_date = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method for your bot to leave a group, supergroup or channel.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#leavechat).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct LeaveChat {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for LeaveChat {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "leaveChat", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LeaveChat {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
|
||||||
/// supergroup or 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
mod add_sticker_to_set;
|
|
||||||
mod answer_callback_query;
|
|
||||||
mod answer_inline_query;
|
|
||||||
mod answer_pre_checkout_query;
|
|
||||||
mod answer_shipping_query;
|
|
||||||
mod create_new_sticker_set;
|
|
||||||
mod delete_chat_photo;
|
|
||||||
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;
|
|
||||||
mod edit_message_reply_markup;
|
|
||||||
mod edit_message_text;
|
|
||||||
mod export_chat_invite_link;
|
|
||||||
mod forward_message;
|
|
||||||
mod get_chat;
|
|
||||||
mod get_chat_administrators;
|
|
||||||
mod get_chat_member;
|
|
||||||
mod get_chat_members_count;
|
|
||||||
mod get_file;
|
|
||||||
mod get_game_high_scores;
|
|
||||||
mod get_me;
|
|
||||||
mod get_my_commands;
|
|
||||||
mod get_sticker_set;
|
|
||||||
mod get_updates;
|
|
||||||
mod get_user_profile_photos;
|
|
||||||
mod get_webhook_info;
|
|
||||||
mod kick_chat_member;
|
|
||||||
mod leave_chat;
|
|
||||||
mod pin_chat_message;
|
|
||||||
mod promote_chat_member;
|
|
||||||
mod restrict_chat_member;
|
|
||||||
mod send_animation;
|
|
||||||
mod send_audio;
|
|
||||||
mod send_chat_action;
|
|
||||||
mod send_contact;
|
|
||||||
mod send_dice;
|
|
||||||
mod send_document;
|
|
||||||
mod send_game;
|
|
||||||
mod send_invoice;
|
|
||||||
mod send_location;
|
|
||||||
mod send_media_group;
|
|
||||||
mod send_message;
|
|
||||||
mod send_photo;
|
|
||||||
mod send_poll;
|
|
||||||
mod send_sticker;
|
|
||||||
mod send_venue;
|
|
||||||
mod send_video;
|
|
||||||
mod send_video_note;
|
|
||||||
mod send_voice;
|
|
||||||
mod set_chat_administrator_custom_title;
|
|
||||||
mod set_chat_description;
|
|
||||||
mod set_chat_permissions;
|
|
||||||
mod set_chat_photo;
|
|
||||||
mod set_chat_sticker_set;
|
|
||||||
mod set_chat_title;
|
|
||||||
mod set_game_score;
|
|
||||||
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;
|
|
||||||
mod unpin_chat_message;
|
|
||||||
mod upload_sticker_file;
|
|
||||||
|
|
||||||
pub use add_sticker_to_set::*;
|
|
||||||
pub use answer_callback_query::*;
|
|
||||||
pub use answer_inline_query::*;
|
|
||||||
pub use answer_pre_checkout_query::*;
|
|
||||||
pub use answer_shipping_query::*;
|
|
||||||
pub use create_new_sticker_set::*;
|
|
||||||
pub use delete_chat_photo::*;
|
|
||||||
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::*;
|
|
||||||
pub use edit_message_reply_markup::*;
|
|
||||||
pub use edit_message_text::*;
|
|
||||||
pub use export_chat_invite_link::*;
|
|
||||||
pub use forward_message::*;
|
|
||||||
pub use get_chat::*;
|
|
||||||
pub use get_chat_administrators::*;
|
|
||||||
pub use get_chat_member::*;
|
|
||||||
pub use get_chat_members_count::*;
|
|
||||||
pub use get_file::*;
|
|
||||||
pub use get_game_high_scores::*;
|
|
||||||
pub use get_me::*;
|
|
||||||
pub use get_my_commands::*;
|
|
||||||
pub use get_sticker_set::*;
|
|
||||||
pub use get_updates::*;
|
|
||||||
pub use get_user_profile_photos::*;
|
|
||||||
pub use get_webhook_info::*;
|
|
||||||
pub use kick_chat_member::*;
|
|
||||||
pub use leave_chat::*;
|
|
||||||
pub use pin_chat_message::*;
|
|
||||||
pub use promote_chat_member::*;
|
|
||||||
pub use restrict_chat_member::*;
|
|
||||||
pub use send_animation::*;
|
|
||||||
pub use send_audio::*;
|
|
||||||
pub use send_chat_action::*;
|
|
||||||
pub use send_contact::*;
|
|
||||||
pub use send_dice::*;
|
|
||||||
pub use send_document::*;
|
|
||||||
pub use send_game::*;
|
|
||||||
pub use send_invoice::*;
|
|
||||||
pub use send_location::*;
|
|
||||||
pub use send_media_group::*;
|
|
||||||
pub use send_message::*;
|
|
||||||
pub use send_photo::*;
|
|
||||||
pub use send_poll::*;
|
|
||||||
pub use send_sticker::*;
|
|
||||||
pub use send_venue::*;
|
|
||||||
pub use send_video::*;
|
|
||||||
pub use send_video_note::*;
|
|
||||||
pub use send_voice::*;
|
|
||||||
pub use set_chat_administrator_custom_title::*;
|
|
||||||
pub use set_chat_description::*;
|
|
||||||
pub use set_chat_permissions::*;
|
|
||||||
pub use set_chat_photo::*;
|
|
||||||
pub use set_chat_sticker_set::*;
|
|
||||||
pub use set_chat_title::*;
|
|
||||||
pub use set_game_score::*;
|
|
||||||
pub use set_my_commands::*;
|
|
||||||
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::*;
|
|
||||||
pub use unpin_chat_message::*;
|
|
||||||
pub use upload_sticker_file::*;
|
|
|
@ -1,69 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to pin a message in a group, a supergroup, or a channel.
|
|
||||||
///
|
|
||||||
/// The bot must be an administrator in the chat for this to work and must have
|
|
||||||
/// the `can_pin_messages` admin right in the supergroup or `can_edit_messages`
|
|
||||||
/// admin right in the channel.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#pinchatmessage).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct PinChatMessage {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
message_id: i32,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for PinChatMessage {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "pinChatMessage", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PinChatMessage {
|
|
||||||
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, disable_notification: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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 a message to pin.
|
|
||||||
pub fn message_id(mut self, val: i32) -> Self {
|
|
||||||
self.message_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if it is not necessary to send a notification to all chat
|
|
||||||
/// members about the new pinned message.
|
|
||||||
///
|
|
||||||
/// Notifications are always disabled in channels.
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,134 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to promote or demote a user in a supergroup or a channel.
|
|
||||||
///
|
|
||||||
/// The bot must be an administrator in the chat for this to work and must have
|
|
||||||
/// the appropriate admin rights. Pass False for all boolean parameters to
|
|
||||||
/// demote a user.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#promotechatmember).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct PromoteChatMember {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
user_id: i32,
|
|
||||||
can_change_info: Option<bool>,
|
|
||||||
can_post_messages: Option<bool>,
|
|
||||||
can_edit_messages: Option<bool>,
|
|
||||||
can_delete_messages: Option<bool>,
|
|
||||||
can_invite_users: Option<bool>,
|
|
||||||
can_restrict_members: Option<bool>,
|
|
||||||
can_pin_messages: Option<bool>,
|
|
||||||
can_promote_members: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for PromoteChatMember {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "promoteChatMember", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PromoteChatMember {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, user_id: i32) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id,
|
|
||||||
user_id,
|
|
||||||
can_change_info: None,
|
|
||||||
can_post_messages: None,
|
|
||||||
can_edit_messages: None,
|
|
||||||
can_delete_messages: None,
|
|
||||||
can_invite_users: None,
|
|
||||||
can_restrict_members: None,
|
|
||||||
can_pin_messages: None,
|
|
||||||
can_promote_members: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier of the target user.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the administrator can change chat title, photo and other
|
|
||||||
/// settings.
|
|
||||||
pub fn can_change_info(mut self, val: bool) -> Self {
|
|
||||||
self.can_change_info = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the administrator can create channel posts, channels
|
|
||||||
/// only.
|
|
||||||
pub fn can_post_messages(mut self, val: bool) -> Self {
|
|
||||||
self.can_post_messages = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the administrator can edit messages of other users and
|
|
||||||
/// can pin messages, channels only.
|
|
||||||
pub fn can_edit_messages(mut self, val: bool) -> Self {
|
|
||||||
self.can_edit_messages = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the administrator can delete messages of other users.
|
|
||||||
pub fn can_delete_messages(mut self, val: bool) -> Self {
|
|
||||||
self.can_delete_messages = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the administrator can invite new users to the chat.
|
|
||||||
pub fn can_invite_users(mut self, val: bool) -> Self {
|
|
||||||
self.can_invite_users = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the administrator can restrict, ban or unban chat
|
|
||||||
/// members.
|
|
||||||
pub fn can_restrict_members(mut self, val: bool) -> Self {
|
|
||||||
self.can_restrict_members = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the administrator can pin messages, supergroups only.
|
|
||||||
pub fn can_pin_messages(mut self, val: bool) -> Self {
|
|
||||||
self.can_pin_messages = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the administrator 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 by him).
|
|
||||||
pub fn can_promote_members(mut self, val: bool) -> Self {
|
|
||||||
self.can_promote_members = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, ChatPermissions, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to restrict a user in a supergroup.
|
|
||||||
///
|
|
||||||
/// The bot must be an administrator in the supergroup for this to work and must
|
|
||||||
/// have the appropriate admin rights. Pass `true` for all permissions to lift
|
|
||||||
/// restrictions from a user.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#restrictchatmember).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct RestrictChatMember {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
user_id: i32,
|
|
||||||
permissions: ChatPermissions,
|
|
||||||
until_date: Option<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for RestrictChatMember {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "restrictChatMember", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RestrictChatMember {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, user_id: i32, permissions: ChatPermissions) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id, user_id, permissions, until_date: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
|
||||||
/// supergroup (in the format `@supergroupusername`).
|
|
||||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ChatId>,
|
|
||||||
{
|
|
||||||
self.chat_id = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier of the target user.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// New user permissions.
|
|
||||||
pub fn permissions(mut self, val: ChatPermissions) -> Self {
|
|
||||||
self.permissions = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Date when restrictions will be lifted for the user, unix time.
|
|
||||||
///
|
|
||||||
/// If user is restricted for more than 366 days or less than 30 seconds
|
|
||||||
/// from the current time, they are considered to be restricted forever.
|
|
||||||
pub fn until_date(mut self, val: i32) -> Self {
|
|
||||||
self.until_date = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,193 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, RequestWithFile, ResponseResult},
|
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send animation files (GIF or H.264/MPEG-4 AVC video
|
|
||||||
/// without sound).
|
|
||||||
///
|
|
||||||
/// Bots can currently send animation files of up to 50 MB in size, this limit
|
|
||||||
/// may be changed in the future.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendanimation).
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SendAnimation {
|
|
||||||
bot: Bot,
|
|
||||||
pub chat_id: ChatId,
|
|
||||||
pub animation: InputFile,
|
|
||||||
pub duration: Option<u32>,
|
|
||||||
pub width: Option<u32>,
|
|
||||||
pub height: Option<u32>,
|
|
||||||
pub thumb: Option<InputFile>,
|
|
||||||
pub caption: Option<String>,
|
|
||||||
pub parse_mode: Option<ParseMode>,
|
|
||||||
pub disable_notification: Option<bool>,
|
|
||||||
pub reply_to_message_id: Option<i32>,
|
|
||||||
pub reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl RequestWithFile for SendAnimation {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> tokio::io::Result<ResponseResult<Message>> {
|
|
||||||
let mut builder = FormBuilder::new()
|
|
||||||
.add_text("chat_id", &self.chat_id)
|
|
||||||
.add_input_file("animation", &self.animation)
|
|
||||||
.await?
|
|
||||||
.add_text("duration", &self.duration)
|
|
||||||
.add_text("width", &self.width)
|
|
||||||
.add_text("height", &self.height)
|
|
||||||
.add_text("caption", &self.caption)
|
|
||||||
.add_text("parse_mode", &self.parse_mode)
|
|
||||||
.add_text("disable_notification", &self.disable_notification)
|
|
||||||
.add_text("reply_to_message_id", &self.reply_to_message_id)
|
|
||||||
.add_text("reply_markup", &self.reply_markup);
|
|
||||||
if let Some(thumb) = self.thumb.as_ref() {
|
|
||||||
builder = builder.add_input_file("thumb", thumb).await?;
|
|
||||||
}
|
|
||||||
Ok(net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendAnimation",
|
|
||||||
builder.build(),
|
|
||||||
)
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendAnimation {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, animation: InputFile) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id: chat_id.into(),
|
|
||||||
animation,
|
|
||||||
duration: None,
|
|
||||||
width: None,
|
|
||||||
height: None,
|
|
||||||
thumb: None,
|
|
||||||
caption: None,
|
|
||||||
parse_mode: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target channel
|
|
||||||
/// (in the format `@channelusername`).
|
|
||||||
pub fn chat_id<T>(mut self, value: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ChatId>,
|
|
||||||
{
|
|
||||||
self.chat_id = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Animation to send.
|
|
||||||
///
|
|
||||||
/// Pass [`InputFile::FileId`] to send a file that exists on the Telegram
|
|
||||||
/// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a
|
|
||||||
/// file from the Internet (20MB max.), pass [`InputFile::File`] to upload
|
|
||||||
/// a file from the file system or [`InputFile::Memory`] to upload a file
|
|
||||||
/// from memory (50MB max. each). [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
|
||||||
/// [`InputFile::Url`]: crate::types::InputFile::Url
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn animation(mut self, val: InputFile) -> Self {
|
|
||||||
self.animation = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Duration of sent animation in seconds.
|
|
||||||
pub fn duration(mut self, value: u32) -> Self {
|
|
||||||
self.duration = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Animation width.
|
|
||||||
pub fn width(mut self, value: u32) -> Self {
|
|
||||||
self.width = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Animation height.
|
|
||||||
pub fn height(mut self, value: u32) -> Self {
|
|
||||||
self.height = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Thumbnail of the file sent; can be ignored if thumbnail generation for
|
|
||||||
/// the file is supported server-side.
|
|
||||||
///
|
|
||||||
/// The thumbnail should be in JPEG format and less than 200kB in size. A
|
|
||||||
/// thumbnail‘s width and height should not exceed 320. Ignored if the
|
|
||||||
/// animation is not uploaded using [`InputFile::File`] or
|
|
||||||
/// [`InputFile::Memory`]. Thumbnails can’t be reused and can be only
|
|
||||||
/// uploaded as a new file. Pass [`InputFile::File`] to upload a file from
|
|
||||||
/// the file system or [`InputFile::Memory`] to upload a file from memory.
|
|
||||||
/// [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn thumb(mut self, value: InputFile) -> Self {
|
|
||||||
self.thumb = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Animation caption, `0`-`1024` characters.
|
|
||||||
pub fn caption<T>(mut self, value: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.caption = Some(value.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, value: ParseMode) -> Self {
|
|
||||||
self.parse_mode = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message silently. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
pub fn disable_notification(mut self, value: bool) -> Self {
|
|
||||||
self.disable_notification = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, [id] of the original message.
|
|
||||||
///
|
|
||||||
/// [id]: crate::types::Message::id
|
|
||||||
pub fn reply_to_message_id(mut self, value: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
pub fn reply_markup<T>(mut self, value: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ReplyMarkup>,
|
|
||||||
{
|
|
||||||
self.reply_markup = Some(value.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,206 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, RequestWithFile, ResponseResult},
|
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send audio files, if you want Telegram clients to display
|
|
||||||
/// them in the music player.
|
|
||||||
///
|
|
||||||
/// Your audio must be in the .MP3 or .M4A format. Bots can currently send audio
|
|
||||||
/// files of up to 50 MB in size, this limit may be changed in the future.
|
|
||||||
///
|
|
||||||
/// For sending voice messages, use the [`Bot::send_voice`] method instead.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendaudio).
|
|
||||||
///
|
|
||||||
/// [`Bot::send_voice`]: crate::Bot::send_voice
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SendAudio {
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
audio: InputFile,
|
|
||||||
caption: Option<String>,
|
|
||||||
parse_mode: Option<ParseMode>,
|
|
||||||
duration: Option<i32>,
|
|
||||||
performer: Option<String>,
|
|
||||||
title: Option<String>,
|
|
||||||
thumb: Option<InputFile>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl RequestWithFile for SendAudio {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> tokio::io::Result<ResponseResult<Message>> {
|
|
||||||
let mut builder = FormBuilder::new()
|
|
||||||
.add_text("chat_id", &self.chat_id)
|
|
||||||
.add_input_file("audio", &self.audio)
|
|
||||||
.await?
|
|
||||||
.add_text("caption", &self.caption)
|
|
||||||
.add_text("parse_mode", &self.parse_mode)
|
|
||||||
.add_text("duration", &self.duration)
|
|
||||||
.add_text("performer", &self.performer)
|
|
||||||
.add_text("title", &self.title)
|
|
||||||
.add_text("disable_notification", &self.disable_notification)
|
|
||||||
.add_text("reply_to_message_id", &self.reply_to_message_id)
|
|
||||||
.add_text("reply_markup", &self.reply_markup);
|
|
||||||
if let Some(thumb) = self.thumb.as_ref() {
|
|
||||||
builder = builder.add_input_file("thumb", thumb).await?;
|
|
||||||
}
|
|
||||||
Ok(net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendAudio",
|
|
||||||
builder.build(),
|
|
||||||
)
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendAudio {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, audio: InputFile) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id: chat_id.into(),
|
|
||||||
audio,
|
|
||||||
caption: None,
|
|
||||||
parse_mode: None,
|
|
||||||
duration: None,
|
|
||||||
performer: None,
|
|
||||||
title: None,
|
|
||||||
thumb: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Audio file to send.
|
|
||||||
///
|
|
||||||
/// Pass [`InputFile::FileId`] to send an audio file that exists on the
|
|
||||||
/// Telegram servers (recommended), pass an [`InputFile::Url`] for Telegram
|
|
||||||
/// to get a file from the Internet (20MB max.), pass [`InputFile::File`]
|
|
||||||
/// to upload a file from the file system or [`InputFile::Memory`] to
|
|
||||||
/// upload a file from memory (50MB max. each).
|
|
||||||
/// [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
|
||||||
/// [`InputFile::Url`]: crate::types::InputFile::Url
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn audio(mut self, val: InputFile) -> Self {
|
|
||||||
self.audio = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Audio caption, 0-1024 characters.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Duration of the audio in seconds.
|
|
||||||
pub fn duration(mut self, val: i32) -> Self {
|
|
||||||
self.duration = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performer.
|
|
||||||
pub fn performer<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.performer = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Track name.
|
|
||||||
pub fn title<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.title = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Thumbnail of the file sent; can be ignored if thumbnail generation for
|
|
||||||
/// the file is supported server-side.
|
|
||||||
///
|
|
||||||
/// The thumbnail should be in JPEG format and less than 200kB in size. A
|
|
||||||
/// thumbnail‘s width and height should not exceed 320. Ignored if the
|
|
||||||
/// audio file is not uploaded using [`InputFile::File`] or
|
|
||||||
/// [`InputFile::Memory`]. Thumbnails can’t be reused and can be only
|
|
||||||
/// uploaded as a new file. Pass [`InputFile::File`] to upload a file from
|
|
||||||
/// the file system or [`InputFile::Memory`] to upload a file from memory.
|
|
||||||
/// [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn thumb(mut self, val: InputFile) -> Self {
|
|
||||||
self.thumb = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options. A JSON-serialized object for an [inline
|
|
||||||
/// keyboard], [custom reply keyboard], instructions to remove reply
|
|
||||||
/// keyboard or to force a reply from the user.
|
|
||||||
///
|
|
||||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method when you need to tell the user that something is happening
|
|
||||||
/// on the bot's side.
|
|
||||||
///
|
|
||||||
/// The status is set for 5 seconds or less (when a message arrives from your
|
|
||||||
/// bot, Telegram clients clear its typing status).
|
|
||||||
///
|
|
||||||
/// ## Note
|
|
||||||
/// Example: The [ImageBot] needs some time to process a request and upload the
|
|
||||||
/// image. Instead of sending a text message along the lines of “Retrieving
|
|
||||||
/// image, please wait…”, the bot may use [`Bot::send_chat_action`] with `action
|
|
||||||
/// = upload_photo`. The user will see a `sending photo` status for the bot.
|
|
||||||
///
|
|
||||||
/// We only recommend using this method when a response from the bot will take a
|
|
||||||
/// **noticeable** amount of time to arrive.
|
|
||||||
///
|
|
||||||
/// [ImageBot]: https://t.me/imagebot
|
|
||||||
/// [`Bot::send_chat_action`]: crate::Bot::send_chat_action
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SendChatAction {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
action: SendChatActionKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type of action used in [`SendChatAction`].
|
|
||||||
///
|
|
||||||
/// [`SendChatAction`]: crate::requests::SendChatAction
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum SendChatActionKind {
|
|
||||||
/// For [text messages](crate::Bot::send_message).
|
|
||||||
Typing,
|
|
||||||
|
|
||||||
/// For [photos](crate::Bot::send_photo).
|
|
||||||
UploadPhoto,
|
|
||||||
|
|
||||||
/// For [videos](crate::Bot::send_video).
|
|
||||||
RecordVideo,
|
|
||||||
|
|
||||||
/// For [videos](crate::Bot::send_video).
|
|
||||||
UploadVideo,
|
|
||||||
|
|
||||||
/// For [audio files](crate::Bot::send_audio).
|
|
||||||
RecordAudio,
|
|
||||||
|
|
||||||
/// For [audio files](crate::Bot::send_audio).
|
|
||||||
UploadAudio,
|
|
||||||
|
|
||||||
/// For [general files](crate::Bot::send_document).
|
|
||||||
UploadDocument,
|
|
||||||
|
|
||||||
/// For [location data](crate::Bot::send_location).
|
|
||||||
FindLocation,
|
|
||||||
|
|
||||||
/// For [video notes](crate::Bot::send_video_note).
|
|
||||||
RecordVideoNote,
|
|
||||||
|
|
||||||
/// For [video notes](crate::Bot::send_video_note).
|
|
||||||
UploadVideoNote,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SendChatAction {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "sendChatAction", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendChatAction {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, action: SendChatActionKind) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
Self { bot, chat_id: chat_id.into(), action }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Type of action to broadcast.
|
|
||||||
pub fn action(mut self, val: SendChatActionKind) -> Self {
|
|
||||||
self.action = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,129 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, Message, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send phone contacts.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendcontact).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SendContact {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
phone_number: String,
|
|
||||||
first_name: String,
|
|
||||||
last_name: Option<String>,
|
|
||||||
vcard: Option<String>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SendContact {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "sendContact", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendContact {
|
|
||||||
pub(crate) fn new<C, P, F>(bot: Bot, chat_id: C, phone_number: P, first_name: F) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
P: Into<String>,
|
|
||||||
F: Into<String>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
let phone_number = phone_number.into();
|
|
||||||
let first_name = first_name.into();
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id,
|
|
||||||
phone_number,
|
|
||||||
first_name,
|
|
||||||
last_name: None,
|
|
||||||
vcard: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Contact's phone number.
|
|
||||||
pub fn phone_number<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.phone_number = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Contact's first name.
|
|
||||||
pub fn first_name<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.first_name = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Contact's last name.
|
|
||||||
pub fn last_name<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.last_name = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional data about the contact in the form of a [vCard], 0-2048
|
|
||||||
/// bytes.
|
|
||||||
///
|
|
||||||
/// [vCard]: https://en.wikipedia.org/wiki/VCard
|
|
||||||
pub fn vcard<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.vcard = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, DiceEmoji, Message, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send an animated emoji that will display a random value.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#senddice).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SendDice {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
|
|
||||||
chat_id: ChatId,
|
|
||||||
#[serde(flatten)]
|
|
||||||
emoji: Option<DiceEmoji>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SendDice {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "sendDice", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendDice {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id: chat_id.into(),
|
|
||||||
emoji: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target channel
|
|
||||||
/// (in the format `@channelusername`).
|
|
||||||
pub fn chat_id<T>(mut self, value: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ChatId>,
|
|
||||||
{
|
|
||||||
self.chat_id = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Emoji on which the dice throw animation is based.
|
|
||||||
pub fn emoji(mut self, val: DiceEmoji) -> Self {
|
|
||||||
self.emoji = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, value: bool) -> Self {
|
|
||||||
self.disable_notification = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, value: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
///
|
|
||||||
/// A JSON-serialized object for an [inline keyboard], [custom reply
|
|
||||||
/// keyboard], instructions to remove reply keyboard or to force a reply
|
|
||||||
/// from the user.
|
|
||||||
///
|
|
||||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,163 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, RequestWithFile, ResponseResult},
|
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send general files.
|
|
||||||
///
|
|
||||||
/// Bots can currently send files of any type of up to 50 MB in size, this limit
|
|
||||||
/// may be changed in the future.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#senddocument).
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SendDocument {
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
document: InputFile,
|
|
||||||
thumb: Option<InputFile>,
|
|
||||||
caption: Option<String>,
|
|
||||||
parse_mode: Option<ParseMode>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl RequestWithFile for SendDocument {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> tokio::io::Result<ResponseResult<Message>> {
|
|
||||||
let mut builder = FormBuilder::new()
|
|
||||||
.add_text("chat_id", &self.chat_id)
|
|
||||||
.add_input_file("document", &self.document)
|
|
||||||
.await?
|
|
||||||
.add_text("caption", &self.caption)
|
|
||||||
.add_text("parse_mode", &self.parse_mode)
|
|
||||||
.add_text("disable_notification", &self.disable_notification)
|
|
||||||
.add_text("reply_to_message_id", &self.reply_to_message_id)
|
|
||||||
.add_text("reply_markup", &self.reply_markup);
|
|
||||||
if let Some(thumb) = self.thumb.as_ref() {
|
|
||||||
builder = builder.add_input_file("thumb", thumb).await?;
|
|
||||||
}
|
|
||||||
Ok(net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendDocument",
|
|
||||||
builder.build(),
|
|
||||||
)
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendDocument {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, document: InputFile) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id: chat_id.into(),
|
|
||||||
document,
|
|
||||||
thumb: None,
|
|
||||||
caption: None,
|
|
||||||
parse_mode: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// File to send.
|
|
||||||
///
|
|
||||||
/// Pass [`InputFile::FileId`] to send a file that exists on the Telegram
|
|
||||||
/// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a
|
|
||||||
/// file from the Internet (20MB max.), pass [`InputFile::File`] to upload
|
|
||||||
/// a file from the file system or [`InputFile::Memory`] to upload a file
|
|
||||||
/// from memory (50MB max. each). [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
|
||||||
/// [`InputFile::Url`]: crate::types::InputFile::Url
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn document(mut self, val: InputFile) -> Self {
|
|
||||||
self.document = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Thumbnail of the file sent; can be ignored if thumbnail generation for
|
|
||||||
/// the file is supported server-side.
|
|
||||||
///
|
|
||||||
/// The thumbnail should be in JPEG format and less than 200kB in size. A
|
|
||||||
/// thumbnail‘s width and height should not exceed 320. Ignored if the
|
|
||||||
/// document is not uploaded using [`InputFile::File`] or
|
|
||||||
/// [`InputFile::Memory`]. Thumbnails can’t be reused and can be only
|
|
||||||
/// uploaded as a new file. Pass [`InputFile::File`] to upload a file from
|
|
||||||
/// the file system or [`InputFile::Memory`] to upload a file from memory.
|
|
||||||
/// [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn thumb(mut self, val: InputFile) -> Self {
|
|
||||||
self.thumb = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Document caption (may also be used when resending documents by
|
|
||||||
/// `file_id`), 0-1024 characters.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{InlineKeyboardMarkup, Message},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send a game.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendgame).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SendGame {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: i32,
|
|
||||||
game_short_name: String,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<InlineKeyboardMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SendGame {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "sendGame", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendGame {
|
|
||||||
pub(crate) fn new<G>(bot: Bot, chat_id: i32, game_short_name: G) -> Self
|
|
||||||
where
|
|
||||||
G: Into<String>,
|
|
||||||
{
|
|
||||||
let game_short_name = game_short_name.into();
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id,
|
|
||||||
game_short_name,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat.
|
|
||||||
pub fn chat_id(mut self, val: i32) -> Self {
|
|
||||||
self.chat_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Short name of the game, serves as the unique identifier for the game.
|
|
||||||
/// Set up your games via [@Botfather].
|
|
||||||
///
|
|
||||||
/// [@Botfather]: https://t.me/botfather
|
|
||||||
pub fn game_short_name<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.game_short_name = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A JSON-serialized object for an [inline keyboard]. If empty, one `Play
|
|
||||||
/// game_title` button will be shown. If not empty, the first button must
|
|
||||||
/// launch the game.
|
|
||||||
///
|
|
||||||
/// [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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,299 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{InlineKeyboardMarkup, LabeledPrice, Message},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send invoices.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendinvoice).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SendInvoice {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: i32,
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
payload: String,
|
|
||||||
provider_token: String,
|
|
||||||
start_parameter: String,
|
|
||||||
currency: String,
|
|
||||||
prices: Vec<LabeledPrice>,
|
|
||||||
provider_data: Option<String>,
|
|
||||||
photo_url: Option<String>,
|
|
||||||
photo_size: Option<i32>,
|
|
||||||
photo_width: Option<i32>,
|
|
||||||
photo_height: Option<i32>,
|
|
||||||
need_name: Option<bool>,
|
|
||||||
need_phone_number: Option<bool>,
|
|
||||||
need_email: Option<bool>,
|
|
||||||
need_shipping_address: Option<bool>,
|
|
||||||
send_phone_number_to_provider: Option<bool>,
|
|
||||||
send_email_to_provider: Option<bool>,
|
|
||||||
is_flexible: Option<bool>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<InlineKeyboardMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SendInvoice {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "sendInvoice", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendInvoice {
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub(crate) fn new<T, D, Pl, Pt, S, C, Pr>(
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: i32,
|
|
||||||
title: T,
|
|
||||||
description: D,
|
|
||||||
payload: Pl,
|
|
||||||
provider_token: Pt,
|
|
||||||
start_parameter: S,
|
|
||||||
currency: C,
|
|
||||||
prices: Pr,
|
|
||||||
) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
D: Into<String>,
|
|
||||||
Pl: Into<String>,
|
|
||||||
Pt: Into<String>,
|
|
||||||
S: Into<String>,
|
|
||||||
C: Into<String>,
|
|
||||||
Pr: Into<Vec<LabeledPrice>>,
|
|
||||||
{
|
|
||||||
let title = title.into();
|
|
||||||
let description = description.into();
|
|
||||||
let payload = payload.into();
|
|
||||||
let provider_token = provider_token.into();
|
|
||||||
let start_parameter = start_parameter.into();
|
|
||||||
let currency = currency.into();
|
|
||||||
let prices = prices.into();
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
payload,
|
|
||||||
provider_token,
|
|
||||||
start_parameter,
|
|
||||||
currency,
|
|
||||||
prices,
|
|
||||||
provider_data: None,
|
|
||||||
photo_url: None,
|
|
||||||
photo_size: None,
|
|
||||||
photo_width: None,
|
|
||||||
photo_height: None,
|
|
||||||
need_name: None,
|
|
||||||
need_phone_number: None,
|
|
||||||
need_email: None,
|
|
||||||
need_shipping_address: None,
|
|
||||||
send_phone_number_to_provider: None,
|
|
||||||
send_email_to_provider: None,
|
|
||||||
is_flexible: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target private chat.
|
|
||||||
pub fn chat_id(mut self, val: i32) -> Self {
|
|
||||||
self.chat_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Product name, 1-32 characters.
|
|
||||||
pub fn title<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.title = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Product description, 1-255 characters.
|
|
||||||
pub fn description<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.description = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Bot-defined invoice payload, 1-128 bytes. This will not be displayed to
|
|
||||||
/// the user, use for your internal processes.
|
|
||||||
pub fn payload<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.payload = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Payments provider token, obtained via [@Botfather].
|
|
||||||
///
|
|
||||||
/// [@Botfather]: https://t.me/botfather
|
|
||||||
pub fn provider_token<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.provider_token = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique deep-linking parameter that can be used to generate this invoice
|
|
||||||
/// when used as a start parameter.
|
|
||||||
pub fn start_parameter<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.start_parameter = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Three-letter ISO 4217 currency code, see [more on currencies].
|
|
||||||
///
|
|
||||||
/// [more on currencies]: https://core.telegram.org/bots/payments#supported-currencies
|
|
||||||
pub fn currency<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.currency = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Price breakdown, a list of components (e.g. product price, tax,
|
|
||||||
/// discount, delivery cost, delivery tax, bonus, etc.).
|
|
||||||
pub fn prices<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<Vec<LabeledPrice>>,
|
|
||||||
{
|
|
||||||
self.prices = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// JSON-encoded data about the invoice, which will be shared with the
|
|
||||||
/// payment provider.
|
|
||||||
///
|
|
||||||
/// A detailed description of required fields should be provided by the
|
|
||||||
/// payment provider.
|
|
||||||
pub fn provider_data<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.provider_data = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// URL of the product photo for the invoice.
|
|
||||||
///
|
|
||||||
/// Can be a photo of the goods or a marketing image for a service. People
|
|
||||||
/// like it better when they see what they are paying for.
|
|
||||||
pub fn photo_url<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.photo_url = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Photo size.
|
|
||||||
pub fn photo_size(mut self, val: i32) -> Self {
|
|
||||||
self.photo_size = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Photo width.
|
|
||||||
pub fn photo_width(mut self, val: i32) -> Self {
|
|
||||||
self.photo_width = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Photo height.
|
|
||||||
pub fn photo_height(mut self, val: i32) -> Self {
|
|
||||||
self.photo_height = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if you require the user's full name to complete the order.
|
|
||||||
pub fn need_name(mut self, val: bool) -> Self {
|
|
||||||
self.need_name = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if you require the user's phone number to complete the
|
|
||||||
/// order.
|
|
||||||
pub fn need_phone_number(mut self, val: bool) -> Self {
|
|
||||||
self.need_phone_number = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if you require the user's email address to complete the
|
|
||||||
/// order.
|
|
||||||
pub fn need_email(mut self, val: bool) -> Self {
|
|
||||||
self.need_email = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if you require the user's shipping address to complete the
|
|
||||||
/// order.
|
|
||||||
pub fn need_shipping_address(mut self, val: bool) -> Self {
|
|
||||||
self.need_shipping_address = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if user's phone number should be sent to provider.
|
|
||||||
pub fn send_phone_number_to_provider(mut self, val: bool) -> Self {
|
|
||||||
self.send_phone_number_to_provider = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if user's email address should be sent to provider.
|
|
||||||
pub fn send_email_to_provider(mut self, val: bool) -> Self {
|
|
||||||
self.send_email_to_provider = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the final price depends on the shipping method.
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
|
||||||
pub fn is_flexible(mut self, val: bool) -> Self {
|
|
||||||
self.is_flexible = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A JSON-serialized object for an [inline keyboard].
|
|
||||||
///
|
|
||||||
/// If empty, one 'Pay `total price`' button will be shown. If not empty,
|
|
||||||
/// the first button must be a Pay button.
|
|
||||||
///
|
|
||||||
/// [inlint 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, Message, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send point on the map.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendlocation).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SendLocation {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
latitude: f32,
|
|
||||||
longitude: f32,
|
|
||||||
live_period: Option<i64>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SendLocation {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "sendLocation", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendLocation {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, latitude: f32, longitude: f32) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id,
|
|
||||||
latitude,
|
|
||||||
longitude,
|
|
||||||
live_period: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Latitude of the location.
|
|
||||||
pub fn latitude(mut self, val: f32) -> Self {
|
|
||||||
self.latitude = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Longitude of the location.
|
|
||||||
pub fn longitude(mut self, val: f32) -> Self {
|
|
||||||
self.longitude = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Period in seconds for which the location will be updated (see [Live
|
|
||||||
/// Locations], should be between 60 and 86400).
|
|
||||||
///
|
|
||||||
/// [Live Locations]: https://telegram.org/blog/live-locations
|
|
||||||
pub fn live_period(mut self, val: i64) -> Self {
|
|
||||||
self.live_period = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A JSON-serialized object for an [inline keyboard].
|
|
||||||
///
|
|
||||||
/// If empty, one 'Pay `total price`' button will be shown. If not empty,
|
|
||||||
/// the first button must be a Pay button.
|
|
||||||
///
|
|
||||||
/// [inlint keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
|
||||||
types::{ChatId, InputMedia, Message},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send a group of photos or videos as an album.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendmediagroup).
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SendMediaGroup {
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
media: Vec<InputMedia>, // TODO: InputMediaPhoto and InputMediaVideo
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SendMediaGroup {
|
|
||||||
type Output = Vec<Message>;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Vec<Message>> {
|
|
||||||
net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendMediaGroup",
|
|
||||||
FormBuilder::new()
|
|
||||||
.add_text("chat_id", &self.chat_id)
|
|
||||||
.add_text("media", &self.media)
|
|
||||||
.add_text("disable_notification", &self.disable_notification)
|
|
||||||
.add_text("reply_to_message_id", &self.reply_to_message_id)
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendMediaGroup {
|
|
||||||
pub(crate) fn new<C, M>(bot: Bot, chat_id: C, media: M) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
M: Into<Vec<InputMedia>>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
let media = media.into();
|
|
||||||
Self { bot, chat_id, media, disable_notification: None, reply_to_message_id: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A JSON-serialized array describing photos and videos to be sent, must
|
|
||||||
/// include 2–10 items.
|
|
||||||
pub fn media<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<Vec<InputMedia>>,
|
|
||||||
{
|
|
||||||
self.media = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the messages are a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,121 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, Message, ParseMode, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send text messages.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendmessage).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SendMessage {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
pub chat_id: ChatId,
|
|
||||||
pub text: String,
|
|
||||||
pub parse_mode: Option<ParseMode>,
|
|
||||||
pub disable_web_page_preview: Option<bool>,
|
|
||||||
pub disable_notification: Option<bool>,
|
|
||||||
pub reply_to_message_id: Option<i32>,
|
|
||||||
pub reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SendMessage {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "sendMessage", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendMessage {
|
|
||||||
pub(crate) fn new<C, T>(bot: Bot, chat_id: C, text: T) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id: chat_id.into(),
|
|
||||||
text: text.into(),
|
|
||||||
parse_mode: None,
|
|
||||||
disable_web_page_preview: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target channel
|
|
||||||
/// (in the format `@channelusername`).
|
|
||||||
pub fn chat_id<T>(mut self, value: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ChatId>,
|
|
||||||
{
|
|
||||||
self.chat_id = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Text of the message to be sent.
|
|
||||||
pub fn text<T>(mut self, value: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.text = value.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, value: ParseMode) -> Self {
|
|
||||||
self.parse_mode = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Disables link previews for links in this message.
|
|
||||||
pub fn disable_web_page_preview(mut self, value: bool) -> Self {
|
|
||||||
self.disable_web_page_preview = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, value: bool) -> Self {
|
|
||||||
self.disable_notification = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, value: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
///
|
|
||||||
/// A JSON-serialized object for an [inline keyboard], [custom reply
|
|
||||||
/// keyboard], instructions to remove reply keyboard or to force a reply
|
|
||||||
/// from the user.
|
|
||||||
///
|
|
||||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
|
|
||||||
pub fn reply_markup<T>(mut self, value: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ReplyMarkup>,
|
|
||||||
{
|
|
||||||
self.reply_markup = Some(value.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, RequestWithFile, ResponseResult},
|
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send photos.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendphoto).
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SendPhoto {
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
photo: InputFile,
|
|
||||||
caption: Option<String>,
|
|
||||||
parse_mode: Option<ParseMode>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl RequestWithFile for SendPhoto {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> tokio::io::Result<ResponseResult<Message>> {
|
|
||||||
Ok(net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendPhoto",
|
|
||||||
FormBuilder::new()
|
|
||||||
.add_text("chat_id", &self.chat_id)
|
|
||||||
.add_input_file("photo", &self.photo)
|
|
||||||
.await?
|
|
||||||
.add_text("caption", &self.caption)
|
|
||||||
.add_text("parse_mode", &self.parse_mode)
|
|
||||||
.add_text("disable_notification", &self.disable_notification)
|
|
||||||
.add_text("reply_to_message_id", &self.reply_to_message_id)
|
|
||||||
.add_text("reply_markup", &self.reply_markup)
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendPhoto {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, photo: InputFile) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id: chat_id.into(),
|
|
||||||
photo,
|
|
||||||
caption: None,
|
|
||||||
parse_mode: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Photo to send.
|
|
||||||
///
|
|
||||||
/// Pass [`InputFile::FileId`] to send a photo that exists on the Telegram
|
|
||||||
/// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a
|
|
||||||
/// photo from the Internet (5MB max.), pass [`InputFile::File`] to upload
|
|
||||||
/// a picture from the file system or [`InputFile::Memory`] to upload a
|
|
||||||
/// photo from memory (10MB max. each). [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
|
||||||
/// [`InputFile::Url`]: crate::types::InputFile::Url
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn photo(mut self, val: InputFile) -> Self {
|
|
||||||
self.photo = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
///Photo caption (may also be used when resending photos by file_id),
|
|
||||||
/// 0-1024 characters.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options. A JSON-serialized object for an [inline
|
|
||||||
/// keyboard], [custom reply keyboard], instructions to remove reply
|
|
||||||
/// keyboard or to force a reply from the user.
|
|
||||||
///
|
|
||||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,217 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, Message, ParseMode, PollType, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send a native poll.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendpoll).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SendPoll {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
question: String,
|
|
||||||
options: Vec<String>,
|
|
||||||
is_anonymous: Option<bool>,
|
|
||||||
poll_type: Option<PollType>,
|
|
||||||
allows_multiple_answers: Option<bool>,
|
|
||||||
correct_option_id: Option<i32>,
|
|
||||||
explanation: Option<String>,
|
|
||||||
explanation_parse_mode: Option<ParseMode>,
|
|
||||||
open_period: Option<i32>,
|
|
||||||
close_date: Option<i32>,
|
|
||||||
is_closed: Option<bool>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SendPoll {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "sendPoll", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendPoll {
|
|
||||||
pub(crate) fn new<C, Q, O>(bot: Bot, chat_id: C, question: Q, options: O) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
Q: Into<String>,
|
|
||||||
O: Into<Vec<String>>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
let question = question.into();
|
|
||||||
let options = options.into();
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id,
|
|
||||||
question,
|
|
||||||
options,
|
|
||||||
is_anonymous: None,
|
|
||||||
poll_type: None,
|
|
||||||
allows_multiple_answers: None,
|
|
||||||
correct_option_id: None,
|
|
||||||
explanation: None,
|
|
||||||
explanation_parse_mode: None,
|
|
||||||
is_closed: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
close_date: None,
|
|
||||||
open_period: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target channel
|
|
||||||
/// (in the format `@channelusername`).
|
|
||||||
///
|
|
||||||
/// A native poll can't be sent to a private chat.
|
|
||||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ChatId>,
|
|
||||||
{
|
|
||||||
self.chat_id = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Poll question, 1-255 characters.
|
|
||||||
pub fn question<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.question = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List of answer options, 2-10 strings 1-100 characters each.
|
|
||||||
pub fn options<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<Vec<String>>,
|
|
||||||
{
|
|
||||||
self.options = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `true`, if the poll needs to be anonymous, defaults to `true`.
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
|
||||||
pub fn is_anonymous<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<bool>,
|
|
||||||
{
|
|
||||||
self.is_anonymous = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Poll type, `quiz` or `regular`, defaults to `regular`.
|
|
||||||
pub fn poll_type(mut self, val: PollType) -> Self {
|
|
||||||
self.poll_type = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `true`, if the poll allows multiple answers, ignored for polls in quiz
|
|
||||||
/// mode.
|
|
||||||
///
|
|
||||||
/// Defaults to `false`.
|
|
||||||
pub fn allows_multiple_answers<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<bool>,
|
|
||||||
{
|
|
||||||
self.allows_multiple_answers = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 0-based identifier of the correct answer option, required for polls in
|
|
||||||
/// quiz mode.
|
|
||||||
pub fn correct_option_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<i32>,
|
|
||||||
{
|
|
||||||
self.correct_option_id = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Text that is shown when a user chooses an incorrect answer or taps on
|
|
||||||
/// the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line
|
|
||||||
/// feeds after entities parsing.
|
|
||||||
pub fn explanation<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.explanation = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mode for parsing entities in the explanation. See [formatting options]
|
|
||||||
/// for more details.
|
|
||||||
///
|
|
||||||
/// [formatting options]: https://core.telegram.org/bots/api#formatting-options
|
|
||||||
pub fn explanation_parse_mode(mut self, val: ParseMode) -> Self {
|
|
||||||
self.explanation_parse_mode = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Amount of time in seconds the poll will be active after creation, 5-600.
|
|
||||||
/// Can't be used together with `close_date`.
|
|
||||||
pub fn open_period(mut self, val: i32) -> Self {
|
|
||||||
self.open_period = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Point in time (Unix timestamp) when the poll will be automatically
|
|
||||||
/// closed. Must be at least 5 and no more than 600 seconds in the future.
|
|
||||||
/// Can't be used together with `open_period`.
|
|
||||||
pub fn close_date(mut self, val: i32) -> Self {
|
|
||||||
self.close_date = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the poll needs to be immediately closed.
|
|
||||||
///
|
|
||||||
/// This can be useful for poll preview.
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
|
||||||
pub fn is_closed<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<bool>,
|
|
||||||
{
|
|
||||||
self.is_closed = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently].
|
|
||||||
///
|
|
||||||
/// Users will receive a notification with no sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
///
|
|
||||||
/// A JSON-serialized object for an [inline keyboard], [custom reply
|
|
||||||
/// keyboard], instructions to remove reply keyboard or to force a reply
|
|
||||||
/// from the user.
|
|
||||||
///
|
|
||||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, RequestWithFile, ResponseResult},
|
|
||||||
types::{ChatId, InputFile, Message, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send static .WEBP or [animated] .TGS stickers.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendsticker).
|
|
||||||
///
|
|
||||||
/// [animated]: https://telegram.org/blog/animated-stickers
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SendSticker {
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
sticker: InputFile,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl RequestWithFile for SendSticker {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> tokio::io::Result<ResponseResult<Message>> {
|
|
||||||
Ok(net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendSticker",
|
|
||||||
FormBuilder::new()
|
|
||||||
.add_text("chat_id", &self.chat_id)
|
|
||||||
.add_input_file("sticker", &self.sticker)
|
|
||||||
.await?
|
|
||||||
.add_text("disable_notification", &self.disable_notification)
|
|
||||||
.add_text("reply_to_message_id", &self.reply_to_message_id)
|
|
||||||
.add_text("reply_markup", &self.reply_markup)
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendSticker {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, sticker: InputFile) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id: chat_id.into(),
|
|
||||||
sticker,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sticker to send.
|
|
||||||
///
|
|
||||||
/// Pass [`InputFile::FileId`] to send a sticker that exists on the
|
|
||||||
/// Telegram servers (recommended), pass an [`InputFile::Url`] for Telegram
|
|
||||||
/// to get a sticker (.WEBP file) from the Internet, pass
|
|
||||||
/// [`InputFile::File`] to upload a sticker from the file system or
|
|
||||||
/// [`InputFile::Memory`] to upload a sticker from memory
|
|
||||||
/// [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
|
||||||
/// [`InputFile::Url`]: crate::types::InputFile::Url
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn sticker(mut self, val: InputFile) -> Self {
|
|
||||||
self.sticker = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
///
|
|
||||||
/// A JSON-serialized object for an [inline keyboard], [custom reply
|
|
||||||
/// keyboard], instructions to remove reply keyboard or to force a reply
|
|
||||||
/// from the user.
|
|
||||||
///
|
|
||||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,159 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, Message, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send information about a venue.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendvenue).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SendVenue {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
latitude: f32,
|
|
||||||
longitude: f32,
|
|
||||||
title: String,
|
|
||||||
address: String,
|
|
||||||
foursquare_id: Option<String>,
|
|
||||||
foursquare_type: Option<String>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SendVenue {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "sendVenue", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendVenue {
|
|
||||||
pub(crate) fn new<C, T, A>(
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: C,
|
|
||||||
latitude: f32,
|
|
||||||
longitude: f32,
|
|
||||||
title: T,
|
|
||||||
address: A,
|
|
||||||
) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
T: Into<String>,
|
|
||||||
A: Into<String>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
let title = title.into();
|
|
||||||
let address = address.into();
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id,
|
|
||||||
latitude,
|
|
||||||
longitude,
|
|
||||||
title,
|
|
||||||
address,
|
|
||||||
foursquare_id: None,
|
|
||||||
foursquare_type: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Latitude of the venue.
|
|
||||||
pub fn latitude(mut self, val: f32) -> Self {
|
|
||||||
self.latitude = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Longitude of the venue.
|
|
||||||
pub fn longitude(mut self, val: f32) -> Self {
|
|
||||||
self.longitude = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Name of the venue.
|
|
||||||
pub fn title<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.title = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Address of the venue.
|
|
||||||
pub fn address<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.address = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Foursquare identifier of the venue.
|
|
||||||
pub fn foursquare_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.foursquare_id = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Foursquare type of the venue, if known.
|
|
||||||
///
|
|
||||||
/// For example, `arts_entertainment/default`, `arts_entertainment/aquarium`
|
|
||||||
/// or `food/icecream`.
|
|
||||||
pub fn foursquare_type<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.foursquare_type = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
///
|
|
||||||
/// A JSON-serialized object for an [inline keyboard], [custom reply
|
|
||||||
/// keyboard], instructions to remove reply keyboard or to force a reply
|
|
||||||
/// from the user.
|
|
||||||
///
|
|
||||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,207 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, RequestWithFile, ResponseResult},
|
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send video files, Telegram clients support mp4 videos
|
|
||||||
/// (other formats may be sent as Document).
|
|
||||||
///
|
|
||||||
/// Bots can currently send video files of up to 50 MB in size, this
|
|
||||||
/// limit may be changed in the future.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendvideo).
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SendVideo {
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
video: InputFile,
|
|
||||||
duration: Option<i32>,
|
|
||||||
width: Option<i32>,
|
|
||||||
height: Option<i32>,
|
|
||||||
thumb: Option<InputFile>,
|
|
||||||
caption: Option<String>,
|
|
||||||
parse_mode: Option<ParseMode>,
|
|
||||||
supports_streaming: Option<bool>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl RequestWithFile for SendVideo {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> tokio::io::Result<ResponseResult<Message>> {
|
|
||||||
let mut builder = FormBuilder::new()
|
|
||||||
.add_text("chat_id", &self.chat_id)
|
|
||||||
.add_input_file("video", &self.video)
|
|
||||||
.await?
|
|
||||||
.add_text("duration", &self.duration)
|
|
||||||
.add_text("width", &self.width)
|
|
||||||
.add_text("height", &self.height)
|
|
||||||
.add_text("caption", &self.caption)
|
|
||||||
.add_text("parse_mode", &self.parse_mode)
|
|
||||||
.add_text("supports_streaming", &self.supports_streaming)
|
|
||||||
.add_text("disable_notification", &self.disable_notification)
|
|
||||||
.add_text("reply_to_message_id", &self.reply_to_message_id)
|
|
||||||
.add_text("reply_markup", &self.reply_markup);
|
|
||||||
if let Some(thumb) = self.thumb.as_ref() {
|
|
||||||
builder = builder.add_input_file("thumb", thumb).await?;
|
|
||||||
}
|
|
||||||
Ok(net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendVideo",
|
|
||||||
builder.build(),
|
|
||||||
)
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendVideo {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, video: InputFile) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id: chat_id.into(),
|
|
||||||
video,
|
|
||||||
duration: None,
|
|
||||||
width: None,
|
|
||||||
height: None,
|
|
||||||
thumb: None,
|
|
||||||
caption: None,
|
|
||||||
parse_mode: None,
|
|
||||||
supports_streaming: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Video to send.
|
|
||||||
///
|
|
||||||
/// Pass [`InputFile::FileId`] to send a file that exists on the Telegram
|
|
||||||
/// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a
|
|
||||||
/// file from the Internet (20MB max.), pass [`InputFile::File`] to upload
|
|
||||||
/// a file from the file system or [`InputFile::Memory`] to upload a file
|
|
||||||
/// from memory (50MB max. each). [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
|
||||||
/// [`InputFile::Url`]: crate::types::InputFile::Url
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn video(mut self, val: InputFile) -> Self {
|
|
||||||
self.video = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Duration of sent video in seconds.
|
|
||||||
pub fn duration(mut self, val: i32) -> Self {
|
|
||||||
self.duration = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Video width.
|
|
||||||
pub fn width(mut self, val: i32) -> Self {
|
|
||||||
self.width = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Video height.
|
|
||||||
pub fn height(mut self, val: i32) -> Self {
|
|
||||||
self.height = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Thumbnail of the file sent; can be ignored if thumbnail generation for
|
|
||||||
/// the file is supported server-side.
|
|
||||||
///
|
|
||||||
/// The thumbnail should be in JPEG format and less than 200kB in size. A
|
|
||||||
/// thumbnail‘s width and height should not exceed 320. Ignored if the
|
|
||||||
/// video file is not uploaded using [`InputFile::File`] or
|
|
||||||
/// [`InputFile::Memory`]. Thumbnails can’t be reused and can be only
|
|
||||||
/// uploaded as a new file. Pass [`InputFile::File`] to upload a file from
|
|
||||||
/// the file system or [`InputFile::Memory`] to upload a file from memory.
|
|
||||||
/// [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn thumb(mut self, val: InputFile) -> Self {
|
|
||||||
self.thumb = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Video caption (may also be used when resending videos by file_id),
|
|
||||||
/// 0-1024 characters.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the uploaded video is suitable for streaming.
|
|
||||||
pub fn supports_streaming(mut self, val: bool) -> Self {
|
|
||||||
self.supports_streaming = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
///
|
|
||||||
/// A JSON-serialized object for an [inline keyboard], [custom reply
|
|
||||||
/// keyboard], instructions to remove reply keyboard or to force a reply
|
|
||||||
/// from the user.
|
|
||||||
///
|
|
||||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,160 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, RequestWithFile, ResponseResult},
|
|
||||||
types::{ChatId, InputFile, Message, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// As of [v.4.0], Telegram clients support rounded square mp4 videos of up to 1
|
|
||||||
/// minute long. Use this method to send video messages.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendvideonote).
|
|
||||||
///
|
|
||||||
/// [v.4.0]: https://telegram.org/blog/video-messages-and-telescope
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SendVideoNote {
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
video_note: InputFile,
|
|
||||||
duration: Option<i32>,
|
|
||||||
length: Option<i32>,
|
|
||||||
thumb: Option<InputFile>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl RequestWithFile for SendVideoNote {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> tokio::io::Result<ResponseResult<Message>> {
|
|
||||||
let mut builder = FormBuilder::new()
|
|
||||||
.add_text("chat_id", &self.chat_id)
|
|
||||||
.add_input_file("video_note", &self.video_note)
|
|
||||||
.await?
|
|
||||||
.add_text("duration", &self.duration)
|
|
||||||
.add_text("length", &self.length)
|
|
||||||
.add_text("disable_notification", &self.disable_notification)
|
|
||||||
.add_text("reply_to_message_id", &self.reply_to_message_id)
|
|
||||||
.add_text("reply_markup", &self.reply_markup);
|
|
||||||
if let Some(thumb) = self.thumb.as_ref() {
|
|
||||||
builder = builder.add_input_file("thumb", thumb).await?;
|
|
||||||
}
|
|
||||||
Ok(net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendVideoNote",
|
|
||||||
builder.build(),
|
|
||||||
)
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendVideoNote {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, video_note: InputFile) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id: chat_id.into(),
|
|
||||||
video_note,
|
|
||||||
duration: None,
|
|
||||||
length: None,
|
|
||||||
thumb: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Video note to send.
|
|
||||||
///
|
|
||||||
/// Pass [`InputFile::FileId`] to send a file that exists on the Telegram
|
|
||||||
/// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a
|
|
||||||
/// file from the Internet (20MB max.), pass [`InputFile::File`] to upload
|
|
||||||
/// a file from the file system or [`InputFile::Memory`] to upload a file
|
|
||||||
/// from memory (50MB max. each). [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
|
||||||
/// [`InputFile::Url`]: crate::types::InputFile::Url
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn video_note(mut self, val: InputFile) -> Self {
|
|
||||||
self.video_note = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Duration of sent video in seconds.
|
|
||||||
pub fn duration(mut self, val: i32) -> Self {
|
|
||||||
self.duration = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Video width and height, i.e. diameter of the video message.
|
|
||||||
pub fn length(mut self, val: i32) -> Self {
|
|
||||||
self.length = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Thumbnail of the file sent; can be ignored if thumbnail generation for
|
|
||||||
/// the file is supported server-side.
|
|
||||||
///
|
|
||||||
/// The thumbnail should be in JPEG format and less than 200kB in size. A
|
|
||||||
/// thumbnail‘s width and height should not exceed 320. Ignored if the
|
|
||||||
/// video note is not uploaded using [`InputFile::File`] or
|
|
||||||
/// [`InputFile::Memory`]. Thumbnails can’t be reused and can be only
|
|
||||||
/// uploaded as a new file. Pass [`InputFile::File`] to upload a file from
|
|
||||||
/// the file system or [`InputFile::Memory`] to upload a file from memory.
|
|
||||||
/// [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn thumb(mut self, val: InputFile) -> Self {
|
|
||||||
self.thumb = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
///
|
|
||||||
/// A JSON-serialized object for an [inline keyboard], [custom reply
|
|
||||||
/// keyboard], instructions to remove reply keyboard or to force a reply
|
|
||||||
/// from the user.
|
|
||||||
///
|
|
||||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,159 +0,0 @@
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{form_builder::FormBuilder, RequestWithFile, ResponseResult},
|
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to send audio files, if you want Telegram clients to display
|
|
||||||
/// the file as a playable voice message.
|
|
||||||
///
|
|
||||||
/// For this to work, your audio must be in an .ogg file encoded with OPUS
|
|
||||||
/// (other formats may be sent as [`Audio`] or [`Document`]). Bots can currently
|
|
||||||
/// send voice messages of up to 50 MB in size, this limit may be changed in the
|
|
||||||
/// future.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendvoice).
|
|
||||||
///
|
|
||||||
/// [`Audio`]: crate::types::Audio
|
|
||||||
/// [`Document`]: crate::types::Document
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SendVoice {
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
voice: InputFile,
|
|
||||||
caption: Option<String>,
|
|
||||||
parse_mode: Option<ParseMode>,
|
|
||||||
duration: Option<i32>,
|
|
||||||
disable_notification: Option<bool>,
|
|
||||||
reply_to_message_id: Option<i32>,
|
|
||||||
reply_markup: Option<ReplyMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl RequestWithFile for SendVoice {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> tokio::io::Result<ResponseResult<Message>> {
|
|
||||||
Ok(net::request_multipart(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendVoice",
|
|
||||||
FormBuilder::new()
|
|
||||||
.add_text("chat_id", &self.chat_id)
|
|
||||||
.add_input_file("voice", &self.voice)
|
|
||||||
.await?
|
|
||||||
.add_text("caption", &self.caption)
|
|
||||||
.add_text("parse_mode", &self.parse_mode)
|
|
||||||
.add_text("duration", &self.duration)
|
|
||||||
.add_text("disable_notification", &self.disable_notification)
|
|
||||||
.add_text("reply_to_message_id", &self.reply_to_message_id)
|
|
||||||
.add_text("reply_markup", &self.reply_markup)
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendVoice {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, voice: InputFile) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_id: chat_id.into(),
|
|
||||||
voice,
|
|
||||||
caption: None,
|
|
||||||
parse_mode: None,
|
|
||||||
duration: None,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Audio file to send.
|
|
||||||
///
|
|
||||||
/// Pass [`InputFile::FileId`] to send a file that exists on the Telegram
|
|
||||||
/// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a
|
|
||||||
/// file from the Internet (20MB max.), pass [`InputFile::File`] to upload
|
|
||||||
/// a file from the file system or [`InputFile::Memory`] to upload a file
|
|
||||||
/// from memory (50MB max. each). [More info on Sending Files »].
|
|
||||||
///
|
|
||||||
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
|
||||||
/// [`InputFile::Url`]: crate::types::InputFile::Url
|
|
||||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
|
||||||
/// [`InputFile::Memory`]: crate::types::InputFile::Memory
|
|
||||||
///
|
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
|
||||||
pub fn voice(mut self, val: InputFile) -> Self {
|
|
||||||
self.voice = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Voice message caption, 0-1024 characters.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Duration of the voice message in seconds.
|
|
||||||
pub fn duration(mut self, val: i32) -> Self {
|
|
||||||
self.duration = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_notification(mut self, val: bool) -> Self {
|
|
||||||
self.disable_notification = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the message is a reply, ID of the original message.
|
|
||||||
pub fn reply_to_message_id(mut self, val: i32) -> Self {
|
|
||||||
self.reply_to_message_id = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional interface options.
|
|
||||||
///
|
|
||||||
/// A JSON-serialized object for an [inline keyboard], [custom reply
|
|
||||||
/// keyboard], instructions to remove reply keyboard or to force a reply
|
|
||||||
/// from the user.
|
|
||||||
///
|
|
||||||
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
|
||||||
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
|
|
||||||
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
|
|
||||||
self.reply_markup = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to set a custom title for an administrator in a supergroup
|
|
||||||
/// promoted by the bot.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchatadministratorcustomtitle).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetChatAdministratorCustomTitle {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
user_id: i32,
|
|
||||||
custom_title: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetChatAdministratorCustomTitle {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"setChatAdministratorCustomTitle",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetChatAdministratorCustomTitle {
|
|
||||||
pub(crate) fn new<C, CT>(bot: Bot, chat_id: C, user_id: i32, custom_title: CT) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
CT: Into<String>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
let custom_title = custom_title.into();
|
|
||||||
Self { bot, chat_id, user_id, custom_title }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier of the target user.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// New custom title for the administrator; 0-16 characters, emoji are not
|
|
||||||
/// allowed.
|
|
||||||
pub fn custom_title<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.custom_title = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to change the description of a group, a supergroup or a
|
|
||||||
/// channel.
|
|
||||||
///
|
|
||||||
/// The bot must be an administrator in the chat for this to work and must have
|
|
||||||
/// the appropriate admin rights.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchatdescription).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetChatDescription {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
description: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetChatDescription {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "setChatDescription", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetChatDescription {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id, description: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// New chat description, 0-255 characters.
|
|
||||||
pub fn description<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.description = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, ChatPermissions, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to set default chat permissions for all members.
|
|
||||||
///
|
|
||||||
/// The bot must be an administrator in the group or a supergroup for this to
|
|
||||||
/// work and must have the can_restrict_members admin rights.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchatpermissions).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetChatPermissions {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
permissions: ChatPermissions,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetChatPermissions {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "sendChatPermissions", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetChatPermissions {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, permissions: ChatPermissions) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id, permissions }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
|
||||||
/// supergroup (in the format `@supergroupusername`).
|
|
||||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ChatId>,
|
|
||||||
{
|
|
||||||
self.chat_id = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// New default chat permissions.
|
|
||||||
pub fn permissions(mut self, val: ChatPermissions) -> Self {
|
|
||||||
self.permissions = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, InputFile, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to set a new profile photo for the chat.
|
|
||||||
///
|
|
||||||
/// Photos can't be changed for private chats. The bot must be an administrator
|
|
||||||
/// in the chat for this to work and must have the appropriate admin rights.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchatphoto).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetChatPhoto {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
photo: InputFile,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetChatPhoto {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "setChatPhoto", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetChatPhoto {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, chat_id: C, photo: InputFile) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
Self { bot, chat_id, photo }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// New chat photo, uploaded using `multipart/form-data`.
|
|
||||||
pub fn photo(mut self, val: InputFile) -> Self {
|
|
||||||
self.photo = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to set a new group sticker set for a supergroup.
|
|
||||||
///
|
|
||||||
/// The bot must be an administrator in the chat for this to work and must have
|
|
||||||
/// the appropriate admin rights. Use the field can_set_sticker_set optionally
|
|
||||||
/// returned in getChat requests to check if the bot can use this method.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchatstickerset).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetChatStickerSet {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
sticker_set_name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetChatStickerSet {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "setChatStickerSet", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetChatStickerSet {
|
|
||||||
pub(crate) fn new<C, S>(bot: Bot, chat_id: C, sticker_set_name: S) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
S: Into<String>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
let sticker_set_name = sticker_set_name.into();
|
|
||||||
Self { bot, chat_id, sticker_set_name }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
|
||||||
/// supergroup (in the format `@supergroupusername`).
|
|
||||||
pub fn chat_id<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<ChatId>,
|
|
||||||
{
|
|
||||||
self.chat_id = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Name of the sticker set to be set as the group sticker set.
|
|
||||||
pub fn sticker_set_name<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.sticker_set_name = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to change the title of a chat.
|
|
||||||
///
|
|
||||||
/// Titles can't be changed for private chats. The bot must be an administrator
|
|
||||||
/// in the chat for this to work and must have the appropriate admin rights.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchattitle).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetChatTitle {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
title: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetChatTitle {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "setChatTitle", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetChatTitle {
|
|
||||||
pub(crate) fn new<C, T>(bot: Bot, chat_id: C, title: T) -> Self
|
|
||||||
where
|
|
||||||
C: Into<ChatId>,
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
let chat_id = chat_id.into();
|
|
||||||
let title = title.into();
|
|
||||||
Self { bot, chat_id, title }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// New chat title, 1-255 characters.
|
|
||||||
pub fn title<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.title = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{Message, TargetMessage},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to set the score of the specified user in a game.
|
|
||||||
///
|
|
||||||
/// On success, if the message was sent by the bot, returns the edited
|
|
||||||
/// [`Message`], otherwise returns [`True`]. Returns an error, if the new score
|
|
||||||
/// is not greater than the user's current score in the chat and force is
|
|
||||||
/// `false`.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setgamescore).
|
|
||||||
///
|
|
||||||
/// [`Message`]: crate::types::Message
|
|
||||||
/// [`True`]: crate::types::True
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetGameScore {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
#[serde(flatten)]
|
|
||||||
target: TargetMessage,
|
|
||||||
user_id: i32,
|
|
||||||
score: i32,
|
|
||||||
force: Option<bool>,
|
|
||||||
disable_edit_message: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetGameScore {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "setGameScore", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetGameScore {
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// User identifier.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// New score, must be non-negative.
|
|
||||||
pub fn score(mut self, val: i32) -> Self {
|
|
||||||
self.score = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pass `true`, if the high score is allowed to decrease.
|
|
||||||
///
|
|
||||||
/// This can be useful when fixing mistakes or banning cheaters.
|
|
||||||
pub fn force(mut self, val: bool) -> Self {
|
|
||||||
self.force = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends the message [silently]. Users will receive a notification with no
|
|
||||||
/// sound.
|
|
||||||
///
|
|
||||||
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
|
|
||||||
pub fn disable_edit_message(mut self, val: bool) -> Self {
|
|
||||||
self.disable_edit_message = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{BotCommand, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to change the list of the bot's commands.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setmycommands).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetMyCommands {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
|
|
||||||
commands: Vec<BotCommand>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetMyCommands {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Self::Output> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "setMyCommands", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetMyCommands {
|
|
||||||
pub(crate) fn new<C>(bot: Bot, commands: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<Vec<BotCommand>>,
|
|
||||||
{
|
|
||||||
Self { bot, commands: commands.into() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A JSON-serialized list of bot commands to be set as the list of the
|
|
||||||
/// bot's commands.
|
|
||||||
///
|
|
||||||
/// At most 100 commands can be specified.
|
|
||||||
pub fn commands<C>(mut self, commands: C) -> Self
|
|
||||||
where
|
|
||||||
C: Into<Vec<BotCommand>>,
|
|
||||||
{
|
|
||||||
self.commands = commands.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::True,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to move a sticker in a set created by the bot to a specific
|
|
||||||
/// position.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setstickerpositioninset).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetStickerPositionInSet {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
sticker: String,
|
|
||||||
position: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetStickerPositionInSet {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "setStickerPositionInSet", &self)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetStickerPositionInSet {
|
|
||||||
pub(crate) fn new<S>(bot: Bot, sticker: S, position: i32) -> Self
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
{
|
|
||||||
let sticker = sticker.into();
|
|
||||||
Self { bot, sticker, position }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// File identifier of the sticker.
|
|
||||||
pub fn sticker<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.sticker = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// New sticker position in the set, zero-based.
|
|
||||||
pub fn position(mut self, val: i32) -> Self {
|
|
||||||
self.position = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{InputFile, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to set the thumbnail of a sticker set. Animated thumbnails
|
|
||||||
/// can be set for animated sticker sets only.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setstickersetthumb).
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetStickerSetThumb {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
name: String,
|
|
||||||
user_id: i32,
|
|
||||||
thumb: Option<InputFile>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetStickerSetThumb {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Self::Output> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "setStickerSetThumb", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetStickerSetThumb {
|
|
||||||
pub(crate) fn new<S>(bot: Bot, name: S, user_id: i32) -> Self
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
{
|
|
||||||
Self { bot, name: name.into(), user_id, thumb: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sticker set name.
|
|
||||||
pub fn name<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.name = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// User identifier of the sticker set owner.
|
|
||||||
pub fn user_id(mut self, val: i32) -> Self {
|
|
||||||
self.user_id = val;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A PNG image with the thumbnail, must be up to 128 kilobytes in size and
|
|
||||||
/// have width and height exactly 100px, or a TGS animation with the
|
|
||||||
/// thumbnail up to 32 kilobytes in size; see https://core.telegram.org/animated_stickers#technical-requirements
|
|
||||||
/// for animated sticker technical requirements.
|
|
||||||
///
|
|
||||||
/// Pass [`InputFile::FileId`] to send a file that exists on the Telegram
|
|
||||||
/// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a
|
|
||||||
/// file from the Internet (20MB max.), pass [`InputFile::File`] to upload
|
|
||||||
/// a file from the file system or [`InputFile::Memory`] to upload a file
|
|
||||||
/// from memory (50MB max. each). [More info on Sending Files »]. Animated
|
|
||||||
/// sticker set thumbnail can't be uploaded via HTTP URL.
|
|
||||||
///
|
|
||||||
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
|
||||||
/// [`InputFile::Url]: crate::types::InputFile::Url
|
|
||||||
pub fn thumb(mut self, val: InputFile) -> Self {
|
|
||||||
self.thumb = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{AllowedUpdate, InputFile, True},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to specify a url and receive incoming updates via an
|
|
||||||
/// outgoing webhook.
|
|
||||||
///
|
|
||||||
/// Whenever there is an update for the bot, we will send an
|
|
||||||
/// HTTPS POST request to the specified url, containing a JSON-serialized
|
|
||||||
/// [`Update`]. In case of an unsuccessful request, we will give up after a
|
|
||||||
/// reasonable amount of attempts.
|
|
||||||
///
|
|
||||||
/// If you'd like to make sure that the Webhook request comes from Telegram,
|
|
||||||
/// we recommend using a secret path in the URL, e.g.
|
|
||||||
/// `https://www.example.com/<token>`. Since nobody else knows your bot‘s
|
|
||||||
/// token, you can be pretty sure it’s us.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setwebhook).
|
|
||||||
///
|
|
||||||
/// [`Update`]: crate::types::Update
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct SetWebhook {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
url: String,
|
|
||||||
certificate: Option<InputFile>,
|
|
||||||
max_connections: Option<i32>,
|
|
||||||
allowed_updates: Option<Vec<AllowedUpdate>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for SetWebhook {
|
|
||||||
type Output = True;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "setWebhook", &self).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetWebhook {
|
|
||||||
pub(crate) fn new<U>(bot: Bot, url: U) -> Self
|
|
||||||
where
|
|
||||||
U: Into<String>,
|
|
||||||
{
|
|
||||||
let url = url.into();
|
|
||||||
Self { bot, url, certificate: None, max_connections: None, allowed_updates: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HTTPS url to send updates to.
|
|
||||||
///
|
|
||||||
/// Use an empty string to remove webhook integration.
|
|
||||||
pub fn url<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.url = val.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Upload your public key certificate so that the root certificate in use
|
|
||||||
/// can be checked.
|
|
||||||
///
|
|
||||||
/// See our [self-signed guide] for details.
|
|
||||||
///
|
|
||||||
/// [self-signed guide]: https://core.telegram.org/bots/self-signed
|
|
||||||
pub fn certificate(mut self, val: InputFile) -> Self {
|
|
||||||
self.certificate = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Maximum allowed number of simultaneous HTTPS connections to the webhook
|
|
||||||
/// for update delivery, 1-100.
|
|
||||||
///
|
|
||||||
/// Defaults to 40. Use lower values to limit the load on your bot‘s server,
|
|
||||||
/// and higher values to increase your bot’s throughput.
|
|
||||||
pub fn max_connections(mut self, val: i32) -> Self {
|
|
||||||
self.max_connections = Some(val);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List the types of updates you want your bot to receive.
|
|
||||||
///
|
|
||||||
/// For example, specify [`AllowedUpdate::Message`],
|
|
||||||
/// [`AllowedUpdate::EditedChannelPost`], [`AllowedUpdate::CallbackQuery`]
|
|
||||||
/// to only receive updates of these types. Specify an empty list to receive
|
|
||||||
/// all updates regardless of type (default). If not specified, the
|
|
||||||
/// previous setting will be used. See [`AllowedUpdate`] for a complete list
|
|
||||||
/// of available update types.
|
|
||||||
///
|
|
||||||
/// Please note that this parameter doesn't affect updates created before
|
|
||||||
/// the call to the [`Bot::set_webhook`], so unwanted updates may be
|
|
||||||
/// received for a short period of time.
|
|
||||||
///
|
|
||||||
/// [`Bot::set_webhook`]: crate::Bot::set_webhook
|
|
||||||
/// [`AllowedUpdate::Message`]: crate::types::AllowedUpdate::Message
|
|
||||||
/// [`AllowedUpdate::EditedChannelPost`]:
|
|
||||||
/// crate::types::AllowedUpdate::EditedChannelPost
|
|
||||||
/// [`AllowedUpdate::CallbackQuery`]:
|
|
||||||
/// crate::types::AllowedUpdate::CallbackQuery
|
|
||||||
/// [`AllowedUpdate`]: crate::types::AllowedUpdate
|
|
||||||
pub fn allowed_updates<T>(mut self, val: T) -> Self
|
|
||||||
where
|
|
||||||
T: Into<Vec<AllowedUpdate>>,
|
|
||||||
{
|
|
||||||
self.allowed_updates = Some(val.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
net,
|
|
||||||
requests::{Request, ResponseResult},
|
|
||||||
types::{ChatId, InlineKeyboardMarkup, Message},
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Use this method to stop updating a live location message before
|
|
||||||
/// `live_period` expires.
|
|
||||||
///
|
|
||||||
/// On success, the sent [`Message`] is returned.
|
|
||||||
///
|
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#stopmessagelivelocation).
|
|
||||||
///
|
|
||||||
/// [`Message`]: crate::types::Message
|
|
||||||
#[serde_with_macros::skip_serializing_none]
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
|
||||||
pub struct StopMessageLiveLocation {
|
|
||||||
#[serde(skip_serializing)]
|
|
||||||
bot: Bot,
|
|
||||||
chat_id: ChatId,
|
|
||||||
message_id: i32,
|
|
||||||
reply_markup: Option<InlineKeyboardMarkup>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Request for StopMessageLiveLocation {
|
|
||||||
type Output = Message;
|
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "stopMessageLiveLocation", &self)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StopMessageLiveLocation {
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue