feat: timezone implementation

This commit is contained in:
Patrick 2024-09-12 19:35:51 +02:00
parent 41f9b6f3f5
commit b2c44e9003
Signed by: patrick
GPG key ID: 451F95EFB8BECD0F

View file

@ -1,13 +1,14 @@
use copy_dir::copy_dir; use copy_dir::copy_dir;
use std::fs::{create_dir_all, remove_file, write, File, OpenOptions}; use std::fs::{create_dir_all, read_to_string, remove_file, write, File, OpenOptions};
use std::io::{BufRead, BufReader, Write}; use std::io::{BufRead, BufReader, Read, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Stdio; use std::process::Stdio;
use askama::Template; use askama::Template;
use base64::prelude::BASE64_STANDARD; use base64::prelude::BASE64_STANDARD;
use base64::Engine; use base64::Engine;
use chrono::{DateTime, Days, Local}; use chrono::offset::FixedOffset;
use chrono::{DateTime, Days, Local, Utc};
use clap::{command, Parser}; use clap::{command, Parser};
use color_eyre::eyre::{eyre, OptionExt, Result}; use color_eyre::eyre::{eyre, OptionExt, Result};
use futures::future::join_all; use futures::future::join_all;
@ -42,6 +43,10 @@ struct Config {
///The used as the journal ///The used as the journal
#[arg(short, long)] #[arg(short, long)]
url: String, url: String,
///The timezone used if none is given in the data folder
#[arg(short, long)]
timezone: String,
} }
#[derive(Debug, Default, Template)] #[derive(Debug, Default, Template)]
@ -89,11 +94,18 @@ async fn generate_post(config: &Config, client: &mut Client) -> Result<String> {
attachments.push(id.to_string()); attachments.push(id.to_string());
} }
} }
let time = get_msg_time(&v).ok_or_eyre("Message without time???")?;
let secs = config.timezone.parse::<i32>()?;
println!("{:?}", secs);
let tz = FixedOffset::east_opt(config.timezone.parse::<i32>()? * 3600)
.ok_or_eyre("timezone von nem anderen planete?")?;
let time = time.with_timezone(&tz);
println!("{:?}", time);
msgs.push(Message { msgs.push(Message {
content: get_msg_text(&v).unwrap_or("").to_string(), content: get_msg_text(&v).unwrap_or("").to_string(),
attachments, attachments,
time: get_msg_time(&v).ok_or_eyre("Message without time???")?, time: time.format("%H:%M").to_string(),
}); });
} }
if msgs.is_empty() { if msgs.is_empty() {
@ -117,10 +129,15 @@ async fn generate_post(config: &Config, client: &mut Client) -> Result<String> {
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let config = Config::parse(); let mut config = Config::parse();
if !Path::new(&config.data_folder).exists() { if !Path::new(&config.data_folder).exists() {
create_dir_all(&config.data_folder)? create_dir_all(&config.data_folder)?
} }
let tz_data_path = format!("{}/tz.data", config.data_folder);
if Path::new(&tz_data_path).exists() {
config.timezone = read_to_string(&tz_data_path)?;
}
println!("{:?}", config.timezone);
let mut cmd = Command::new(COMMAND_PATH) let mut cmd = Command::new(COMMAND_PATH)
.arg("jsonRpc") .arg("jsonRpc")
@ -146,131 +163,69 @@ async fn main() -> Result<()> {
continue; continue;
} else if sender != &config.allowed_sender { } else if sender != &config.allowed_sender {
println!("{:?}", sender); println!("{:?}", sender);
client send(
.send( &client,
None, sender,
vec![sender.to_string()], "This is the signal-to-blog bot, you are not in the list of allowed writers."
Vec::new(), .to_string(),
false, )
false, .await?;
"This is the signal-to-blog bot, you are not in the list of allowed writers."
.to_string(),
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
None,
None,
None,
None,
None,
)
.await?;
continue; continue;
}; };
println!("{v}"); println!("{v}");
println!("{:?}", text); println!("{:?}", text);
if let Some(text) = text { if let Some(text) = text {
// ©ontrol character // ©ontrol character
if let Some(text) = text.strip_prefix("©").and_then(|x| Some(x.trim())) { let cmds: Vec<&str> = text.split_whitespace().collect();
match text { if cmds.len() >= 2 && cmds[0] == "©" {
match cmds[1] {
"help" => {
let text = "
Available commands:
- post: Generate post for yesterday
- tz: change timezone
"
.to_string();
send(&client, sender, text).await?;
}
"post" => { "post" => {
let res = generate_post(&config, &mut client).await; let res = generate_post(&config, &mut client).await;
if let Ok(res) = res { if let Ok(res) = res {
client send(
.send( &client,
None, sender,
vec![sender.to_string()], format!("Generated blog post at: {}/{}", config.url, res),
Vec::new(), )
false, .await?;
false,
format!("Generated blog post at: {}/{}", config.url, res)
.to_string(),
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
None,
None,
None,
None,
None,
)
.await?;
} else { } else {
client send(
.send( &client,
None, sender,
vec![sender.to_string()], format!("Error generating blog post:\n{:?}", res),
Vec::new(), )
false, .await?;
false, }
format!("Error generating blog post:\n{:?}", res).to_string(), }
Vec::new(), "tz" => {
Vec::new(), if cmds.get(2).is_some_and(|x| {
Vec::new(), x.parse::<i32>()
None, .is_ok_and(|x| FixedOffset::east_opt(x * 3600).is_some())
None, }) {
None, println!("{}", tz_data_path);
Vec::new(), let mut file = OpenOptions::new()
Vec::new(), .create(true)
Vec::new(), .write(true)
None, .open(&tz_data_path)?;
None, file.write_all(cmds[2].as_bytes())?;
None, config.timezone = cmds[2].to_string();
None,
None, send(&client, sender, format!("Updated tz data")).await?;
None, } else {
None, send(&client, sender, format!("Error parsing")).await?;
None,
)
.await?;
} }
} }
_ => { _ => {
client send(&client, sender, format!("Unknown command: {}", text)).await?;
.send(
None,
vec![sender.to_string()],
Vec::new(),
false,
false,
format!("Unknown command: {}", text).to_string(),
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
None,
None,
None,
None,
None,
)
.await?;
} }
} }
continue; continue;
@ -283,6 +238,36 @@ async fn main() -> Result<()> {
writeln!(file, "{}", v.to_string())?; writeln!(file, "{}", v.to_string())?;
} }
} }
async fn send(client: &Client, sender: &str, msg: String) -> Result<()> {
client
.send(
None,
vec![sender.to_string()],
Vec::new(),
false,
false,
msg,
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
Vec::new(),
Vec::new(),
Vec::new(),
None,
None,
None,
None,
None,
None,
None,
None,
)
.await?;
Ok(())
}
/// make sure the directory exists before trying to save into it /// make sure the directory exists before trying to save into it
fn save_picture(file: &PathBuf, content: &str) -> Result<()> { fn save_picture(file: &PathBuf, content: &str) -> Result<()> {
@ -325,12 +310,11 @@ fn get_msg_sender(val: &Value) -> Option<&str> {
val.pointer("/envelope/source").and_then(|x| x.as_str()) val.pointer("/envelope/source").and_then(|x| x.as_str())
} }
fn get_msg_time(val: &Value) -> Option<String> { fn get_msg_time(val: &Value) -> Option<DateTime<Utc>> {
let time = val let time = val
.pointer("/envelope/timestamp") .pointer("/envelope/timestamp")
.and_then(|x| x.as_i64())?; .and_then(|x| x.as_i64())?;
let time = DateTime::from_timestamp(time, 0)?; DateTime::from_timestamp_millis(time)
Some(time.format("%H:%M").to_string())
} }
fn get_msg_text(val: &Value) -> Option<&str> { fn get_msg_text(val: &Value) -> Option<&str> {