mirror of
https://github.com/FliegendeWurst/telegram_notes_bot.git
synced 2024-11-22 10:54:57 +00:00
/next command to display upcoming events
This commit is contained in:
parent
32cae2d119
commit
d0d19fbd72
133
src/main.rs
133
src/main.rs
@ -74,7 +74,10 @@ async fn process_one(update: Update, context: &mut Context) -> Result<(), Error>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let MessageKind::Text { ref data, .. } = message.kind {
|
if let MessageKind::Text { ref data, .. } = message.kind {
|
||||||
if data == "/remindme" {
|
if data == "/next" {
|
||||||
|
command_next().await?;
|
||||||
|
return Ok(());
|
||||||
|
} else if data == "/remindme" {
|
||||||
let mut msg = SendMessage::new(*OWNER, "in 0m: new reminder");
|
let mut msg = SendMessage::new(*OWNER, "in 0m: new reminder");
|
||||||
msg.reply_markup(get_keyboard());
|
msg.reply_markup(get_keyboard());
|
||||||
*reminder_msg = API.send(msg).await?.to_message_id();
|
*reminder_msg = API.send(msg).await?.to_message_id();
|
||||||
@ -229,6 +232,49 @@ async fn create_text_note(client: &Client, trilium_token: &str, title: &str, con
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn command_next() -> Result<(), Error> {
|
||||||
|
let events = request_event_alerts().await?;
|
||||||
|
let tasks = request_task_alerts().await?;
|
||||||
|
let mut all: Vec<_> = events.into_iter().map(EventOrTask::Event).chain(tasks.into_iter().map(EventOrTask::Task)).collect();
|
||||||
|
all.sort_by_key(|x| x.time());
|
||||||
|
let mut printed = 0;
|
||||||
|
let now = Local::now();
|
||||||
|
let mut buf = String::new();
|
||||||
|
for x in all {
|
||||||
|
let time = x.time();
|
||||||
|
if time < now {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buf += &format!("{} {}\n", time.format("%Y-%m-%d %H:%M").to_string(), x.description());
|
||||||
|
printed += 1;
|
||||||
|
if printed >= 10 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
send_message(buf).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EventOrTask {
|
||||||
|
Event(UsefulEvent),
|
||||||
|
Task(UsefulTask)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventOrTask {
|
||||||
|
fn time(&self) -> DateTime<Local> {
|
||||||
|
match self {
|
||||||
|
EventOrTask::Event(e) => e.todo_time,
|
||||||
|
EventOrTask::Task(t) => t.todo_time,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
EventOrTask::Event(e) => &e.event.name,
|
||||||
|
EventOrTask::Task(t) => &t.task.title,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// image note:
|
// image note:
|
||||||
// curl /api/clipper/clippings -H 'Accept: */*' -H 'Accept-Language: en' --compressed -H 'Content-Type: application/json' -H 'Authorization: icB3xohFDpkVt7YFpbTflUYC8pucmryVGpb1DFpd6ns=' -H 'Origin: moz-extension://13bc3fd7-5cb0-4d48-b368-76e389fd7c5f' --data $'{"title":"trilium/clipper.js at master \xb7 zadam/trilium","content":"<img src=\\"BoCpsLz9je8a01MdGbj4\\">","images":[{"imageId":"BoCpsLz9je8a01MdGbj4","src":"inline.png","dataUrl":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASkAAAESCAYAAAChJCPsAAAgAElEQV"}]}'
|
// curl /api/clipper/clippings -H 'Accept: */*' -H 'Accept-Language: en' --compressed -H 'Content-Type: application/json' -H 'Authorization: icB3xohFDpkVt7YFpbTflUYC8pucmryVGpb1DFpd6ns=' -H 'Origin: moz-extension://13bc3fd7-5cb0-4d48-b368-76e389fd7c5f' --data $'{"title":"trilium/clipper.js at master \xb7 zadam/trilium","content":"<img src=\\"BoCpsLz9je8a01MdGbj4\\">","images":[{"imageId":"BoCpsLz9je8a01MdGbj4","src":"inline.png","dataUrl":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASkAAAESCAYAAAChJCPsAAAgAElEQV"}]}'
|
||||||
|
|
||||||
@ -245,28 +291,37 @@ async fn event_alerts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn event_alerts_soon() -> Result<(), Error> {
|
async fn request_event_alerts() -> Result<Vec<UsefulEvent>, Error> {
|
||||||
let now = Local::now();
|
|
||||||
|
|
||||||
let text = CLIENT.get(&trilium_url("/custom/event_alerts")).send().await?.text().await?;
|
let text = CLIENT.get(&trilium_url("/custom/event_alerts")).send().await?.text().await?;
|
||||||
debug!("event_alerts response {}", text);
|
debug!("event_alerts response {}", text);
|
||||||
let events: Result<Vec<Event>, _> = serde_json::from_str(&text);
|
let events: Result<Vec<Event>, _> = serde_json::from_str(&text);
|
||||||
if events.is_err() {
|
if events.is_err() {
|
||||||
eprintln!("failed to parse {}", text);
|
eprintln!("failed to parse {}", text);
|
||||||
events?;
|
|
||||||
unreachable!() // needed to please the borrow checker
|
|
||||||
}
|
}
|
||||||
let events = events.unwrap();
|
let events = events.map(|x| x.into_iter().flat_map(|event| {
|
||||||
|
let todo_time: DateTime<Local> = TimeZone::from_local_datetime(&Local,
|
||||||
|
&NaiveDateTime::parse_from_str(&event.start_time, "%Y-%m-%dT%H:%M:%S").ok()?).unwrap();
|
||||||
|
Some(UsefulEvent {
|
||||||
|
event,
|
||||||
|
todo_time
|
||||||
|
})
|
||||||
|
}).collect());
|
||||||
|
Ok(events?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn event_alerts_soon() -> Result<(), Error> {
|
||||||
|
let now = Local::now();
|
||||||
|
|
||||||
|
let events = request_event_alerts().await?;
|
||||||
debug!("events_alerts: {} objects", events.len());
|
debug!("events_alerts: {} objects", events.len());
|
||||||
for event in events {
|
for event in events {
|
||||||
let todo_time: DateTime<Local> = TimeZone::from_local_datetime(&Local, &NaiveDateTime::parse_from_str(&event.start_time, "%Y-%m-%dT%H:%M:%S")?).unwrap();
|
if event.todo_time <= now {
|
||||||
if todo_time <= now {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let diff = todo_time - now;
|
let diff = event.todo_time - now;
|
||||||
let minutes = diff.num_minutes();
|
let minutes = diff.num_minutes();
|
||||||
if minutes == 7 * 24 * 60 || minutes == 48 * 60 || minutes == 24 * 60 || minutes == 60 || minutes == 10 {
|
if minutes == 7 * 24 * 60 || minutes == 48 * 60 || minutes == 24 * 60 || minutes == 60 || minutes == 10 {
|
||||||
event_alert_notify(&format_time(diff), event).await?;
|
event_alert_notify(&format_time(diff), event.event).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -284,6 +339,11 @@ struct Event {
|
|||||||
start_time: String,
|
start_time: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UsefulEvent {
|
||||||
|
event: Event,
|
||||||
|
todo_time: DateTime<Local>,
|
||||||
|
}
|
||||||
|
|
||||||
async fn task_alerts() {
|
async fn task_alerts() {
|
||||||
loop {
|
loop {
|
||||||
let last_min = Local::now().minute();
|
let last_min = Local::now().minute();
|
||||||
@ -297,24 +357,17 @@ async fn task_alerts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn task_alerts_soon() -> Result<(), Error> {
|
async fn request_task_alerts() -> Result<Vec<UsefulTask>, Error> {
|
||||||
let now = Local::now();
|
|
||||||
|
|
||||||
let text = CLIENT.get(&trilium_url("/custom/task_alerts")).send().await?.text().await?;
|
let text = CLIENT.get(&trilium_url("/custom/task_alerts")).send().await?.text().await?;
|
||||||
debug!("task_alerts response {}", text);
|
debug!("task_alerts response {}", text);
|
||||||
let tasks: Result<Vec<Task>, _> = serde_json::from_str(&text);
|
let tasks: Result<Vec<Task>, _> = serde_json::from_str(&text);
|
||||||
if tasks.is_err() {
|
if tasks.is_err() {
|
||||||
eprintln!("failed to parse {}", text);
|
eprintln!("failed to parse {}", text);
|
||||||
tasks?;
|
|
||||||
unreachable!() // needed to please the borrow checker
|
|
||||||
}
|
}
|
||||||
let tasks = tasks.unwrap();
|
let tasks = tasks.map(|tasks| tasks.into_iter().flat_map(|task| {
|
||||||
debug!("task_alerts: {} objects", tasks.len());
|
|
||||||
'task: for task in tasks {
|
|
||||||
let mut todo_date = None;
|
let mut todo_date = None;
|
||||||
let mut todo_time = None;
|
let mut todo_time = None;
|
||||||
let mut is_reminder = false;
|
let mut is_reminder = false;
|
||||||
//println!("considering {:?} with {:?}", task.title, task.attributes);
|
|
||||||
for attribute in &task.attributes {
|
for attribute in &task.attributes {
|
||||||
if attribute.r#type != "label" {
|
if attribute.r#type != "label" {
|
||||||
continue;
|
continue;
|
||||||
@ -322,14 +375,14 @@ async fn task_alerts_soon() -> Result<(), Error> {
|
|||||||
match &*attribute.name {
|
match &*attribute.name {
|
||||||
"todoDate" => todo_date = Some(attribute.value.as_str().unwrap().to_owned()),
|
"todoDate" => todo_date = Some(attribute.value.as_str().unwrap().to_owned()),
|
||||||
"todoTime" => todo_time = Some(attribute.value.as_str().unwrap().to_owned()),
|
"todoTime" => todo_time = Some(attribute.value.as_str().unwrap().to_owned()),
|
||||||
"doneDate" => continue 'task,
|
"doneDate" => return None,
|
||||||
"reminder" => is_reminder = true,
|
"reminder" => is_reminder = true,
|
||||||
"canceled" => if attribute.value.as_str().unwrap() == "true" { continue 'task },
|
"canceled" => if attribute.value.as_str().unwrap() == "true" { return None },
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if todo_date.is_none() {
|
if todo_date.is_none() {
|
||||||
continue;
|
return None;
|
||||||
}
|
}
|
||||||
let todo_date = todo_date.unwrap();
|
let todo_date = todo_date.unwrap();
|
||||||
let parts = todo_date.split('-').collect::<Vec<_>>();
|
let parts = todo_date.split('-').collect::<Vec<_>>();
|
||||||
@ -339,15 +392,31 @@ async fn task_alerts_soon() -> Result<(), Error> {
|
|||||||
(parts.get(0).map(|x| x.parse().unwrap()).unwrap_or(0), parts.get(1).map(|x| x.parse().unwrap()).unwrap_or(0), parts.get(2).map(|x| x.parse().unwrap()).unwrap_or(0))
|
(parts.get(0).map(|x| x.parse().unwrap()).unwrap_or(0), parts.get(1).map(|x| x.parse().unwrap()).unwrap_or(0), parts.get(2).map(|x| x.parse().unwrap()).unwrap_or(0))
|
||||||
} else { (0, 0, 0) };
|
} else { (0, 0, 0) };
|
||||||
let todo_time: DateTime<Local> = TimeZone::from_local_datetime(&Local, &NaiveDate::from_ymd(year, month, day).and_hms(hour, minute, second)).unwrap();
|
let todo_time: DateTime<Local> = TimeZone::from_local_datetime(&Local, &NaiveDate::from_ymd(year, month, day).and_hms(hour, minute, second)).unwrap();
|
||||||
if todo_time <= now {
|
Some(UsefulTask {
|
||||||
|
task,
|
||||||
|
todo_time,
|
||||||
|
is_reminder
|
||||||
|
})
|
||||||
|
|
||||||
|
}).collect());
|
||||||
|
Ok(tasks?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn task_alerts_soon() -> Result<(), Error> {
|
||||||
|
let now = Local::now();
|
||||||
|
|
||||||
|
let tasks = request_task_alerts().await?;
|
||||||
|
debug!("task_alerts: {} objects", tasks.len());
|
||||||
|
for task in tasks {
|
||||||
|
if task.todo_time <= now {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let diff = todo_time - now;
|
let diff = task.todo_time - now;
|
||||||
let minutes = diff.num_minutes();
|
let minutes = diff.num_minutes();
|
||||||
if !is_reminder && (minutes == 7 * 24 * 60 || minutes == 48 * 60 || minutes == 24 * 60 || minutes == 60 || minutes == 10) {
|
if !task.is_reminder && (minutes == 7 * 24 * 60 || minutes == 48 * 60 || minutes == 24 * 60 || minutes == 60 || minutes == 10) {
|
||||||
notify_owner(&format_time(diff), task).await?;
|
notify_owner(&format_time(diff), task.task).await?;
|
||||||
} else if is_reminder && minutes == 0 {
|
} else if task.is_reminder && minutes == 0 {
|
||||||
notify_owner("⏰", task).await?;
|
notify_owner("⏰", task.task).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -394,6 +463,12 @@ struct Task {
|
|||||||
utcDateModified: DateTime<Utc>,
|
utcDateModified: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UsefulTask {
|
||||||
|
task: Task,
|
||||||
|
todo_time: DateTime<Local>,
|
||||||
|
is_reminder: bool
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
struct Attribute {
|
struct Attribute {
|
||||||
|
Loading…
Reference in New Issue
Block a user