use crate::filters::base::{Filter, FilterResult, Update};
pub struct DocumentAll;
impl Filter for DocumentAll {
fn check_update(&self, update: &Update) -> FilterResult {
if update
.effective_message()
.and_then(|m| m.document.as_ref())
.is_some()
{
FilterResult::Match
} else {
FilterResult::NoMatch
}
}
fn name(&self) -> &str {
"filters.Document.ALL"
}
}
pub struct DocumentCategory {
category: String,
display: String,
}
impl DocumentCategory {
pub fn new(category: impl Into<String>) -> Self {
let cat: String = category.into();
let display = format!("filters.Document.Category('{}')", cat);
Self {
category: cat,
display,
}
}
}
impl Filter for DocumentCategory {
fn check_update(&self, update: &Update) -> FilterResult {
let matched = update
.effective_message()
.and_then(|m| m.document.as_ref())
.and_then(|d| d.mime_type.as_deref())
.map(|mime| mime.starts_with(&self.category))
.unwrap_or(false);
if matched {
FilterResult::Match
} else {
FilterResult::NoMatch
}
}
fn name(&self) -> &str {
&self.display
}
}
pub struct DocumentFileExtension {
extension: Option<String>,
case_sensitive: bool,
display: String,
}
impl DocumentFileExtension {
pub fn new(extension: Option<&str>, case_sensitive: bool) -> Self {
let (ext, display) = match extension {
None => (None, "filters.Document.FileExtension(None)".to_owned()),
Some(e) => {
let stored = if case_sensitive {
format!(".{}", e)
} else {
format!(".{}", e).to_lowercase()
};
let display = if case_sensitive {
format!(
"filters.Document.FileExtension({:?}, case_sensitive=true)",
e
)
} else {
format!("filters.Document.FileExtension({:?})", e.to_lowercase())
};
(Some(stored), display)
}
};
Self {
extension: ext,
case_sensitive,
display,
}
}
}
impl Filter for DocumentFileExtension {
fn check_update(&self, update: &Update) -> FilterResult {
let doc = match update.effective_message().and_then(|m| m.document.as_ref()) {
Some(d) => d,
None => return FilterResult::NoMatch,
};
let file_name = match doc.file_name.as_deref() {
Some(n) => n,
None => return FilterResult::NoMatch,
};
let matched = match &self.extension {
None => !file_name.contains('.'),
Some(ext) => {
let name = if self.case_sensitive {
file_name.to_owned()
} else {
file_name.to_lowercase()
};
name.ends_with(ext.as_str())
}
};
if matched {
FilterResult::Match
} else {
FilterResult::NoMatch
}
}
fn name(&self) -> &str {
&self.display
}
}
pub struct DocumentMimeType {
mimetype: String,
display: String,
}
impl DocumentMimeType {
pub fn new(mimetype: impl Into<String>) -> Self {
let mt: String = mimetype.into();
let display = format!("filters.Document.MimeType('{}')", mt);
Self {
mimetype: mt,
display,
}
}
}
impl Filter for DocumentMimeType {
fn check_update(&self, update: &Update) -> FilterResult {
let matched = update
.effective_message()
.and_then(|m| m.document.as_ref())
.and_then(|d| d.mime_type.as_deref())
.map(|mime| mime == self.mimetype)
.unwrap_or(false);
if matched {
FilterResult::Match
} else {
FilterResult::NoMatch
}
}
fn name(&self) -> &str {
&self.display
}
}
pub mod presets {
use super::*;
pub const ALL: DocumentAll = DocumentAll;
pub fn application() -> DocumentCategory {
DocumentCategory::new("application/")
}
pub fn audio() -> DocumentCategory {
DocumentCategory::new("audio/")
}
pub fn image() -> DocumentCategory {
DocumentCategory::new("image/")
}
pub fn video() -> DocumentCategory {
DocumentCategory::new("video/")
}
pub fn text() -> DocumentCategory {
DocumentCategory::new("text/")
}
pub fn apk() -> DocumentMimeType {
DocumentMimeType::new("application/vnd.android.package-archive")
}
pub fn doc() -> DocumentMimeType {
DocumentMimeType::new("application/msword")
}
pub fn docx() -> DocumentMimeType {
DocumentMimeType::new(
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
)
}
pub fn exe() -> DocumentMimeType {
DocumentMimeType::new("application/x-msdos-program")
}
pub fn gif() -> DocumentMimeType {
DocumentMimeType::new("image/gif")
}
pub fn jpg() -> DocumentMimeType {
DocumentMimeType::new("image/jpeg")
}
pub fn mp3() -> DocumentMimeType {
DocumentMimeType::new("audio/mpeg")
}
pub fn mp4() -> DocumentMimeType {
DocumentMimeType::new("video/mp4")
}
pub fn pdf() -> DocumentMimeType {
DocumentMimeType::new("application/pdf")
}
pub fn py() -> DocumentMimeType {
DocumentMimeType::new("text/x-python")
}
pub fn svg() -> DocumentMimeType {
DocumentMimeType::new("image/svg+xml")
}
pub fn txt() -> DocumentMimeType {
DocumentMimeType::new("text/plain")
}
pub fn targz() -> DocumentMimeType {
DocumentMimeType::new("application/x-compressed-tar")
}
pub fn wav() -> DocumentMimeType {
DocumentMimeType::new("audio/x-wav")
}
pub fn xml() -> DocumentMimeType {
DocumentMimeType::new("text/xml")
}
pub fn zip() -> DocumentMimeType {
DocumentMimeType::new("application/zip")
}
}
pub use presets as document;
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn doc_update(mime: &str, file_name: &str) -> Update {
serde_json::from_value(json!({
"update_id": 1,
"message": {
"message_id": 1, "date": 0,
"chat": {"id": 1, "type": "private"},
"document": {
"file_id": "f1", "file_unique_id": "u1",
"mime_type": mime, "file_name": file_name
}
}
}))
.unwrap()
}
#[test]
fn document_all() {
assert!(DocumentAll
.check_update(&doc_update("application/pdf", "test.pdf"))
.is_match());
}
#[test]
fn document_all_no_doc() {
let update: Update = serde_json::from_value(json!({
"update_id": 1,
"message": {"message_id": 1, "date": 0, "chat": {"id": 1, "type": "private"}, "text": "hi"}
})).unwrap();
assert!(!DocumentAll.check_update(&update).is_match());
}
#[test]
fn document_category_audio() {
let f = DocumentCategory::new("audio/");
assert!(f
.check_update(&doc_update("audio/mpeg", "song.mp3"))
.is_match());
assert!(!f
.check_update(&doc_update("video/mp4", "vid.mp4"))
.is_match());
}
#[test]
fn document_mime_type() {
let f = DocumentMimeType::new("application/pdf");
assert!(f
.check_update(&doc_update("application/pdf", "doc.pdf"))
.is_match());
assert!(!f
.check_update(&doc_update("application/zip", "arc.zip"))
.is_match());
}
#[test]
fn document_file_extension() {
let f = DocumentFileExtension::new(Some("pdf"), false);
assert!(f
.check_update(&doc_update("application/pdf", "report.PDF"))
.is_match());
assert!(!f
.check_update(&doc_update("application/pdf", "report.docx"))
.is_match());
}
#[test]
fn document_file_extension_case_sensitive() {
let f = DocumentFileExtension::new(Some("PDF"), true);
assert!(f
.check_update(&doc_update("application/pdf", "report.PDF"))
.is_match());
assert!(!f
.check_update(&doc_update("application/pdf", "report.pdf"))
.is_match());
}
#[test]
fn document_file_extension_none() {
let f = DocumentFileExtension::new(None, false);
assert!(f
.check_update(&doc_update("application/octet-stream", "Dockerfile"))
.is_match());
assert!(!f
.check_update(&doc_update("application/pdf", "test.pdf"))
.is_match());
}
#[test]
fn document_namespace_shortcuts() {
let pdf = document::pdf();
assert!(pdf
.check_update(&doc_update("application/pdf", "x.pdf"))
.is_match());
let mp3 = document::mp3();
assert!(mp3
.check_update(&doc_update("audio/mpeg", "song.mp3"))
.is_match());
}
}