store events in db
This commit is contained in:
parent
bb547dc222
commit
11dab8a049
13
schema.sql
13
schema.sql
|
@ -9,3 +9,16 @@ CREATE TABLE calendars (
|
||||||
etag TEXT,
|
etag TEXT,
|
||||||
last_modified 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
|
||||||
|
);
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use chrono::NaiveDateTime;
|
||||||
|
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
mod parser;
|
mod parser;
|
||||||
pub use parser::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)>;
|
pub type Props = Vec<(String, String)>;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
@ -12,9 +17,26 @@ pub struct Object {
|
||||||
pub content: HashMap<String, (Props, String)>,
|
pub content: HashMap<String, (Props, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Object {
|
impl<'a> GetValue<'a, &'a str> for Object {
|
||||||
pub fn get(&self, key: &'_ str) -> Option<&str> {
|
fn get(&'a self, key: &'_ str) -> Option<&'a str> {
|
||||||
self.content.get(key)
|
self.content.get(key)
|
||||||
.map(|(_props, value)| value.as_ref())
|
.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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
51
src/main.rs
51
src/main.rs
|
@ -12,11 +12,34 @@ use diesel::{Connection, pg::PgConnection, prelude::*};
|
||||||
mod config;
|
mod config;
|
||||||
use config::{Config, CalendarOptions};
|
use config::{Config, CalendarOptions};
|
||||||
mod schema;
|
mod schema;
|
||||||
use schema::{calendars::dsl::calendars, events};
|
use schema::{calendars::dsl::calendars};
|
||||||
mod model;
|
mod model;
|
||||||
use model::{Calendar, NewCalendar};
|
use model::{Calendar, NewCalendar, Event};
|
||||||
mod ics;
|
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 {
|
pub struct Resources {
|
||||||
db_url: String,
|
db_url: String,
|
||||||
|
@ -84,9 +107,9 @@ impl Resources {
|
||||||
}
|
}
|
||||||
let mut res = req.send()?;
|
let mut res = req.send()?;
|
||||||
|
|
||||||
println!("{} {}", res.status(), cal_opts.url);
|
|
||||||
if res.status() != 200 {
|
if res.status() != 200 {
|
||||||
let msg = format!("HTTP {}", res.status());
|
let msg = format!("HTTP {}", res.status());
|
||||||
|
println!("{} {}", res.status(), cal_opts.url);
|
||||||
diesel::update(calendars)
|
diesel::update(calendars)
|
||||||
.filter(schema::calendars::dsl::id.eq(id.clone()))
|
.filter(schema::calendars::dsl::id.eq(id.clone()))
|
||||||
.set((schema::calendars::dsl::last_success.eq(Utc::now().naive_utc()),
|
.set((schema::calendars::dsl::last_success.eq(Utc::now().naive_utc()),
|
||||||
|
@ -112,20 +135,32 @@ impl Resources {
|
||||||
|
|
||||||
let mut p = Parser::new();
|
let mut p = Parser::new();
|
||||||
let mut buf = [0; 1024];
|
let mut buf = [0; 1024];
|
||||||
|
let mut events = vec![];
|
||||||
loop {
|
loop {
|
||||||
match res.read(&mut buf)? {
|
match res.read(&mut buf)? {
|
||||||
len if len > 0 => {
|
len if len > 0 => {
|
||||||
let data = &buf[..len];
|
let data = &buf[..len];
|
||||||
p.feed(data, |obj| {
|
p.feed(data, |obj| {
|
||||||
println!("- [{}] {}", obj.get("DTSTART").unwrap_or("?"), obj.get("SUMMARY").unwrap_or("?"));
|
if let Some(event) = obj_to_event(cal_opts.url.clone(), obj) {
|
||||||
print!(" {}", obj.get("LOCATION").unwrap_or("?"));
|
events.push(event);
|
||||||
obj.get("URL").map(|url| print!(" <{}>", url));
|
}
|
||||||
println!("");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => 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(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
18
src/model.rs
18
src/model.rs
|
@ -1,7 +1,7 @@
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use super::schema::calendars;
|
use super::schema::{calendars, events};
|
||||||
|
|
||||||
#[derive(Queryable)]
|
#[derive(Debug, Queryable)]
|
||||||
pub struct Calendar {
|
pub struct Calendar {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub url: String,
|
pub url: String,
|
||||||
|
@ -14,7 +14,7 @@ pub struct Calendar {
|
||||||
pub last_modified: Option<String>,
|
pub last_modified: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable)]
|
#[derive(Debug, Insertable)]
|
||||||
#[table_name = "calendars"]
|
#[table_name = "calendars"]
|
||||||
pub struct NewCalendar {
|
pub struct NewCalendar {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
@ -22,3 +22,15 @@ pub struct NewCalendar {
|
||||||
|
|
||||||
pub last_fetch: Option<NaiveDateTime>,
|
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>,
|
||||||
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ table! {
|
||||||
calendar -> VarChar,
|
calendar -> VarChar,
|
||||||
id -> VarChar,
|
id -> VarChar,
|
||||||
|
|
||||||
start -> Timestamp,
|
dtstart -> Timestamp,
|
||||||
end -> Nullable<Timestamp>,
|
dtend -> Nullable<Timestamp>,
|
||||||
summary -> VarChar,
|
summary -> VarChar,
|
||||||
location -> Nullable<VarChar>,
|
location -> Nullable<VarChar>,
|
||||||
url -> Nullable<VarChar>,
|
url -> Nullable<VarChar>,
|
||||||
|
|
Loading…
Reference in New Issue