store events in db

This commit is contained in:
Astro 2019-10-10 17:39:34 +02:00
parent bb547dc222
commit 11dab8a049
5 changed files with 97 additions and 15 deletions

View File

@ -9,3 +9,16 @@ CREATE TABLE calendars (
etag TEXT,
last_modified TEXT
);
CREATE TABLE events (
calendar TEXT NOT NULL,
id TEXT NOT NULL,
PRIMARY KEY (calendar, id),
dtstart TIMESTAMP NOT NULL,
dtend TIMESTAMP,
summary TEXT NOT NULL,
location TEXT,
url TEXT
);

View File

@ -1,9 +1,14 @@
use std::collections::HashMap;
use chrono::NaiveDateTime;
mod tokenizer;
mod parser;
pub use parser::Parser;
pub trait GetValue<'a, R: 'a> {
fn get(&'a self, key: &'_ str) -> Option<R>;
}
pub type Props = Vec<(String, String)>;
#[derive(Debug, PartialEq)]
@ -12,9 +17,26 @@ pub struct Object {
pub content: HashMap<String, (Props, String)>,
}
impl Object {
pub fn get(&self, key: &'_ str) -> Option<&str> {
impl<'a> GetValue<'a, &'a str> for Object {
fn get(&'a self, key: &'_ str) -> Option<&'a str> {
self.content.get(key)
.map(|(_props, value)| value.as_ref())
}
}
impl<'a> GetValue<'a, String> for Object {
fn get(&self, key: &'_ str) -> Option<String> {
self.content.get(key)
.map(|(_props, value)| value.clone())
}
}
impl<'a> GetValue<'a, NaiveDateTime> for Object {
fn get(&self, key: &'_ str) -> Option<NaiveDateTime> {
let s = self.get(key)?;
NaiveDateTime::parse_from_str(s, "%Y%m%dT%H%M%SZ")
.or_else(|_| NaiveDateTime::parse_from_str(s, "%Y%m%dT%H%M%S"))
.or_else(|_| NaiveDateTime::parse_from_str(s, "%Y%m%d"))
.ok()
}
}

View File

@ -12,11 +12,34 @@ use diesel::{Connection, pg::PgConnection, prelude::*};
mod config;
use config::{Config, CalendarOptions};
mod schema;
use schema::{calendars::dsl::calendars, events};
use schema::{calendars::dsl::calendars};
mod model;
use model::{Calendar, NewCalendar};
use model::{Calendar, NewCalendar, Event};
mod ics;
use ics::Parser;
use ics::{Parser, Object, GetValue};
fn obj_to_event(calendar: String, obj: Object) -> Option<Event> {
if obj.name != "VEVENT" {
return None;
}
let dtstart = obj.get("DTSTART")?;
let summary = obj.get("SUMMARY")?;
let id = format!("{}{}{}{}",
obj.get("UID").unwrap_or(""),
dtstart,
obj.get("DTSTAMP").unwrap_or(""),
obj.get("RECURRENCE-ID").unwrap_or(""));
// TODO: DESCRIPTION
Some(Event {
calendar, id,
dtstart,
dtend: obj.get("DTEND"),
summary,
location: obj.get("LOCATION"),
url: obj.get("URL"),
})
}
pub struct Resources {
db_url: String,
@ -84,9 +107,9 @@ impl Resources {
}
let mut res = req.send()?;
println!("{} {}", res.status(), cal_opts.url);
if res.status() != 200 {
let msg = format!("HTTP {}", res.status());
println!("{} {}", res.status(), cal_opts.url);
diesel::update(calendars)
.filter(schema::calendars::dsl::id.eq(id.clone()))
.set((schema::calendars::dsl::last_success.eq(Utc::now().naive_utc()),
@ -112,20 +135,32 @@ impl Resources {
let mut p = Parser::new();
let mut buf = [0; 1024];
let mut events = vec![];
loop {
match res.read(&mut buf)? {
len if len > 0 => {
let data = &buf[..len];
p.feed(data, |obj| {
println!("- [{}] {}", obj.get("DTSTART").unwrap_or("?"), obj.get("SUMMARY").unwrap_or("?"));
print!(" {}", obj.get("LOCATION").unwrap_or("?"));
obj.get("URL").map(|url| print!(" <{}>", url));
println!("");
if let Some(event) = obj_to_event(cal_opts.url.clone(), obj) {
events.push(event);
}
});
}
_ => break,
}
}
drop(res);
println!("{} events {}", events.len(), cal_opts.url);
diesel::delete(schema::events::dsl::events)
.filter(schema::events::dsl::calendar.eq(cal_opts.url))
.execute(&db)?;
for event in events {
// println!("insert {:?}", event);
diesel::insert_into(schema::events::dsl::events)
.values(&event)
.execute(&db)?;
}
Ok(())
})?;

View File

@ -1,7 +1,7 @@
use chrono::NaiveDateTime;
use super::schema::calendars;
use super::schema::{calendars, events};
#[derive(Queryable)]
#[derive(Debug, Queryable)]
pub struct Calendar {
pub id: String,
pub url: String,
@ -14,7 +14,7 @@ pub struct Calendar {
pub last_modified: Option<String>,
}
#[derive(Insertable)]
#[derive(Debug, Insertable)]
#[table_name = "calendars"]
pub struct NewCalendar {
pub id: String,
@ -22,3 +22,15 @@ pub struct NewCalendar {
pub last_fetch: Option<NaiveDateTime>,
}
#[derive(Debug, Queryable, Insertable)]
pub struct Event {
pub calendar: String,
pub id: String,
pub dtstart: NaiveDateTime,
pub dtend: Option<NaiveDateTime>,
pub summary: String,
pub location: Option<String>,
pub url: Option<String>,
}

View File

@ -17,8 +17,8 @@ table! {
calendar -> VarChar,
id -> VarChar,
start -> Timestamp,
end -> Nullable<Timestamp>,
dtstart -> Timestamp,
dtend -> Nullable<Timestamp>,
summary -> VarChar,
location -> Nullable<VarChar>,
url -> Nullable<VarChar>,