use crate::types::{chat::ChatId, primitive::Integer};
use serde::{Deserialize, Serialize};
use std::{error::Error, fmt};
const MIN_NAME_LEN: usize = 1;
const MAX_NAME_LEN: usize = 32;
const MIN_DESCRIPTION_LEN: usize = 3;
const MAX_DESCRIPTION_LEN: usize = 256;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BotCommand {
command: String,
description: String,
}
impl BotCommand {
pub fn new<C, D>(name: C, description: D) -> Result<Self, BotCommandError>
where
C: Into<String>,
D: Into<String>,
{
let name = name.into();
let description = description.into();
let name_len = name.len();
let description_len = description.len();
if !(MIN_NAME_LEN..=MAX_NAME_LEN).contains(&name_len) {
Err(BotCommandError::BadNameLen(name_len))
} else if !(MIN_DESCRIPTION_LEN..=MAX_DESCRIPTION_LEN).contains(&description_len) {
Err(BotCommandError::BadDescriptionLen(description_len))
} else {
Ok(Self {
command: name,
description,
})
}
}
pub fn name(&self) -> &str {
&self.command
}
pub fn description(&self) -> &str {
&self.description
}
}
#[derive(Debug)]
pub enum BotCommandError {
BadNameLen(usize),
BadDescriptionLen(usize),
}
impl Error for BotCommandError {}
impl fmt::Display for BotCommandError {
fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
use self::BotCommandError::*;
match self {
BadNameLen(len) => write!(
out,
"command name can have a length of {} up to {} characters, got {}",
MIN_NAME_LEN, MAX_NAME_LEN, len
),
BadDescriptionLen(len) => write!(
out,
"command description can have a length of {} up to {} characters, got {}",
MIN_DESCRIPTION_LEN, MAX_DESCRIPTION_LEN, len
),
}
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
pub enum BotCommandScope {
Default,
AllPrivateChats,
AllGroupChats,
AllChatAdministrators,
Chat {
chat_id: ChatId,
},
ChatAdministrators {
chat_id: ChatId,
},
ChatMember {
chat_id: ChatId,
user_id: Integer,
},
}
impl BotCommandScope {
pub fn chat<T>(value: T) -> Self
where
T: Into<ChatId>,
{
Self::Chat { chat_id: value.into() }
}
pub fn chat_administrators<T>(value: T) -> Self
where
T: Into<ChatId>,
{
Self::ChatAdministrators { chat_id: value.into() }
}
pub fn chat_member<A>(chat_id: A, user_id: Integer) -> Self
where
A: Into<ChatId>,
{
Self::ChatMember {
chat_id: chat_id.into(),
user_id,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::Value as JsonValue;
#[test]
fn new_bot_command() {
let err = BotCommand::new("", "description").unwrap_err().to_string();
assert_eq!(err, "command name can have a length of 1 up to 32 characters, got 0");
let err = BotCommand::new("2".repeat(33), "description").unwrap_err().to_string();
assert_eq!(err, "command name can have a length of 1 up to 32 characters, got 33");
let err = BotCommand::new("name", "d").unwrap_err().to_string();
assert_eq!(
err,
"command description can have a length of 3 up to 256 characters, got 1"
);
let err = BotCommand::new("name", "d".repeat(257)).unwrap_err().to_string();
assert_eq!(
err,
"command description can have a length of 3 up to 256 characters, got 257"
);
}
#[test]
fn bot_command_scope() {
for (scope, scope_type) in [
(BotCommandScope::Default, "default"),
(BotCommandScope::AllPrivateChats, "all_private_chats"),
(BotCommandScope::AllGroupChats, "all_group_chats"),
(BotCommandScope::AllChatAdministrators, "all_chat_administrators"),
(BotCommandScope::chat(1), "chat"),
(BotCommandScope::chat_administrators(1), "chat_administrators"),
(BotCommandScope::chat_member(1, 1), "chat_member"),
] {
let serialized_scope = serde_json::to_string(&scope).unwrap();
let value: JsonValue = serde_json::from_str(&serialized_scope).unwrap();
assert_eq!(value["type"], scope_type);
let parsed_scope: BotCommandScope = serde_json::from_value(value).unwrap();
assert_eq!(scope, parsed_scope);
}
}
}