Compare commits
12 Commits
4ea77e0444
...
cca87da403
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cca87da403 | ||
|
|
98be2b0f7d | ||
|
|
e9a44a221d | ||
|
|
2bad5d79c7 | ||
|
|
f7ced4b780 | ||
|
|
f619b1d375 | ||
|
|
15813901d8 | ||
|
|
1d3ec66b11 | ||
|
|
9ac297cf5a | ||
|
|
dda5fd5a93 | ||
|
|
3656c1be6d | ||
|
|
fc8f98c2fa |
93
Cargo.lock
generated
93
Cargo.lock
generated
@ -17,6 +17,15 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "allocator-api2"
|
name = "allocator-api2"
|
||||||
version = "0.2.21"
|
version = "0.2.21"
|
||||||
@ -173,11 +182,34 @@ checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"android-tzdata",
|
"android-tzdata",
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono-tz"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "efdce149c370f133a071ca8ef6ea340b7b88748ab0810097a9e2976eaa34b4f3"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"chrono-tz-build",
|
||||||
|
"phf",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono-tz-build"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f10f8c9340e31fc120ff885fcdb54a0b48e474bbd77cab557f0c30a3e569402"
|
||||||
|
dependencies = [
|
||||||
|
"parse-zoneinfo",
|
||||||
|
"phf_codegen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@ -335,6 +367,7 @@ checksum = "470eb10efc8646313634c99bb1593f402a6434cbd86e266770c6e39219adb86a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"chrono",
|
||||||
"diesel_derives",
|
"diesel_derives",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pq-sys",
|
"pq-sys",
|
||||||
@ -731,6 +764,8 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
|||||||
name = "gongbotrs"
|
name = "gongbotrs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"chrono-tz",
|
||||||
"diesel",
|
"diesel",
|
||||||
"diesel-async",
|
"diesel-async",
|
||||||
"diesel-derive-enum",
|
"diesel-derive-enum",
|
||||||
@ -1365,6 +1400,15 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parse-zoneinfo"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24"
|
||||||
|
dependencies = [
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
@ -1380,6 +1424,26 @@ dependencies = [
|
|||||||
"phf_shared",
|
"phf_shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_codegen"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator",
|
||||||
|
"phf_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared",
|
||||||
|
"rand 0.8.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_shared"
|
||||||
version = "0.11.3"
|
version = "0.11.3"
|
||||||
@ -1604,6 +1668,35 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.15"
|
version = "0.12.15"
|
||||||
|
|||||||
@ -6,7 +6,9 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
diesel = { version = "2.2.8", features = ["postgres"] }
|
chrono = "0.4.40"
|
||||||
|
chrono-tz = "0.10.3"
|
||||||
|
diesel = { version = "2.2.8", features = ["postgres", "chrono"] }
|
||||||
diesel-async = { version = "0.5.2", features = ["bb8", "postgres"] }
|
diesel-async = { version = "0.5.2", features = ["bb8", "postgres"] }
|
||||||
diesel-derive-enum = "2.1.0"
|
diesel-derive-enum = "2.1.0"
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
[tasks.gen-models]
|
[tasks.models]
|
||||||
install_crate = "diesel_cli_ext"
|
install_crate = "diesel_cli_ext"
|
||||||
command = "sh"
|
command = "sh"
|
||||||
args = ["-c", "diesel_ext --model -t > src/db/models.rs"]
|
args = ["-c", "diesel_ext -I 'crate::db::schema::*' --model -t > src/db/models.rs"]
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE reservations
|
||||||
|
ALTER COLUMN user_id TYPE INTEGER;
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE reservations
|
||||||
|
ALTER COLUMN user_id TYPE BIGINT;
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE reservations
|
||||||
|
ALTER COLUMN user_id DROP NOT NULL,
|
||||||
|
ALTER COLUMN entered_name DROP NOT NULL,
|
||||||
|
ALTER COLUMN event_id DROP NOT NULL;
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE reservations
|
||||||
|
ALTER COLUMN user_id SET NOT NULL,
|
||||||
|
ALTER COLUMN entered_name SET NOT NULL,
|
||||||
|
ALTER COLUMN event_id SET NOT NULL;
|
||||||
2
migrations/2025-04-07-153426_event_timestamptz/down.sql
Normal file
2
migrations/2025-04-07-153426_event_timestamptz/down.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE events
|
||||||
|
ALTER COLUMN time TYPE TIMESTAMP;
|
||||||
2
migrations/2025-04-07-153426_event_timestamptz/up.sql
Normal file
2
migrations/2025-04-07-153426_event_timestamptz/up.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE events
|
||||||
|
ALTER COLUMN time TYPE TIMESTAMPTZ;
|
||||||
26
src/db.rs
26
src/db.rs
@ -4,6 +4,7 @@ use crate::Config;
|
|||||||
|
|
||||||
use self::models::*;
|
use self::models::*;
|
||||||
|
|
||||||
|
use chrono::Utc;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel_async::pooled_connection::bb8::Pool;
|
use diesel_async::pooled_connection::bb8::Pool;
|
||||||
use diesel_async::pooled_connection::AsyncDieselConnectionManager;
|
use diesel_async::pooled_connection::AsyncDieselConnectionManager;
|
||||||
@ -186,4 +187,29 @@ impl DB {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_all_events(&mut self) -> Vec<Event> {
|
||||||
|
use self::schema::events::dsl::*;
|
||||||
|
let mut conn = self.pool.get().await.unwrap();
|
||||||
|
events
|
||||||
|
.filter(id.gt(0))
|
||||||
|
.load::<Event>(&mut conn)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_event(
|
||||||
|
&mut self,
|
||||||
|
event_datetime: chrono::DateTime<Utc>,
|
||||||
|
) -> Result<Event, Box<dyn std::error::Error>> {
|
||||||
|
use self::schema::events::dsl::*;
|
||||||
|
let conn = &mut self.pool.get().await.unwrap();
|
||||||
|
|
||||||
|
let new_event = diesel::insert_into(events)
|
||||||
|
.values((time.eq(event_datetime),))
|
||||||
|
.get_result::<Event>(conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(new_event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,14 +3,17 @@
|
|||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![allow(clippy::all)]
|
#![allow(clippy::all)]
|
||||||
|
|
||||||
|
use crate::db::schema::*;
|
||||||
|
|
||||||
|
use chrono::offset::Utc;
|
||||||
|
use chrono::DateTime;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
#[derive(Queryable, Debug, Identifiable)]
|
#[derive(Queryable, Debug, Identifiable)]
|
||||||
#[diesel(table_name = events)]
|
#[diesel(table_name = events)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub time: NaiveDateTime,
|
pub time: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Debug, Identifiable)]
|
#[derive(Queryable, Debug, Identifiable)]
|
||||||
@ -34,10 +37,10 @@ pub struct Message {
|
|||||||
#[diesel(table_name = reservations)]
|
#[diesel(table_name = reservations)]
|
||||||
pub struct Reservation {
|
pub struct Reservation {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub user_id: Option<i32>,
|
pub user_id: i64,
|
||||||
pub entered_name: Option<String>,
|
pub entered_name: String,
|
||||||
pub booked_time: NaiveDateTime,
|
pub booked_time: NaiveDateTime,
|
||||||
pub event_id: Option<i32>,
|
pub event_id: i32,
|
||||||
pub status: String,
|
pub status: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,4 +62,3 @@ pub struct User {
|
|||||||
pub username: Option<String>,
|
pub username: Option<String>,
|
||||||
pub language_code: Option<String>,
|
pub language_code: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
diesel::table! {
|
diesel::table! {
|
||||||
events (id) {
|
events (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
time -> Timestamp,
|
time -> Timestamptz,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,11 +29,11 @@ diesel::table! {
|
|||||||
diesel::table! {
|
diesel::table! {
|
||||||
reservations (id) {
|
reservations (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
user_id -> Nullable<Int4>,
|
user_id -> Int8,
|
||||||
#[max_length = 255]
|
#[max_length = 255]
|
||||||
entered_name -> Nullable<Varchar>,
|
entered_name -> Varchar,
|
||||||
booked_time -> Timestamp,
|
booked_time -> Timestamp,
|
||||||
event_id -> Nullable<Int4>,
|
event_id -> Int4,
|
||||||
status -> Varchar,
|
status -> Varchar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/main.rs
39
src/main.rs
@ -5,10 +5,14 @@ use crate::admin::{admin_command_handler, AdminCommands};
|
|||||||
use crate::admin::{secret_command_handler, SecretCommands};
|
use crate::admin::{secret_command_handler, SecretCommands};
|
||||||
use crate::db::DB;
|
use crate::db::DB;
|
||||||
|
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use chrono_tz::Asia;
|
||||||
|
use db::schema::events;
|
||||||
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::{InMemStorage, PostgresStorage};
|
use teloxide::dispatching::dialogue::{InMemStorage, PostgresStorage};
|
||||||
|
use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup};
|
||||||
use teloxide::{
|
use teloxide::{
|
||||||
payloads::SendMessageSetters,
|
payloads::SendMessageSetters,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@ -68,6 +72,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let db_url2 = config.db_url.clone();
|
let db_url2 = config.db_url.clone();
|
||||||
let state_mgr = PostgresStorage::open(&db_url2, 8, Json).await?;
|
let state_mgr = PostgresStorage::open(&db_url2, 8, Json).await?;
|
||||||
|
|
||||||
|
// TODO: delete this in production
|
||||||
|
let events: Vec<DateTime<Utc>> = vec!["2025-04-09T18:00:00+04:00", "2025-04-11T16:00:00+04:00"]
|
||||||
|
.iter()
|
||||||
|
.map(|d| DateTime::parse_from_rfc3339(d).unwrap().into())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for event in events {
|
||||||
|
match db.clone().create_event(event).await {
|
||||||
|
Ok(e) => println!("Created event {}", e.id),
|
||||||
|
Err(err) => println!("Failed to create event, error: {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
let handler = dptree::entry()
|
let handler = dptree::entry()
|
||||||
.inspect(|u: Update| {
|
.inspect(|u: Update| {
|
||||||
eprintln!("{u:#?}"); // Print the update to the console with inspect
|
eprintln!("{u:#?}"); // Print the update to the console with inspect
|
||||||
@ -214,6 +232,7 @@ async fn user_command_handler(
|
|||||||
.unwrap_or("Please, set content of this message".into());
|
.unwrap_or("Please, set content of this message".into());
|
||||||
let msg = bot
|
let msg = bot
|
||||||
.send_message(msg.chat.id, text)
|
.send_message(msg.chat.id, text)
|
||||||
|
.reply_markup(make_start_buttons(&mut db).await)
|
||||||
.parse_mode(teloxide::types::ParseMode::Html)
|
.parse_mode(teloxide::types::ParseMode::Html)
|
||||||
.await?;
|
.await?;
|
||||||
db.set_message_literal(msg.chat.id.0, msg.id.0, literal)
|
db.set_message_literal(msg.chat.id.0, msg.id.0, literal)
|
||||||
@ -229,6 +248,26 @@ async fn user_command_handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn make_start_buttons(db: &mut DB) -> InlineKeyboardMarkup {
|
||||||
|
let mut buttons: Vec<Vec<InlineKeyboardButton>> = db
|
||||||
|
.get_all_events()
|
||||||
|
.await
|
||||||
|
.iter()
|
||||||
|
.map(|e| {
|
||||||
|
vec![InlineKeyboardButton::callback(
|
||||||
|
e.time.with_timezone(&Asia::Dubai).to_string(),
|
||||||
|
format!("event:{}", e.id),
|
||||||
|
)]
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
buttons.push(vec![InlineKeyboardButton::callback(
|
||||||
|
"More info",
|
||||||
|
"more_info",
|
||||||
|
)]);
|
||||||
|
|
||||||
|
InlineKeyboardMarkup::new(buttons)
|
||||||
|
}
|
||||||
|
|
||||||
async fn echo(bot: Bot, msg: Message) -> Result<(), teloxide::RequestError> {
|
async fn echo(bot: Bot, msg: Message) -> Result<(), teloxide::RequestError> {
|
||||||
if let Some(photo) = msg.photo() {
|
if let Some(photo) = msg.photo() {
|
||||||
println!("File ID: {}", photo[0].file.id);
|
println!("File ID: {}", photo[0].file.id);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user