serve: split main into index

This commit is contained in:
Astro 2020-10-26 16:51:25 +01:00
förälder d1566f6c31
incheckning 9a1a106e0e
2 ändrade filer med 119 tillägg och 115 borttagningar

113
ticker-serve/src/index.rs Normal file
Visa fil

@ -0,0 +1,113 @@
use gotham::{
helpers::http::response::create_response,
hyper::{Body, Response},
state::{FromState, State},
};
use http::status::StatusCode;
use mime::TEXT_HTML;
use typed_html::{html, text, dom::DOMTree};
use diesel::prelude::*;
use chrono::{offset::Local, NaiveDate};
use libticker::{
schema::{self, events::dsl::events},
model::Event,
};
use crate::AppState;
fn fix_url(s: &str) -> std::borrow::Cow<str> {
if s.starts_with("http:") || s.starts_with("https:") {
s.into()
} else {
format!("http://{}", s).into()
}
}
struct DayEvents<'e> {
date: NaiveDate,
events: &'e [Event],
}
/// assumes pre-sorted input
fn group_by_day(es: &[Event]) -> Vec<DayEvents> {
let mut results = vec![];
let mut prev_date = None;
let mut date_start = 0;
for (i, event) in es.iter().enumerate() {
if prev_date.is_some() && prev_date != Some(event.dtstart.date()) {
if i > date_start {
results.push(DayEvents {
date: prev_date.unwrap().clone(),
events: &es[date_start..i],
});
date_start = i;
}
}
prev_date = Some(event.dtstart.date());
}
results
}
fn render_index(app_state: &AppState) -> String {
let db = app_state.db.lock().unwrap();
let today = Local::today().naive_local().and_hms(0, 0, 0);
let es = events
.filter(schema::events::dtstart.ge(&today))
.order_by(schema::events::dtstart.asc())
.then_order_by(schema::events::dtend.desc())
.load::<Event>(&*db)
.unwrap();
let days = group_by_day(&es);
let doc: DOMTree<String> = html!(
<html>
<head>
<title>"Ticker"</title>
<meta charset="utf-8" />
</head>
<body>
{ days.iter().map(|day| html!(<div>
<nav><h2>{ text!("{}", &day.date) }</h2></nav>
{ day.events.iter().map(|e| html!(
<article class="event">
{ match &e.url {
None => html!(
<h3>{ text!("{}", &e.summary) }</h3>
),
Some(url) => html!(
<h3>
<a href={ fix_url(url) }>
{ text!("{}", &e.summary) }
</a>
</h3>
),
} }
<p class="dtstart">{ text!("{}", &e.dtstart) }</p>
{ e.location.as_ref().map(|location| html!(
<p>
{ text!("{}", location) }
</p>
)) }
</article>
)) }
</div>)) }
</body>
</html>
);
format!("<DOCTYPE html>\n{}", doc.to_string())
}
pub fn index(state: State) -> (State, Response<Body>) {
let message = {
let app_state = AppState::borrow_from(&state);
render_index(app_state)
};
let res = create_response(&state, StatusCode::OK, TEXT_HTML, message);
(state, res)
}

Visa fil

@ -6,129 +6,20 @@ extern crate gotham_derive;
use std::sync::{Arc, Mutex};
use gotham::{
handler::assets::FileOptions,
helpers::http::response::create_response,
hyper::{Body, Response},
router::builder::{DefineSingleRoute, DrawRoutes},
middleware::state::StateMiddleware,
pipeline::single::single_pipeline,
pipeline::single_middleware,
router::builder::*,
state::{FromState, State},
};
use http::status::StatusCode;
use mime::TEXT_HTML;
use diesel::{Connection, pg::PgConnection};
use typed_html::{html, text, dom::DOMTree};
use diesel::{Connection, pg::PgConnection, prelude::*};
use chrono::{offset::Local, NaiveDate};
use libticker::{
config::{Config, CalendarOptions},
schema::{self, events::dsl::events},
model::{Calendar, Event},
ics::{Object, Timestamp, GetValue},
};
fn fix_url(s: &str) -> std::borrow::Cow<str> {
if s.starts_with("http:") || s.starts_with("https:") {
s.into()
} else {
format!("http://{}", s).into()
}
}
struct DayEvents<'e> {
date: NaiveDate,
events: &'e [Event],
}
/// assumes pre-sorted input
fn group_by_day(es: &[Event]) -> Vec<DayEvents> {
let mut results = vec![];
let mut prev_date = None;
let mut date_start = 0;
for (i, event) in es.iter().enumerate() {
if prev_date.is_some() && prev_date != Some(event.dtstart.date()) {
if i > date_start {
results.push(DayEvents {
date: prev_date.unwrap().clone(),
events: &es[date_start..i],
});
date_start = i;
}
}
prev_date = Some(event.dtstart.date());
}
results
}
use libticker::config::Config;
mod index;
#[derive(Clone, StateData)]
struct AppState {
db: Arc<Mutex<PgConnection>>,
}
fn render_index(app_state: &AppState) -> String {
let db = app_state.db.lock().unwrap();
let today = Local::today().naive_local().and_hms(0, 0, 0);
let es = events
.filter(schema::events::dtstart.ge(&today))
.order_by(schema::events::dtstart.asc())
.then_order_by(schema::events::dtend.desc())
.load::<Event>(&*db)
.unwrap();
let days = group_by_day(&es);
let doc: DOMTree<String> = html!(
<html>
<head>
<title>"Ticker"</title>
<meta charset="utf-8" />
</head>
<body>
<h1>"Ticker"</h1>
{ days.iter().map(|day| html!(<div>
<nav><h2>{ text!("{}", &day.date) }</h2></nav>
{ day.events.iter().map(|e| html!(
<article class="event">
{ match &e.url {
None => html!(
<h3>{ text!("{}", &e.summary) }</h3>
),
Some(url) => html!(
<h3>
<a href={ fix_url(url) }>
{ text!("{}", &e.summary) }
</a>
</h3>
),
} }
<p class="dtstart">{ text!("{}", &e.dtstart) }</p>
{ e.location.as_ref().map(|location| html!(
<p>
{ text!("{}", location) }
</p>
)) }
</article>
)) }
</div>)) }
</body>
</html>
);
format!("<DOCTYPE html>\n{}", doc.to_string())
}
fn index(state: State) -> (State, Response<Body>) {
let message = {
let app_state = AppState::borrow_from(&state);
render_index(app_state)
};
let res = create_response(&state, StatusCode::OK, TEXT_HTML, message);
(state, res)
pub struct AppState {
pub db: Arc<Mutex<PgConnection>>,
}
fn main() {
@ -145,7 +36,7 @@ fn main() {
)
);
let router = build_router(chain, pipelines, |route| {
route.get("/").to(index);
route.get("/").to(index::index);
route.get("static/*").to_dir(
FileOptions::new(&"static")
// TODO: