Compare commits

..

9 Commits

Author SHA1 Message Date
Akulij
827a5022d1 implement db functions to manipulate media table 2025-04-10 21:15:42 +09:00
Akulij
ed211f2d72 create table media 2025-04-10 21:11:14 +09:00
Akulij
412a54d647 cargo fmt 2025-04-10 20:55:32 +09:00
Akulij
1006fbe5c1 fix: request first_name in user creation db function
it is required column in table
2025-04-10 20:46:23 +09:00
Akulij
a9919a9307 handle edit command in any case 2025-04-10 20:12:15 +09:00
Akulij
4a37792c0c change edit_msg_handler logic for more extensibility 2025-04-10 20:06:52 +09:00
Akulij
2bac30e711 create callback_handler 2025-04-10 19:27:31 +09:00
Akulij
a58fca01f9 fix: ask only for chat_id instead of whole message in answer_message in
case of generalization
2025-04-10 02:34:41 +09:00
Akulij
089ef3218c move out message answer into function 2025-04-10 02:18:28 +09:00
7 changed files with 181 additions and 32 deletions

View File

@ -0,0 +1,2 @@
DROP TABLE media;

View File

@ -0,0 +1,6 @@
CREATE TABLE media (
id SERIAL PRIMARY KEY,
token VARCHAR NOT NULL,
media_type VARCHAR NOT NULL,
file_id VARCHAR NOT NULL
);

View File

@ -71,8 +71,9 @@ pub async fn secret_command_handler(
admin_password: String,
) -> Result<(), teloxide::RequestError> {
println!("Admin Pass: {}", admin_password);
let tguser = msg.from.clone().unwrap();
let user = db
.get_or_init_user(msg.from.clone().unwrap().id.0 as i64)
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
.await;
println!("MSG: {}", msg.html_text().unwrap());
match cmd {

View File

@ -62,7 +62,7 @@ impl DB {
.unwrap();
}
pub async fn get_or_init_user(&mut self, userid: i64) -> User {
pub async fn get_or_init_user(&mut self, userid: i64, firstname: &str) -> User {
use self::schema::users::dsl::*;
let connection = &mut self.pool.get().await.unwrap();
@ -76,7 +76,11 @@ impl DB {
match user {
Some(existing_user) => existing_user,
None => diesel::insert_into(users)
.values((id.eq(userid as i64), is_admin.eq(false)))
.values((
id.eq(userid as i64),
is_admin.eq(false),
first_name.eq(firstname),
))
.get_result(connection)
.await
.unwrap(),
@ -212,4 +216,48 @@ impl DB {
Ok(new_event)
}
pub async fn get_media(
&mut self,
literal: &str,
) -> Result<Vec<Media>, Box<dyn std::error::Error>> {
use self::schema::media::dsl::*;
let conn = &mut self.pool.get().await.unwrap();
let media_items = media.filter(token.eq(literal)).load::<Media>(conn).await?;
Ok(media_items)
}
pub async fn drop_media(&mut self, literal: &str) -> Result<usize, Box<dyn std::error::Error>> {
use self::schema::media::dsl::*;
let conn = &mut self.pool.get().await.unwrap();
let deleted_count = diesel::delete(media.filter(token.eq(literal)))
.execute(conn)
.await?;
Ok(deleted_count)
}
pub async fn add_media(
&mut self,
literal: &str,
mediatype: String,
fileid: i64,
) -> Result<Media, Box<dyn std::error::Error>> {
use self::schema::media::dsl::*;
let conn = &mut self.pool.get().await.unwrap();
let new_media = diesel::insert_into(media)
.values((
token.eq(literal),
media_type.eq(mediatype),
file_id.eq(fileid),
))
.get_result::<Media>(conn)
.await?;
Ok(new_media)
}
}

View File

@ -24,6 +24,15 @@ pub struct Literal {
pub value: String,
}
#[derive(Queryable, Debug, Identifiable)]
#[diesel(table_name = media)]
pub struct Media {
pub id: i32,
pub token: String,
pub media_type: String,
pub file_id: String,
}
#[derive(Queryable, Debug, Identifiable)]
#[diesel(table_name = messages)]
pub struct Message {

View File

@ -16,6 +16,15 @@ diesel::table! {
}
}
diesel::table! {
media (id) {
id -> Int4,
token -> Varchar,
media_type -> Varchar,
file_id -> Varchar,
}
}
diesel::table! {
messages (id) {
id -> Int4,
@ -66,6 +75,7 @@ diesel::joinable!(reservations -> users (user_id));
diesel::allow_tables_to_appear_in_same_query!(
events,
literals,
media,
messages,
reservations,
teloxide_dialogues,

View File

@ -11,8 +11,10 @@ use db::schema::events;
use envconfig::Envconfig;
use serde::{Deserialize, Serialize};
use teloxide::dispatching::dialogue::serializer::Json;
use teloxide::dispatching::dialogue::{InMemStorage, PostgresStorage};
use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup};
use teloxide::dispatching::dialogue::{GetChatId, InMemStorage, PostgresStorage};
use teloxide::types::{
InlineKeyboardButton, InlineKeyboardMarkup, MediaKind, MessageKind, ReplyMarkup,
};
use teloxide::{
payloads::SendMessageSetters,
prelude::*,
@ -90,17 +92,23 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.inspect(|u: Update| {
eprintln!("{u:#?}"); // Print the update to the console with inspect
})
.branch(Update::filter_callback_query().endpoint(callback_handler))
.branch(command_handler(config))
.branch(
Update::filter_message()
.filter_async(async |msg: Message, mut db: DB| {
let user = db.get_or_init_user(msg.from.unwrap().id.0 as i64).await;
let tguser = msg.from.unwrap();
let user = db
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
.await;
user.is_admin
})
.enter_dialogue::<Message, PostgresStorage<Json>, State>()
.branch(
Update::filter_message()
.filter(|msg: Message| msg.text().unwrap_or("") == "edit")
.filter(|msg: Message| {
msg.text().unwrap_or("").to_lowercase().as_str() == "edit"
})
.endpoint(edit_msg_cmd_handler),
)
.branch(dptree::case![State::Edit { literal, lang }].endpoint(edit_msg_handler)),
@ -117,6 +125,35 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
async fn callback_handler(
bot: Bot,
mut db: DB,
q: CallbackQuery,
) -> Result<(), teloxide::RequestError> {
bot.answer_callback_query(&q.id).await?;
if let Some(ref data) = q.data {
match data.as_str() {
"more_info" => {
answer_message(
&bot,
q.chat_id()
.clone()
.map(|i| i.0)
.unwrap_or(q.from.id.0 as i64),
&mut db,
"more_info",
None as Option<InlineKeyboardMarkup>,
)
.await?
}
_ => {} // do nothing, yet
}
}
Ok(())
}
async fn edit_msg_cmd_handler(
bot: Bot,
mut db: DB,
@ -165,16 +202,28 @@ async fn edit_msg_handler(
(literal, lang): (String, String),
msg: Message,
) -> Result<(), teloxide::RequestError> {
match msg.html_text() {
Some(text) => {
db.set_literal(&literal, &text).await.unwrap();
bot.send_message(msg.chat.id, "Updated text of message!")
.await
.unwrap();
use teloxide::utils::render::Renderer;
let chat_id = msg.chat.id;
println!("Type: {:#?}", msg.kind);
let msg = if let MessageKind::Common(msg) = msg.kind {
msg
} else {
println!("Not a Common, somehow");
return Ok(());
};
match msg.media_kind {
MediaKind::Text(text) => {
let html_text = Renderer::new(&text.text, &text.entities).as_html();
db.set_literal(&literal, &html_text).await.unwrap();
bot.send_message(chat_id, "Updated text of message!")
.await?;
dialogue.exit().await.unwrap();
}
None => {
bot.send_message(msg.chat.id, "Send text!").await.unwrap();
_ => {
bot.send_message(chat_id, "this type of message is not supported yet")
.await?;
}
}
@ -204,7 +253,10 @@ fn command_handler(
.branch(
dptree::entry()
.filter_async(async |msg: Message, mut db: DB| {
let user = db.get_or_init_user(msg.from.unwrap().id.0 as i64).await;
let tguser = msg.from.unwrap();
let user = db
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
.await;
user.is_admin
})
.filter_command::<AdminCommands>()
@ -218,27 +270,22 @@ async fn user_command_handler(
msg: Message,
cmd: UserCommands,
) -> Result<(), teloxide::RequestError> {
let tguser = msg.from.clone().unwrap();
let user = db
.get_or_init_user(msg.from.clone().unwrap().id.0 as i64)
.get_or_init_user(tguser.id.0 as i64, &tguser.first_name)
.await;
println!("MSG: {}", msg.html_text().unwrap());
match cmd {
UserCommands::Start => {
let literal = "start";
let text = db
.get_literal_value(literal)
let mut db2 = db.clone();
answer_message(
&bot,
msg.chat.id.0,
&mut db,
"start",
Some(make_start_buttons(&mut db2).await),
)
.await
.unwrap()
.unwrap_or("Please, set content of this message".into());
let msg = bot
.send_message(msg.chat.id, text)
.reply_markup(make_start_buttons(&mut db).await)
.parse_mode(teloxide::types::ParseMode::Html)
.await?;
db.set_message_literal(msg.chat.id.0, msg.id.0, literal)
.await
.unwrap();
Ok(())
}
UserCommands::Help => {
bot.send_message(msg.chat.id, UserCommands::descriptions().to_string())
@ -248,6 +295,32 @@ async fn user_command_handler(
}
}
async fn answer_message<RM: Into<ReplyMarkup>>(
bot: &Bot,
chat_id: i64,
db: &mut DB,
literal: &str,
keyboard: Option<RM>,
) -> Result<(), teloxide::RequestError> {
let text = db
.get_literal_value(literal)
.await
.unwrap()
.unwrap_or("Please, set content of this message".into());
let msg = bot.send_message(ChatId(chat_id), text);
let msg = match keyboard {
Some(kbd) => msg.reply_markup(kbd),
None => msg,
};
let msg = msg.parse_mode(teloxide::types::ParseMode::Html);
println!("ENTS: {:?}", msg.entities);
let msg = msg.await?;
db.set_message_literal(msg.chat.id.0, msg.id.0, literal)
.await
.unwrap();
Ok(())
}
async fn make_start_buttons(db: &mut DB) -> InlineKeyboardMarkup {
let mut buttons: Vec<Vec<InlineKeyboardButton>> = db
.get_all_events()