Skip to content

Commit

Permalink
build: add thiserror, dotenv, update teloxide
Browse files Browse the repository at this point in the history
refactor: change bot architecture

build: add chrono, update rusqlite

feat: add command /add:

- insert, select catigories,hometasks,users in database
- add pagination pages to command /add
- add commands: add,cancel,help
- add validation deadline
  • Loading branch information
DmitroPodolsky authored and nezutero committed Feb 19, 2024
1 parent 21f875b commit 301915c
Show file tree
Hide file tree
Showing 9 changed files with 547 additions and 191 deletions.
304 changes: 141 additions & 163 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 5 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@
name = "hh"
version = "0.1.0"
edition = "2021"
authors = ["github.com/DmitroPodolsky", "github.com/geekenji"]
description = "Centralized platform to manage and access your university homework information."
license = "MIT"
repository = "github.com/seadclub/hh.git"
readme = "README.md"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
log = "0.4.20"
pretty_env_logger = "0.5.0"
rusqlite = "0.30.0"
teloxide = "0.12.2"
rusqlite = { version = "0.30.0", features = ["bundled"] }
teloxide = { version = "0.12.2", features = ["macros"] }
tokio = { version = "1.36.0", features = ["full"] }
dotenv = "0.15.0"
thiserror = "1.0.56"
chrono = "0.4.34"
43 changes: 43 additions & 0 deletions src/commands.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use crate::models::{State, Command};
use crate::telegram::basic_methods::*;
use teloxide::dispatching::dialogue::InMemStorage;
use teloxide::dispatching::{dialogue, DpHandlerDescription};
use teloxide::dptree;
use teloxide::dptree::{case, Handler};
use teloxide::prelude::*;


pub fn schema() -> Handler<'static, DependencyMap, crate::errors::Result<()>, DpHandlerDescription>
{
let command_handler = teloxide::filter_command::<Command, _>()
.branch(
case![State::Start]
.branch(case![Command::Help].endpoint(help))
.branch(case![Command::Add].endpoint(add)),
)
.branch(case![Command::Cancel].endpoint(cancel));

let callback_query_handler = Update::filter_callback_query().branch(
case![State::ReceiveProductChoice].endpoint(receive_add_button),
);

// let callback_query_handler = Update::filter_message()
// .branch(case![State::GetEmail { phone_number }].endpoint(get_email))
// .branch(case![State::GetAge { phone_number }].endpoint(get_age))
// .branch(case![State::GetWeightAndHeight { phone_number }].endpoint(get_height_and_weight));

let message_handler = Update::filter_message()
.branch(command_handler)
// .branch(case![State::GetPhoneNumber].endpoint(get_number))
// .branch(case![State::HomeTrainingMenu { phone_number }].endpoint(home_training_menu))
// .branch(case![State::GymTrainingMenu { phone_number }].endpoint(gym_training_menu))
.branch(case![State::CreateCategorie].endpoint(send_categorie))
.branch(case![State::AddTaskName { categorie }].endpoint(send_taskname))
.branch(case![State::AddDescription { categorie, taskname }].endpoint(send_description))
.branch(case![State::CreateTask { categorie, taskname, description }].endpoint(send_deadline))
.branch(dptree::endpoint(invalid_state));


dialogue::enter::<Update, InMemStorage<State>, State, _>().branch(message_handler).branch(callback_query_handler)
//State::Start - initial state
}
73 changes: 71 additions & 2 deletions src/db.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use rusqlite::Connection;
use rusqlite::{Connection, Error};

use crate::models::MyDialogue;

pub fn create_db() {
let conn = Connection::open("your_database.db").expect("Failed to open database");
Expand Down Expand Up @@ -33,4 +35,71 @@ pub fn create_db() {
).expect("Failed to create homework_hub table");

log::info!("created database successfully!");
}
}

pub fn select_all_categories() -> Result<Vec<String>, Error> {
let conn = Connection::open("your_database.db")?;

let mut stmt = conn.prepare("SELECT name FROM category")?;

let category_iter = stmt.query_map([], |row| {
Ok(row.get(0)?)
})?;

let mut categories = Vec::new();

for name in category_iter {
categories.push(name?);
}

Ok(categories)
}

pub fn insert_user(msg: MyDialogue) -> Result<(), Error> {
let conn = Connection::open("your_database.db")?;

let mut stmt = conn.prepare("SELECT COUNT(*) FROM users WHERE id = ?")?;
let user_exists: i64 = stmt.query_row([msg.chat_id().to_string()], |row| row.get(0))?;

if user_exists == 0 {
conn.execute("INSERT INTO users(id) VALUES (?)", [&msg.chat_id().to_string()])?;
} else {

}

Ok(())
}

pub fn insert_category(name: &str) -> Result<(), Error> {
let conn = Connection::open("your_database.db")?;

conn.execute(
"INSERT INTO category (name) VALUES (?)",
&[name],
)?;

Ok(())
}

pub fn select_categorie(name: &str) -> Result<i32, Error> {
let conn = Connection::open("your_database.db")?;

let category_id: i32 = conn.query_row(
"SELECT id FROM category WHERE name = ?",
&[name],
|row| row.get(0)
)?;

Ok(category_id)
}

pub fn insert_homework(name: &str, desc: &str, deadline: &str, category_id: &i32, msg: MyDialogue) -> Result<(), Error> {
let conn = Connection::open("your_database.db")?;

conn.execute(
"INSERT INTO homework_hub (name, desc, deadline, category_id, user_id) VALUES (?, ?, ?, ?, ?)",
&[name, desc, deadline, &category_id.to_string(), &msg.chat_id().to_string()],
)?;

Ok(())
}
18 changes: 18 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#[allow(clippy::enum_variant_names)]
#[derive(Debug, thiserror::Error)]
pub enum Errors {
#[error(transparent)]
EnvError(#[from] dotenv::Error),

#[error(transparent)]
TeloxideError(#[from] teloxide::RequestError),

#[error(transparent)]
InMemStorageError(#[from] teloxide::dispatching::dialogue::InMemStorageError),


#[error(transparent)]
ParseIntError(#[from] std::num::ParseIntError),
}

pub type Result<T> = std::result::Result<T, Errors>;
41 changes: 22 additions & 19 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
pub mod bot;
pub mod telegram;
pub mod db;

use crate::errors::Result;
use crate::commands::schema;
use crate::models::State;
use dotenv::dotenv;
use std::sync::Arc;
use db::create_db;
use bot::*;
use teloxide::{dispatching::dialogue::InMemStorage, prelude::*};
use teloxide::dispatching::dialogue::InMemStorage;
use teloxide::prelude::*;

mod models;
mod commands;
mod errors;

#[tokio::main]
async fn main() {
async fn main() -> Result<()> {
dotenv().ok();
log::info!("Starting dialogue bot...");
create_db();
pretty_env_logger::init();

let bot = Bot::from_env();
let bot = Bot::new(dotenv::var("TELOXIDE_TOKEN")?);
let state = Arc::new(State::Start);

Dispatcher::builder(
bot,
Update::filter_message()
.enter_dialogue::<Message, InMemStorage<State>, State>()
.branch(dptree::case![State::Start].endpoint(start))
.branch(dptree::case![State::ReceiveFullName].endpoint(receive_full_name))
.branch(dptree::case![State::ReceiveAge { full_name }].endpoint(receive_age))
.branch(
dptree::case![State::ReceiveLocation { full_name, age }].endpoint(receive_location),
),
)
.dependencies(dptree::deps![InMemStorage::<State>::new()])
Dispatcher::builder(bot, schema())
.dependencies(dptree::deps![
InMemStorage::<State>::new(),
Arc::clone(&state)
])
.enable_ctrlc_handler()
.build()
.dispatch()
.await;
Ok(())
}
32 changes: 32 additions & 0 deletions src/models.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

use teloxide::dispatching::dialogue::InMemStorage;
use teloxide::prelude::Dialogue;
use teloxide::utils::command::BotCommands;

pub type MyDialogue = Dialogue<State, InMemStorage<State>>;

/// These commands are supported:
#[derive(BotCommands, Clone)]
#[command(
rename_rule = "lowercase",
description = "These commands are supported:"
)]
pub enum Command {
#[command(description = "display this text.")]
Help,
#[command(description = "cancel the purchase procedure.")]
Cancel,
#[command(description = "create new hometask")]
Add,
}

#[derive(Clone, Default)]
pub enum State {
#[default]
Start,
ReceiveProductChoice,
CreateCategorie,
AddTaskName { categorie: String },
AddDescription { categorie: String, taskname: String },
CreateTask { categorie: String, taskname: String, description: String },
}
Loading

0 comments on commit 301915c

Please sign in to comment.