Compare commits
No commits in common. "ec49ab24b663d1cd1bf4c1f4be0caff38f9fb06d" and "03e42c910889b0dc979d3947b615f79f15e6231a" have entirely different histories.
ec49ab24b6
...
03e42c9108
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
.env
|
.env
|
||||||
result
|
result
|
||||||
**/.DS_Store
|
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -839,11 +839,9 @@ dependencies = [
|
|||||||
"enum_stringify",
|
"enum_stringify",
|
||||||
"envconfig",
|
"envconfig",
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
|
||||||
"mongodb",
|
"mongodb",
|
||||||
"serde",
|
"serde",
|
||||||
"teloxide",
|
"teloxide",
|
||||||
"thiserror 2.0.12",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -14,13 +14,7 @@ dotenvy = "0.15.7"
|
|||||||
enum_stringify = "0.6.3"
|
enum_stringify = "0.6.3"
|
||||||
envconfig = "0.11.0"
|
envconfig = "0.11.0"
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
log = "0.4.27"
|
|
||||||
mongodb = "3.2.3"
|
mongodb = "3.2.3"
|
||||||
serde = { version = "1.0.219", features = ["derive", "serde_derive"] }
|
serde = { version = "1.0.219", features = ["derive", "serde_derive"] }
|
||||||
teloxide = { version = "0.14.0", features = ["macros", "postgres-storage-nativetls"] }
|
teloxide = { version = "0.14.0", features = ["macros", "postgres-storage-nativetls"] }
|
||||||
thiserror = "2.0.12"
|
|
||||||
tokio = { version = "1.44.1", features = ["rt-multi-thread", "macros"] }
|
tokio = { version = "1.44.1", features = ["rt-multi-thread", "macros"] }
|
||||||
|
|
||||||
[lints.clippy]
|
|
||||||
print_stdout = "warn"
|
|
||||||
unwrap_used = "warn"
|
|
||||||
|
|||||||
45
src/admin.rs
45
src/admin.rs
@ -3,12 +3,8 @@ use teloxide::{
|
|||||||
utils::{command::BotCommands, render::RenderMessageTextHelper},
|
utils::{command::BotCommands, render::RenderMessageTextHelper},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::db::{CallDB, DB};
|
||||||
use crate::LogMsg;
|
use crate::LogMsg;
|
||||||
use crate::{
|
|
||||||
db::{CallDB, DB},
|
|
||||||
BotResult,
|
|
||||||
};
|
|
||||||
use log::info;
|
|
||||||
|
|
||||||
// These are should not appear in /help
|
// These are should not appear in /help
|
||||||
#[derive(BotCommands, Clone)]
|
#[derive(BotCommands, Clone)]
|
||||||
@ -34,15 +30,9 @@ pub async fn admin_command_handler(
|
|||||||
bot: Bot,
|
bot: Bot,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
cmd: AdminCommands,
|
cmd: AdminCommands,
|
||||||
) -> BotResult<()> {
|
) -> Result<(), teloxide::RequestError> {
|
||||||
let tguser = match msg.from.clone() {
|
let tguser = msg.from.clone().unwrap();
|
||||||
Some(user) => user,
|
println!("MSG: {}", msg.html_text().unwrap());
|
||||||
None => return Ok(()), // do nothing, cause its not usecase of function
|
|
||||||
};
|
|
||||||
info!(
|
|
||||||
"MSG: {}",
|
|
||||||
msg.html_text().unwrap_or("|EMPTY_MESSAGE|".into())
|
|
||||||
);
|
|
||||||
match cmd {
|
match cmd {
|
||||||
AdminCommands::MyId => {
|
AdminCommands::MyId => {
|
||||||
bot.send_message(msg.chat.id, format!("Your ID is: {}", tguser.id))
|
bot.send_message(msg.chat.id, format!("Your ID is: {}", tguser.id))
|
||||||
@ -64,7 +54,7 @@ pub async fn admin_command_handler(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
AdminCommands::Deop => {
|
AdminCommands::Deop => {
|
||||||
db.set_admin(tguser.id.0 as i64, false).await?;
|
db.set_admin(tguser.id.0 as i64, false).await;
|
||||||
bot.send_message(msg.chat.id, "You are not an admin anymore")
|
bot.send_message(msg.chat.id, "You are not an admin anymore")
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -79,27 +69,22 @@ pub async fn secret_command_handler(
|
|||||||
msg: Message,
|
msg: Message,
|
||||||
cmd: SecretCommands,
|
cmd: SecretCommands,
|
||||||
admin_password: String,
|
admin_password: String,
|
||||||
) -> BotResult<()> {
|
) -> Result<(), teloxide::RequestError> {
|
||||||
info!("Admin Pass: {}", admin_password);
|
println!("Admin Pass: {}", admin_password);
|
||||||
let tguser = match msg.from.clone() {
|
let tguser = msg.from.clone().unwrap();
|
||||||
Some(user) => user,
|
|
||||||
None => return Ok(()), // do nothing, cause its not usecase of function
|
|
||||||
};
|
|
||||||
let user = db
|
let user = db
|
||||||
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
|
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
|
||||||
.await?;
|
.await;
|
||||||
info!(
|
println!("MSG: {}", msg.html_text().unwrap());
|
||||||
"MSG: {}",
|
|
||||||
msg.html_text().unwrap_or("|EMPTY_MESSAGE|".into())
|
|
||||||
);
|
|
||||||
match cmd {
|
match cmd {
|
||||||
SecretCommands::Secret { pass } => {
|
SecretCommands::Secret { pass } => {
|
||||||
if user.is_admin {
|
if user.is_admin == true {
|
||||||
bot.send_message(tguser.id, "You are an admin already")
|
bot.send_message(msg.from.unwrap().id, "You are an admin already")
|
||||||
.await?;
|
.await?;
|
||||||
} else if pass == admin_password {
|
} else if pass == admin_password {
|
||||||
db.set_admin(user.id, true).await?;
|
db.set_admin(user.id, true).await;
|
||||||
bot.send_message(tguser.id, "You are an admin now!").await?;
|
bot.send_message(msg.from.unwrap().id, "You are an admin now!")
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
109
src/db/mod.rs
109
src/db/mod.rs
@ -1,7 +1,7 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use enum_stringify::EnumStringify;
|
use enum_stringify::EnumStringify;
|
||||||
use futures::stream::TryStreamExt;
|
use futures::stream::{StreamExt, TryStreamExt};
|
||||||
|
|
||||||
use mongodb::options::IndexOptions;
|
use mongodb::options::IndexOptions;
|
||||||
use mongodb::{bson::doc, options::ClientOptions, Client};
|
use mongodb::{bson::doc, options::ClientOptions, Client};
|
||||||
@ -38,7 +38,7 @@ pub struct User {
|
|||||||
macro_rules! query_call {
|
macro_rules! query_call {
|
||||||
($func_name:ident, $self:ident, $db:ident, $return_type:ty, $body:block) => {
|
($func_name:ident, $self:ident, $db:ident, $return_type:ty, $body:block) => {
|
||||||
pub async fn $func_name<D: CallDB>(&$self, $db: &mut D)
|
pub async fn $func_name<D: CallDB>(&$self, $db: &mut D)
|
||||||
-> DbResult<$return_type> $body
|
-> Result<$return_type, Box<dyn std::error::Error>> $body
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,14 +101,14 @@ pub struct DB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DB {
|
impl DB {
|
||||||
pub async fn new<S: Into<String>>(db_url: S) -> DbResult<Self> {
|
pub async fn new<S: Into<String>>(db_url: S) -> Self {
|
||||||
let options = ClientOptions::parse(db_url.into()).await?;
|
let options = ClientOptions::parse(db_url.into()).await.unwrap();
|
||||||
let client = Client::with_options(options)?;
|
let client = Client::with_options(options).unwrap();
|
||||||
|
|
||||||
Ok(DB { client })
|
DB { client }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn migrate(&mut self) -> DbResult<()> {
|
pub async fn migrate(&mut self) -> Result<(), mongodb::error::Error> {
|
||||||
let events = self.get_database().await.collection::<Event>("events");
|
let events = self.get_database().await.collection::<Event>("events");
|
||||||
events
|
events
|
||||||
.create_index(
|
.create_index(
|
||||||
@ -121,8 +121,8 @@ impl DB {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn init<S: Into<String>>(db_url: S) -> DbResult<Self> {
|
pub async fn init<S: Into<String>>(db_url: S) -> Result<Self, mongodb::error::Error> {
|
||||||
let mut db = Self::new(db_url).await?;
|
let mut db = Self::new(db_url).await;
|
||||||
db.migrate().await?;
|
db.migrate().await?;
|
||||||
|
|
||||||
Ok(db)
|
Ok(db)
|
||||||
@ -136,22 +136,24 @@ impl CallDB for DB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type DbError = mongodb::error::Error;
|
|
||||||
pub type DbResult<T> = Result<T, DbError>;
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait CallDB {
|
pub trait CallDB {
|
||||||
//type C;
|
//type C;
|
||||||
async fn get_database(&mut self) -> Database;
|
async fn get_database(&mut self) -> Database;
|
||||||
//async fn get_pool(&mut self) -> PooledConnection<'_, AsyncDieselConnectionManager<C>>;
|
//async fn get_pool(&mut self) -> PooledConnection<'_, AsyncDieselConnectionManager<C>>;
|
||||||
async fn get_users(&mut self) -> DbResult<Vec<User>> {
|
async fn get_users(&mut self) -> Vec<User> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let users = db.collection::<User>("users");
|
let users = db.collection::<User>("users");
|
||||||
|
users
|
||||||
users.find(doc! {}).await?.try_collect().await
|
.find(doc! {})
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.map(|u| u.unwrap())
|
||||||
|
.collect()
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_admin(&mut self, userid: i64, isadmin: bool) -> DbResult<()> {
|
async fn set_admin(&mut self, userid: i64, isadmin: bool) {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let users = db.collection::<User>("users");
|
let users = db.collection::<User>("users");
|
||||||
users
|
users
|
||||||
@ -163,12 +165,11 @@ pub trait CallDB {
|
|||||||
"$set": { "is_admin": isadmin }
|
"$set": { "is_admin": isadmin }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await
|
||||||
|
.unwrap();
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_or_init_user(&mut self, userid: i64, firstname: &str) -> DbResult<User> {
|
async fn get_or_init_user(&mut self, userid: i64, firstname: &str) -> User {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let users = db.collection::<User>("users");
|
let users = db.collection::<User>("users");
|
||||||
|
|
||||||
@ -181,15 +182,21 @@ pub trait CallDB {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.upsert(true)
|
.upsert(true)
|
||||||
.await?;
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
Ok(users
|
users
|
||||||
.find_one(doc! { "id": userid })
|
.find_one(doc! { "id": userid })
|
||||||
.await?
|
.await
|
||||||
.expect("no such user created"))
|
.unwrap()
|
||||||
|
.expect("no such user created")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_message(&mut self, chatid: i64, messageid: i32) -> DbResult<Option<Message>> {
|
async fn get_message(
|
||||||
|
&mut self,
|
||||||
|
chatid: i64,
|
||||||
|
messageid: i32,
|
||||||
|
) -> Result<Option<Message>, Box<dyn std::error::Error>> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let messages = db.collection::<Message>("messages");
|
let messages = db.collection::<Message>("messages");
|
||||||
|
|
||||||
@ -204,7 +211,7 @@ pub trait CallDB {
|
|||||||
&mut self,
|
&mut self,
|
||||||
chatid: i64,
|
chatid: i64,
|
||||||
messageid: i32,
|
messageid: i32,
|
||||||
) -> DbResult<Option<String>> {
|
) -> Result<Option<String>, Box<dyn std::error::Error>> {
|
||||||
let msg = self.get_message(chatid, messageid).await?;
|
let msg = self.get_message(chatid, messageid).await?;
|
||||||
Ok(msg.map(|m| m.token))
|
Ok(msg.map(|m| m.token))
|
||||||
}
|
}
|
||||||
@ -214,7 +221,7 @@ pub trait CallDB {
|
|||||||
chatid: i64,
|
chatid: i64,
|
||||||
messageid: i32,
|
messageid: i32,
|
||||||
literal: &str,
|
literal: &str,
|
||||||
) -> DbResult<()> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let messages = db.collection::<Message>("messages");
|
let messages = db.collection::<Message>("messages");
|
||||||
|
|
||||||
@ -234,7 +241,10 @@ pub trait CallDB {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_literal(&mut self, literal: &str) -> DbResult<Option<Literal>> {
|
async fn get_literal(
|
||||||
|
&mut self,
|
||||||
|
literal: &str,
|
||||||
|
) -> Result<Option<Literal>, Box<dyn std::error::Error>> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let messages = db.collection::<Literal>("literals");
|
let messages = db.collection::<Literal>("literals");
|
||||||
|
|
||||||
@ -243,13 +253,20 @@ pub trait CallDB {
|
|||||||
Ok(literal)
|
Ok(literal)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_literal_value(&mut self, literal: &str) -> DbResult<Option<String>> {
|
async fn get_literal_value(
|
||||||
|
&mut self,
|
||||||
|
literal: &str,
|
||||||
|
) -> Result<Option<String>, Box<dyn std::error::Error>> {
|
||||||
let literal = self.get_literal(literal).await?;
|
let literal = self.get_literal(literal).await?;
|
||||||
|
|
||||||
Ok(literal.map(|l| l.value))
|
Ok(literal.map(|l| l.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_literal(&mut self, literal: &str, valuestr: &str) -> DbResult<()> {
|
async fn set_literal(
|
||||||
|
&mut self,
|
||||||
|
literal: &str,
|
||||||
|
valuestr: &str,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let literals = db.collection::<Literal>("literals");
|
let literals = db.collection::<Literal>("literals");
|
||||||
|
|
||||||
@ -264,14 +281,23 @@ pub trait CallDB {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_all_events(&mut self) -> DbResult<Vec<Event>> {
|
async fn get_all_events(&mut self) -> Vec<Event> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let events = db.collection::<Event>("events");
|
let events = db.collection::<Event>("events");
|
||||||
|
|
||||||
events.find(doc! {}).await?.try_collect().await
|
events
|
||||||
|
.find(doc! {})
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.map(|e| e.unwrap())
|
||||||
|
.collect()
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_event(&mut self, event_datetime: chrono::DateTime<Utc>) -> DbResult<Event> {
|
async fn create_event(
|
||||||
|
&mut self,
|
||||||
|
event_datetime: chrono::DateTime<Utc>,
|
||||||
|
) -> Result<Event, Box<dyn std::error::Error>> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let events = db.collection::<Event>("events");
|
let events = db.collection::<Event>("events");
|
||||||
|
|
||||||
@ -285,7 +311,7 @@ pub trait CallDB {
|
|||||||
Ok(new_event)
|
Ok(new_event)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_media(&mut self, literal: &str) -> DbResult<Vec<Media>> {
|
async fn get_media(&mut self, literal: &str) -> Result<Vec<Media>, Box<dyn std::error::Error>> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let media = db.collection::<Media>("media");
|
let media = db.collection::<Media>("media");
|
||||||
|
|
||||||
@ -298,7 +324,10 @@ pub trait CallDB {
|
|||||||
Ok(media_items)
|
Ok(media_items)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_media_group_exists(&mut self, media_group: &str) -> DbResult<bool> {
|
async fn is_media_group_exists(
|
||||||
|
&mut self,
|
||||||
|
media_group: &str,
|
||||||
|
) -> Result<bool, Box<dyn std::error::Error>> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let media = db.collection::<Media>("media");
|
let media = db.collection::<Media>("media");
|
||||||
|
|
||||||
@ -310,7 +339,7 @@ pub trait CallDB {
|
|||||||
Ok(is_exists)
|
Ok(is_exists)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drop_media(&mut self, literal: &str) -> DbResult<usize> {
|
async fn drop_media(&mut self, literal: &str) -> Result<usize, Box<dyn std::error::Error>> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let media = db.collection::<Media>("media");
|
let media = db.collection::<Media>("media");
|
||||||
|
|
||||||
@ -322,7 +351,11 @@ pub trait CallDB {
|
|||||||
Ok(deleted_count as usize)
|
Ok(deleted_count as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drop_media_except(&mut self, literal: &str, except_group: &str) -> DbResult<usize> {
|
async fn drop_media_except(
|
||||||
|
&mut self,
|
||||||
|
literal: &str,
|
||||||
|
except_group: &str,
|
||||||
|
) -> Result<usize, Box<dyn std::error::Error>> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let media = db.collection::<Media>("media");
|
let media = db.collection::<Media>("media");
|
||||||
|
|
||||||
@ -343,7 +376,7 @@ pub trait CallDB {
|
|||||||
mediatype: &str,
|
mediatype: &str,
|
||||||
fileid: &str,
|
fileid: &str,
|
||||||
media_group: Option<&str>,
|
media_group: Option<&str>,
|
||||||
) -> DbResult<Media> {
|
) -> Result<Media, Box<dyn std::error::Error>> {
|
||||||
let db = self.get_database().await;
|
let db = self.get_database().await;
|
||||||
let media = db.collection::<Media>("media");
|
let media = db.collection::<Media>("media");
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
|
|
||||||
use dotenvy;
|
use dotenvy;
|
||||||
|
|
||||||
use super::CallDB;
|
use super::CallDB;
|
||||||
@ -8,20 +6,21 @@ use super::DB;
|
|||||||
async fn setup_db() -> DB {
|
async fn setup_db() -> DB {
|
||||||
dotenvy::dotenv().unwrap();
|
dotenvy::dotenv().unwrap();
|
||||||
let db_url = std::env::var("DATABASE_URL").unwrap();
|
let db_url = std::env::var("DATABASE_URL").unwrap();
|
||||||
|
let db = DB::new(db_url).await;
|
||||||
|
|
||||||
DB::new(db_url).await.unwrap()
|
db
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_media() {
|
async fn test_get_media() {
|
||||||
let mut db = setup_db().await;
|
let mut db = setup_db().await;
|
||||||
|
|
||||||
let _result = db.drop_media("test_get_media_literal").await.unwrap();
|
let result = db.drop_media("test_get_media_literal").await.unwrap();
|
||||||
|
|
||||||
let media_items = db.get_media("test_get_media_literal").await.unwrap();
|
let media_items = db.get_media("test_get_media_literal").await.unwrap();
|
||||||
assert_eq!(media_items.len(), 0);
|
assert_eq!(media_items.len(), 0);
|
||||||
|
|
||||||
let _result = db
|
let result = db
|
||||||
.add_media("test_get_media_literal", "photo", "file_id_1", None)
|
.add_media("test_get_media_literal", "photo", "file_id_1", None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -29,7 +28,7 @@ async fn test_get_media() {
|
|||||||
let media_items = db.get_media("test_get_media_literal").await.unwrap();
|
let media_items = db.get_media("test_get_media_literal").await.unwrap();
|
||||||
assert_eq!(media_items.len(), 1);
|
assert_eq!(media_items.len(), 1);
|
||||||
|
|
||||||
let _result = db
|
let result = db
|
||||||
.add_media("test_get_media_literal", "video", "file_id_2", None)
|
.add_media("test_get_media_literal", "video", "file_id_2", None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -38,7 +37,7 @@ async fn test_get_media() {
|
|||||||
assert_eq!(media_items.len(), 2);
|
assert_eq!(media_items.len(), 2);
|
||||||
|
|
||||||
// Clean up after test
|
// Clean up after test
|
||||||
let _result = db.drop_media("test_get_media_literal").await.unwrap();
|
let result = db.drop_media("test_get_media_literal").await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@ -49,9 +48,9 @@ async fn test_add_media() {
|
|||||||
let media_type = "photo";
|
let media_type = "photo";
|
||||||
let file_id = "LjaldhAOh";
|
let file_id = "LjaldhAOh";
|
||||||
|
|
||||||
let _result = db.drop_media(literal).await.unwrap();
|
let result = db.drop_media(literal).await.unwrap();
|
||||||
|
|
||||||
let _result = db
|
let result = db
|
||||||
.add_media(literal, media_type, file_id, None)
|
.add_media(literal, media_type, file_id, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -64,14 +63,14 @@ async fn test_add_media() {
|
|||||||
assert_eq!(media_items[0].file_id, file_id);
|
assert_eq!(media_items[0].file_id, file_id);
|
||||||
|
|
||||||
// Clean up after test
|
// Clean up after test
|
||||||
let _result = db.drop_media(literal).await.unwrap();
|
let result = db.drop_media(literal).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_drop_media() {
|
async fn test_drop_media() {
|
||||||
let mut db = setup_db().await;
|
let mut db = setup_db().await;
|
||||||
|
|
||||||
let _result = db
|
let result = db
|
||||||
.add_media("test_drop_media_literal", "photo", "file_id_1", None)
|
.add_media("test_drop_media_literal", "photo", "file_id_1", None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -80,14 +79,14 @@ async fn test_drop_media() {
|
|||||||
let media_items = db.get_media("test_drop_media_literal").await.unwrap();
|
let media_items = db.get_media("test_drop_media_literal").await.unwrap();
|
||||||
assert_eq!(media_items.len(), 1);
|
assert_eq!(media_items.len(), 1);
|
||||||
|
|
||||||
let _result = db.drop_media("test_drop_media_literal").await.unwrap();
|
let result = db.drop_media("test_drop_media_literal").await.unwrap();
|
||||||
|
|
||||||
// Verify that the media has been dropped
|
// Verify that the media has been dropped
|
||||||
let media_items = db.get_media("test_drop_media_literal").await.unwrap();
|
let media_items = db.get_media("test_drop_media_literal").await.unwrap();
|
||||||
assert_eq!(media_items.len(), 0);
|
assert_eq!(media_items.len(), 0);
|
||||||
|
|
||||||
// Clean up after test
|
// Clean up after test
|
||||||
let _result = db.drop_media("test_drop_media_literal").await.unwrap();
|
let result = db.drop_media("test_drop_media_literal").await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@ -136,7 +135,7 @@ async fn test_drop_media_except() {
|
|||||||
let media_items = db.get_media(literal).await.unwrap();
|
let media_items = db.get_media(literal).await.unwrap();
|
||||||
assert_eq!(media_items.len(), 2);
|
assert_eq!(media_items.len(), 2);
|
||||||
|
|
||||||
let _deleted_count = db.drop_media_except(literal, media_group).await.unwrap();
|
let deleted_count = db.drop_media_except(literal, media_group).await.unwrap();
|
||||||
let media_items = db.get_media(literal).await.unwrap();
|
let media_items = db.get_media(literal).await.unwrap();
|
||||||
assert_eq!(media_items.len(), 0);
|
assert_eq!(media_items.len(), 0);
|
||||||
|
|
||||||
@ -153,7 +152,7 @@ async fn test_drop_media_except() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let _deleted_count = db.drop_media_except(literal, media_group).await.unwrap();
|
let deleted_count = db.drop_media_except(literal, media_group).await.unwrap();
|
||||||
let media_items = db.get_media(literal).await.unwrap();
|
let media_items = db.get_media(literal).await.unwrap();
|
||||||
assert_eq!(media_items.len(), 1);
|
assert_eq!(media_items.len(), 1);
|
||||||
let _ = db.drop_media(literal).await.unwrap();
|
let _ = db.drop_media(literal).await.unwrap();
|
||||||
@ -167,7 +166,7 @@ async fn test_drop_media_except() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let _deleted_count = db.drop_media_except(literal, media_group).await.unwrap();
|
let deleted_count = db.drop_media_except(literal, media_group).await.unwrap();
|
||||||
let media_items = db.get_media(literal).await.unwrap();
|
let media_items = db.get_media(literal).await.unwrap();
|
||||||
assert_eq!(media_items.len(), 2);
|
assert_eq!(media_items.len(), 2);
|
||||||
|
|
||||||
|
|||||||
167
src/main.rs
167
src/main.rs
@ -2,7 +2,6 @@ pub mod admin;
|
|||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod mongodb_storage;
|
pub mod mongodb_storage;
|
||||||
|
|
||||||
use log::info;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::admin::{admin_command_handler, AdminCommands};
|
use crate::admin::{admin_command_handler, AdminCommands};
|
||||||
@ -12,11 +11,10 @@ use crate::mongodb_storage::MongodbStorage;
|
|||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use chrono_tz::Asia;
|
use chrono_tz::Asia;
|
||||||
use db::DbError;
|
|
||||||
use envconfig::Envconfig;
|
use envconfig::Envconfig;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use teloxide::dispatching::dialogue::serializer::Json;
|
use teloxide::dispatching::dialogue::serializer::Json;
|
||||||
use teloxide::dispatching::dialogue::{GetChatId, Serializer};
|
use teloxide::dispatching::dialogue::GetChatId;
|
||||||
use teloxide::types::{
|
use teloxide::types::{
|
||||||
InlineKeyboardButton, InlineKeyboardMarkup, InputFile, InputMedia, MediaKind, MessageKind,
|
InlineKeyboardButton, InlineKeyboardMarkup, InputFile, InputMedia, MediaKind, MessageKind,
|
||||||
ParseMode, ReplyMarkup,
|
ParseMode, ReplyMarkup,
|
||||||
@ -54,7 +52,7 @@ trait LogMsg {
|
|||||||
|
|
||||||
impl LogMsg for <teloxide::Bot as teloxide::prelude::Requester>::SendMessage {
|
impl LogMsg for <teloxide::Bot as teloxide::prelude::Requester>::SendMessage {
|
||||||
fn log(self) -> Self {
|
fn log(self) -> Self {
|
||||||
info!("msg: {}", self.text);
|
println!("msg: {}", self.text);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,21 +82,6 @@ impl BotController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
pub enum BotError {
|
|
||||||
DBError(#[from] DbError),
|
|
||||||
TeloxideError(#[from] teloxide::RequestError),
|
|
||||||
StorageError(#[from] mongodb_storage::MongodbStorageError<<Json as Serializer<State>>::Error>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type BotResult<T> = Result<T, BotError>;
|
|
||||||
|
|
||||||
impl std::fmt::Display for BotError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:?}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
dotenvy::dotenv()?;
|
dotenvy::dotenv()?;
|
||||||
@ -108,39 +91,33 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let state_mgr = MongodbStorage::open(config.db_url.clone().as_ref(), "gongbot", Json).await?;
|
let state_mgr = MongodbStorage::open(config.db_url.clone().as_ref(), "gongbot", Json).await?;
|
||||||
|
|
||||||
// TODO: delete this in production
|
// TODO: delete this in production
|
||||||
// allow because values are hardcoded and if they will be unparsable
|
let events: Vec<DateTime<Utc>> = vec!["2025-04-09T18:00:00+04:00", "2025-04-11T16:00:00+04:00"]
|
||||||
// we should panic anyway
|
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
let events: Vec<DateTime<Utc>> = ["2025-04-09T18:00:00+04:00", "2025-04-11T16:00:00+04:00"]
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|d| DateTime::parse_from_rfc3339(d).unwrap().into())
|
.map(|d| DateTime::parse_from_rfc3339(d).unwrap().into())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for event in events {
|
for event in events {
|
||||||
match bc.db.create_event(event).await {
|
match bc.db.create_event(event).await {
|
||||||
Ok(e) => info!("Created event {}", e._id),
|
Ok(e) => println!("Created event {}", e._id),
|
||||||
Err(err) => info!("Failed to create event, error: {}", err),
|
Err(err) => println!("Failed to create event, error: {}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
||||||
let handler = dptree::entry()
|
let handler = dptree::entry()
|
||||||
.inspect(|u: Update| {
|
.inspect(|u: Update| {
|
||||||
info!("{u:#?}"); // Print the update to the console with inspect
|
eprintln!("{u:#?}"); // Print the update to the console with inspect
|
||||||
})
|
})
|
||||||
.branch(Update::filter_callback_query().endpoint(callback_handler))
|
.branch(Update::filter_callback_query().endpoint(callback_handler))
|
||||||
.branch(command_handler(config))
|
.branch(command_handler(config))
|
||||||
.branch(
|
.branch(
|
||||||
Update::filter_message()
|
Update::filter_message()
|
||||||
.filter_async(async |msg: Message, mut db: DB| {
|
.filter_async(async |msg: Message, mut db: DB| {
|
||||||
let tguser = match msg.from.clone() {
|
let tguser = msg.from.unwrap();
|
||||||
Some(user) => user,
|
|
||||||
None => return false, // do nothing, cause its not usecase of function
|
|
||||||
};
|
|
||||||
let user = db
|
let user = db
|
||||||
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
|
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
|
||||||
.await;
|
.await;
|
||||||
user.map(|u| u.is_admin).unwrap_or(false)
|
user.is_admin
|
||||||
})
|
})
|
||||||
.enter_dialogue::<Message, MongodbStorage<Json>, State>()
|
.enter_dialogue::<Message, MongodbStorage<Json>, State>()
|
||||||
.branch(
|
.branch(
|
||||||
@ -171,7 +148,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn callback_handler(bot: Bot, mut db: DB, q: CallbackQuery) -> BotResult<()> {
|
async fn callback_handler(
|
||||||
|
bot: Bot,
|
||||||
|
mut db: DB,
|
||||||
|
q: CallbackQuery,
|
||||||
|
) -> Result<(), teloxide::RequestError> {
|
||||||
bot.answer_callback_query(&q.id).await?;
|
bot.answer_callback_query(&q.id).await?;
|
||||||
|
|
||||||
if let Some(ref data) = q.data {
|
if let Some(ref data) = q.data {
|
||||||
@ -179,7 +160,10 @@ async fn callback_handler(bot: Bot, mut db: DB, q: CallbackQuery) -> BotResult<(
|
|||||||
"more_info" => {
|
"more_info" => {
|
||||||
answer_message(
|
answer_message(
|
||||||
&bot,
|
&bot,
|
||||||
q.chat_id().map(|i| i.0).unwrap_or(q.from.id.0 as i64),
|
q.chat_id()
|
||||||
|
.clone()
|
||||||
|
.map(|i| i.0)
|
||||||
|
.unwrap_or(q.from.id.0 as i64),
|
||||||
&mut db,
|
&mut db,
|
||||||
"more_info",
|
"more_info",
|
||||||
None as Option<InlineKeyboardMarkup>,
|
None as Option<InlineKeyboardMarkup>,
|
||||||
@ -198,12 +182,16 @@ async fn edit_msg_cmd_handler(
|
|||||||
mut db: DB,
|
mut db: DB,
|
||||||
dialogue: BotDialogue,
|
dialogue: BotDialogue,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
) -> BotResult<()> {
|
) -> Result<(), teloxide::RequestError> {
|
||||||
match msg.reply_to_message() {
|
match msg.reply_to_message() {
|
||||||
Some(replied) => {
|
Some(replied) => {
|
||||||
let msgid = replied.id;
|
let msgid = replied.id;
|
||||||
// look for message in db and set text
|
// look for message in db and set text
|
||||||
let literal = match db.get_message_literal(msg.chat.id.0, msgid.0).await? {
|
let literal = match db
|
||||||
|
.get_message_literal(msg.chat.id.0, msgid.0)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
Some(l) => l,
|
Some(l) => l,
|
||||||
None => {
|
None => {
|
||||||
bot.send_message(msg.chat.id, "No such message found to edit. Look if you replying bot's message and this message is supposed to be editable").await?;
|
bot.send_message(msg.chat.id, "No such message found to edit. Look if you replying bot's message and this message is supposed to be editable").await?;
|
||||||
@ -218,7 +206,8 @@ async fn edit_msg_cmd_handler(
|
|||||||
lang,
|
lang,
|
||||||
is_caption_set: false,
|
is_caption_set: false,
|
||||||
})
|
})
|
||||||
.await?;
|
.await
|
||||||
|
.unwrap();
|
||||||
bot.send_message(
|
bot.send_message(
|
||||||
msg.chat.id,
|
msg.chat.id,
|
||||||
"Ok, now you have to send message text (formatting supported)",
|
"Ok, now you have to send message text (formatting supported)",
|
||||||
@ -239,44 +228,45 @@ async fn edit_msg_handler(
|
|||||||
dialogue: BotDialogue,
|
dialogue: BotDialogue,
|
||||||
(literal, lang, is_caption_set): (String, String, bool),
|
(literal, lang, is_caption_set): (String, String, bool),
|
||||||
msg: Message,
|
msg: Message,
|
||||||
) -> BotResult<()> {
|
) -> Result<(), teloxide::RequestError> {
|
||||||
use teloxide::utils::render::Renderer;
|
use teloxide::utils::render::Renderer;
|
||||||
|
|
||||||
let chat_id = msg.chat.id;
|
let chat_id = msg.chat.id;
|
||||||
info!("Type: {:#?}", msg.kind);
|
println!("Type: {:#?}", msg.kind);
|
||||||
let msg = if let MessageKind::Common(msg) = msg.kind {
|
let msg = if let MessageKind::Common(msg) = msg.kind {
|
||||||
msg
|
msg
|
||||||
} else {
|
} else {
|
||||||
info!("Not a Common, somehow");
|
println!("Not a Common, somehow");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
match msg.media_kind {
|
match msg.media_kind {
|
||||||
MediaKind::Text(text) => {
|
MediaKind::Text(text) => {
|
||||||
db.drop_media(&literal).await?;
|
db.drop_media(&literal).await.unwrap();
|
||||||
if is_caption_set {
|
if is_caption_set {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
let html_text = Renderer::new(&text.text, &text.entities).as_html();
|
let html_text = Renderer::new(&text.text, &text.entities).as_html();
|
||||||
db.set_literal(&literal, &html_text).await?;
|
db.set_literal(&literal, &html_text).await.unwrap();
|
||||||
bot.send_message(chat_id, "Updated text of message!")
|
bot.send_message(chat_id, "Updated text of message!")
|
||||||
.await?;
|
.await?;
|
||||||
dialogue.exit().await?;
|
dialogue.exit().await.unwrap();
|
||||||
}
|
}
|
||||||
MediaKind::Photo(photo) => {
|
MediaKind::Photo(photo) => {
|
||||||
let group = photo.media_group_id;
|
let group = photo.media_group_id;
|
||||||
if let Some(group) = group.clone() {
|
if let Some(group) = group.clone() {
|
||||||
db.drop_media_except(&literal, &group).await?;
|
db.drop_media_except(&literal, &group).await.unwrap();
|
||||||
} else {
|
} else {
|
||||||
db.drop_media(&literal).await?;
|
db.drop_media(&literal).await.unwrap();
|
||||||
}
|
}
|
||||||
let file_id = photo.photo[0].file.id.clone();
|
let file_id = photo.photo[0].file.id.clone();
|
||||||
db.add_media(&literal, "photo", &file_id, group.as_deref())
|
db.add_media(&literal, "photo", &file_id, group.as_deref())
|
||||||
.await?;
|
.await
|
||||||
|
.unwrap();
|
||||||
match photo.caption {
|
match photo.caption {
|
||||||
Some(text) => {
|
Some(text) => {
|
||||||
let html_text = Renderer::new(&text, &photo.caption_entities).as_html();
|
let html_text = Renderer::new(&text, &photo.caption_entities).as_html();
|
||||||
db.set_literal(&literal, &html_text).await?;
|
db.set_literal(&literal, &html_text).await.unwrap();
|
||||||
bot.send_message(chat_id, "Updated photo caption!").await?;
|
bot.send_message(chat_id, "Updated photo caption!").await?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -285,9 +275,10 @@ async fn edit_msg_handler(
|
|||||||
// set text empty
|
// set text empty
|
||||||
if !db
|
if !db
|
||||||
.is_media_group_exists(group.as_deref().unwrap_or(""))
|
.is_media_group_exists(group.as_deref().unwrap_or(""))
|
||||||
.await?
|
.await
|
||||||
|
.unwrap()
|
||||||
{
|
{
|
||||||
db.set_literal(&literal, "").await?;
|
db.set_literal(&literal, "").await.unwrap();
|
||||||
bot.send_message(chat_id, "Set photo without caption")
|
bot.send_message(chat_id, "Set photo without caption")
|
||||||
.await?;
|
.await?;
|
||||||
};
|
};
|
||||||
@ -305,7 +296,8 @@ async fn edit_msg_handler(
|
|||||||
lang,
|
lang,
|
||||||
is_caption_set: true,
|
is_caption_set: true,
|
||||||
})
|
})
|
||||||
.await?;
|
.await
|
||||||
|
.unwrap();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||||
dialogue.exit().await.unwrap_or(());
|
dialogue.exit().await.unwrap_or(());
|
||||||
@ -314,17 +306,18 @@ async fn edit_msg_handler(
|
|||||||
MediaKind::Video(video) => {
|
MediaKind::Video(video) => {
|
||||||
let group = video.media_group_id;
|
let group = video.media_group_id;
|
||||||
if let Some(group) = group.clone() {
|
if let Some(group) = group.clone() {
|
||||||
db.drop_media_except(&literal, &group).await?;
|
db.drop_media_except(&literal, &group).await.unwrap();
|
||||||
} else {
|
} else {
|
||||||
db.drop_media(&literal).await?;
|
db.drop_media(&literal).await.unwrap();
|
||||||
}
|
}
|
||||||
let file_id = video.video.file.id;
|
let file_id = video.video.file.id;
|
||||||
db.add_media(&literal, "video", &file_id, group.as_deref())
|
db.add_media(&literal, "video", &file_id, group.as_deref())
|
||||||
.await?;
|
.await
|
||||||
|
.unwrap();
|
||||||
match video.caption {
|
match video.caption {
|
||||||
Some(text) => {
|
Some(text) => {
|
||||||
let html_text = Renderer::new(&text, &video.caption_entities).as_html();
|
let html_text = Renderer::new(&text, &video.caption_entities).as_html();
|
||||||
db.set_literal(&literal, &html_text).await?;
|
db.set_literal(&literal, &html_text).await.unwrap();
|
||||||
bot.send_message(chat_id, "Updated video caption!").await?;
|
bot.send_message(chat_id, "Updated video caption!").await?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -333,9 +326,10 @@ async fn edit_msg_handler(
|
|||||||
// set text empty
|
// set text empty
|
||||||
if !db
|
if !db
|
||||||
.is_media_group_exists(group.as_deref().unwrap_or(""))
|
.is_media_group_exists(group.as_deref().unwrap_or(""))
|
||||||
.await?
|
.await
|
||||||
|
.unwrap()
|
||||||
{
|
{
|
||||||
db.set_literal(&literal, "").await?;
|
db.set_literal(&literal, "").await.unwrap();
|
||||||
bot.send_message(chat_id, "Set video without caption")
|
bot.send_message(chat_id, "Set video without caption")
|
||||||
.await?;
|
.await?;
|
||||||
};
|
};
|
||||||
@ -353,7 +347,8 @@ async fn edit_msg_handler(
|
|||||||
lang,
|
lang,
|
||||||
is_caption_set: true,
|
is_caption_set: true,
|
||||||
})
|
})
|
||||||
.await?;
|
.await
|
||||||
|
.unwrap();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||||
dialogue.exit().await.unwrap_or(());
|
dialogue.exit().await.unwrap_or(());
|
||||||
@ -370,7 +365,12 @@ async fn edit_msg_handler(
|
|||||||
|
|
||||||
fn command_handler(
|
fn command_handler(
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Handler<'static, DependencyMap, BotResult<()>, teloxide::dispatching::DpHandlerDescription> {
|
) -> Handler<
|
||||||
|
'static,
|
||||||
|
DependencyMap,
|
||||||
|
Result<(), teloxide::RequestError>,
|
||||||
|
teloxide::dispatching::DpHandlerDescription,
|
||||||
|
> {
|
||||||
Update::filter_message()
|
Update::filter_message()
|
||||||
.branch(
|
.branch(
|
||||||
dptree::entry()
|
dptree::entry()
|
||||||
@ -386,14 +386,11 @@ fn command_handler(
|
|||||||
.branch(
|
.branch(
|
||||||
dptree::entry()
|
dptree::entry()
|
||||||
.filter_async(async |msg: Message, mut db: DB| {
|
.filter_async(async |msg: Message, mut db: DB| {
|
||||||
let tguser = match msg.from.clone() {
|
let tguser = msg.from.unwrap();
|
||||||
Some(user) => user,
|
|
||||||
None => return false, // do nothing, cause its not usecase of function
|
|
||||||
};
|
|
||||||
let user = db
|
let user = db
|
||||||
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
|
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
|
||||||
.await;
|
.await;
|
||||||
user.map(|u| u.is_admin).unwrap_or(false)
|
user.is_admin
|
||||||
})
|
})
|
||||||
.filter_command::<AdminCommands>()
|
.filter_command::<AdminCommands>()
|
||||||
.endpoint(admin_command_handler),
|
.endpoint(admin_command_handler),
|
||||||
@ -405,20 +402,14 @@ async fn user_command_handler(
|
|||||||
bot: Bot,
|
bot: Bot,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
cmd: UserCommands,
|
cmd: UserCommands,
|
||||||
) -> BotResult<()> {
|
) -> Result<(), teloxide::RequestError> {
|
||||||
let tguser = match msg.from.clone() {
|
let tguser = msg.from.clone().unwrap();
|
||||||
Some(user) => user,
|
|
||||||
None => return Ok(()), // do nothing, cause its not usecase of function
|
|
||||||
};
|
|
||||||
let user = db
|
let user = db
|
||||||
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
|
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
|
||||||
.await?;
|
.await;
|
||||||
let user = update_user_tg(user, &tguser);
|
let user = update_user_tg(user, msg.from.as_ref().unwrap());
|
||||||
user.update_user(&mut db).await?;
|
user.update_user(&mut db).await.unwrap();
|
||||||
info!(
|
println!("MSG: {}", msg.html_text().unwrap());
|
||||||
"MSG: {}",
|
|
||||||
msg.html_text().unwrap_or("|EMPTY_MESSAGE|".into())
|
|
||||||
);
|
|
||||||
match cmd {
|
match cmd {
|
||||||
UserCommands::Start => {
|
UserCommands::Start => {
|
||||||
let mut db2 = db.clone();
|
let mut db2 = db.clone();
|
||||||
@ -427,10 +418,9 @@ async fn user_command_handler(
|
|||||||
msg.chat.id.0,
|
msg.chat.id.0,
|
||||||
&mut db,
|
&mut db,
|
||||||
"start",
|
"start",
|
||||||
Some(make_start_buttons(&mut db2).await?),
|
Some(make_start_buttons(&mut db2).await),
|
||||||
)
|
)
|
||||||
.await?;
|
.await
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
UserCommands::Help => {
|
UserCommands::Help => {
|
||||||
bot.send_message(msg.chat.id, UserCommands::descriptions().to_string())
|
bot.send_message(msg.chat.id, UserCommands::descriptions().to_string())
|
||||||
@ -446,12 +436,13 @@ async fn answer_message<RM: Into<ReplyMarkup>>(
|
|||||||
db: &mut DB,
|
db: &mut DB,
|
||||||
literal: &str,
|
literal: &str,
|
||||||
keyboard: Option<RM>,
|
keyboard: Option<RM>,
|
||||||
) -> BotResult<()> {
|
) -> Result<(), teloxide::RequestError> {
|
||||||
let text = db
|
let text = db
|
||||||
.get_literal_value(literal)
|
.get_literal_value(literal)
|
||||||
.await?
|
.await
|
||||||
|
.unwrap()
|
||||||
.unwrap_or("Please, set content of this message".into());
|
.unwrap_or("Please, set content of this message".into());
|
||||||
let media = db.get_media(literal).await?;
|
let media = db.get_media(&literal).await.unwrap();
|
||||||
let (chat_id, msg_id) = match media.len() {
|
let (chat_id, msg_id) = match media.len() {
|
||||||
// just a text
|
// just a text
|
||||||
0 => {
|
0 => {
|
||||||
@ -461,7 +452,7 @@ async fn answer_message<RM: Into<ReplyMarkup>>(
|
|||||||
None => msg,
|
None => msg,
|
||||||
};
|
};
|
||||||
let msg = msg.parse_mode(teloxide::types::ParseMode::Html);
|
let msg = msg.parse_mode(teloxide::types::ParseMode::Html);
|
||||||
info!("ENTS: {:?}", msg.entities);
|
println!("ENTS: {:?}", msg.entities);
|
||||||
let msg = msg.await?;
|
let msg = msg.await?;
|
||||||
|
|
||||||
(msg.chat.id.0, msg.id.0)
|
(msg.chat.id.0, msg.id.0)
|
||||||
@ -563,14 +554,16 @@ async fn answer_message<RM: Into<ReplyMarkup>>(
|
|||||||
(msg[0].chat.id.0, msg[0].id.0)
|
(msg[0].chat.id.0, msg[0].id.0)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
db.set_message_literal(chat_id, msg_id, literal).await?;
|
db.set_message_literal(chat_id, msg_id, literal)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn make_start_buttons(db: &mut DB) -> BotResult<InlineKeyboardMarkup> {
|
async fn make_start_buttons(db: &mut DB) -> InlineKeyboardMarkup {
|
||||||
let mut buttons: Vec<Vec<InlineKeyboardButton>> = db
|
let mut buttons: Vec<Vec<InlineKeyboardButton>> = db
|
||||||
.get_all_events()
|
.get_all_events()
|
||||||
.await?
|
.await
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| {
|
.map(|e| {
|
||||||
vec![InlineKeyboardButton::callback(
|
vec![InlineKeyboardButton::callback(
|
||||||
@ -584,12 +577,12 @@ async fn make_start_buttons(db: &mut DB) -> BotResult<InlineKeyboardMarkup> {
|
|||||||
"more_info",
|
"more_info",
|
||||||
)]);
|
)]);
|
||||||
|
|
||||||
Ok(InlineKeyboardMarkup::new(buttons))
|
InlineKeyboardMarkup::new(buttons)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn echo(bot: Bot, msg: Message) -> BotResult<()> {
|
async fn echo(bot: Bot, msg: Message) -> Result<(), teloxide::RequestError> {
|
||||||
if let Some(photo) = msg.photo() {
|
if let Some(photo) = msg.photo() {
|
||||||
info!("File ID: {}", photo[0].file.id);
|
println!("File ID: {}", photo[0].file.id);
|
||||||
}
|
}
|
||||||
bot.send_message(msg.chat.id, msg.html_text().unwrap_or("UNWRAP".into()))
|
bot.send_message(msg.chat.id, msg.html_text().unwrap_or("UNWRAP".into()))
|
||||||
.parse_mode(teloxide::types::ParseMode::Html)
|
.parse_mode(teloxide::types::ParseMode::Html)
|
||||||
|
|||||||
@ -36,26 +36,6 @@ pub struct Dialogue {
|
|||||||
dialogue: Vec<u32>,
|
dialogue: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum MongodbStorageError<SE>
|
|
||||||
where
|
|
||||||
SE: Debug + Display,
|
|
||||||
{
|
|
||||||
MongodbError(#[from] mongodb::error::Error),
|
|
||||||
SerdeError(SE),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type MongodbStorageResult<T, SE> = Result<T, MongodbStorageError<SE>>;
|
|
||||||
|
|
||||||
impl<SE> std::fmt::Display for MongodbStorageError<SE>
|
|
||||||
where
|
|
||||||
SE: Debug + Display,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:?}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S, D> Storage<D> for MongodbStorage<S>
|
impl<S, D> Storage<D> for MongodbStorage<S>
|
||||||
where
|
where
|
||||||
S: Send + Sync + Serializer<D> + 'static,
|
S: Send + Sync + Serializer<D> + 'static,
|
||||||
@ -63,7 +43,7 @@ where
|
|||||||
|
|
||||||
<S as Serializer<D>>::Error: Debug + Display,
|
<S as Serializer<D>>::Error: Debug + Display,
|
||||||
{
|
{
|
||||||
type Error = MongodbStorageError<<S as Serializer<D>>::Error>;
|
type Error = mongodb::error::Error;
|
||||||
|
|
||||||
fn remove_dialogue(
|
fn remove_dialogue(
|
||||||
self: std::sync::Arc<Self>,
|
self: std::sync::Arc<Self>,
|
||||||
@ -76,8 +56,7 @@ where
|
|||||||
let d = self.database.collection::<Dialogue>("dialogues");
|
let d = self.database.collection::<Dialogue>("dialogues");
|
||||||
d.delete_one(doc! { "chat_id": chat_id.0 })
|
d.delete_one(doc! { "chat_id": chat_id.0 })
|
||||||
.await
|
.await
|
||||||
.map(|_| ())?;
|
.map(|_| ())
|
||||||
Ok(())
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,14 +76,9 @@ where
|
|||||||
},
|
},
|
||||||
doc! {
|
doc! {
|
||||||
"$set": doc! {
|
"$set": doc! {
|
||||||
"dialogue": self.serializer.serialize(&dialogue)
|
"dialogue": self.serializer.serialize(&dialogue).unwrap().into_iter().map(|v| v as u32).collect::<Vec<u32>>()
|
||||||
.map_err(MongodbStorageError::SerdeError)?
|
|
||||||
.into_iter().map(|v| v as u32).collect::<Vec<u32>>()
|
|
||||||
}
|
}
|
||||||
},
|
}).upsert(true).await?;
|
||||||
)
|
|
||||||
.upsert(true)
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -115,13 +89,8 @@ where
|
|||||||
) -> BoxFuture<'static, Result<Option<D>, Self::Error>> {
|
) -> BoxFuture<'static, Result<Option<D>, Self::Error>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let d = self.database.collection::<Dialogue>("dialogues");
|
let d = self.database.collection::<Dialogue>("dialogues");
|
||||||
let d = d.find_one(doc! { "chat_id": chat_id.0 }).await?;
|
Ok(d.find_one(doc! { "chat_id": chat_id.0 }).await?.map(|d| {
|
||||||
let d = match d {
|
self.serializer
|
||||||
Some(d) => d,
|
|
||||||
None => return Ok(None),
|
|
||||||
};
|
|
||||||
let d = self
|
|
||||||
.serializer
|
|
||||||
.deserialize(
|
.deserialize(
|
||||||
d.dialogue
|
d.dialogue
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -129,9 +98,8 @@ where
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.as_slice(),
|
.as_slice(),
|
||||||
)
|
)
|
||||||
.map_err(MongodbStorageError::SerdeError)?;
|
.unwrap()
|
||||||
|
}))
|
||||||
Ok(Some(d))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user