Split long list for person in chunks.
This commit is contained in:
parent
36653d760f
commit
63fac99f27
@ -1,7 +1,8 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod nickelext;
|
mod nickelext;
|
||||||
mod views_by_date;
|
|
||||||
mod admin;
|
mod admin;
|
||||||
|
mod splitlist;
|
||||||
|
mod views_by_date;
|
||||||
|
|
||||||
use adm::result::Error;
|
use adm::result::Error;
|
||||||
use chrono::Datelike;
|
use chrono::Datelike;
|
||||||
@ -27,7 +28,6 @@ use models::{Person, Photo, Place, Tag};
|
|||||||
use env::{dburl, env_or, jwt_key, photos_dir};
|
use env::{dburl, env_or, jwt_key, photos_dir};
|
||||||
|
|
||||||
use requestloggermiddleware::RequestLoggerMiddleware;
|
use requestloggermiddleware::RequestLoggerMiddleware;
|
||||||
|
|
||||||
use photosdirmiddleware::{PhotosDirMiddleware, PhotosDirRequestExtensions};
|
use photosdirmiddleware::{PhotosDirMiddleware, PhotosDirRequestExtensions};
|
||||||
|
|
||||||
use memcachemiddleware::*;
|
use memcachemiddleware::*;
|
||||||
@ -37,9 +37,56 @@ use rustc_serialize::json::ToJson;
|
|||||||
use templates;
|
use templates;
|
||||||
|
|
||||||
use self::nickelext::{FromSlug, MyResponse, far_expires};
|
use self::nickelext::{FromSlug, MyResponse, far_expires};
|
||||||
|
use self::splitlist::*;
|
||||||
use self::views_by_date::*;
|
use self::views_by_date::*;
|
||||||
|
|
||||||
|
pub struct PhotoLink {
|
||||||
|
pub href: String,
|
||||||
|
pub id: i32,
|
||||||
|
pub lable: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PhotoLink {
|
||||||
|
fn for_group(g: &[Photo], base_url: &str) -> PhotoLink {
|
||||||
|
PhotoLink {
|
||||||
|
href: format!(
|
||||||
|
"{}?from={}&to={}",
|
||||||
|
base_url,
|
||||||
|
g.last().map(|p| p.id).unwrap_or(0),
|
||||||
|
g.first().map(|p| p.id).unwrap_or(0),
|
||||||
|
),
|
||||||
|
id: g.iter()
|
||||||
|
.max_by_key(
|
||||||
|
|p| p.grade.unwrap_or(2) + if p.is_public { 3 } else { 0 },
|
||||||
|
)
|
||||||
|
.map(|p| p.id)
|
||||||
|
.unwrap_or(0),
|
||||||
|
lable: Some(format!(
|
||||||
|
"{} - {} ({})",
|
||||||
|
g.last()
|
||||||
|
.and_then(|p| p.date)
|
||||||
|
.map(|d| format!("{}", d.format("%F %T")))
|
||||||
|
.unwrap_or("-".into()),
|
||||||
|
g.first()
|
||||||
|
.and_then(|p| p.date)
|
||||||
|
.map(|d| format!("{}", d.format("%F %T")))
|
||||||
|
.unwrap_or("-".into()),
|
||||||
|
g.len(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a Photo> for PhotoLink {
|
||||||
|
fn from(p: &'a Photo) -> PhotoLink {
|
||||||
|
PhotoLink {
|
||||||
|
href: format!("/img/{}", p.id),
|
||||||
|
id: p.id,
|
||||||
|
lable: p.date.map(|d| format!("{}", d.format("%F %T"))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Group {
|
pub struct Group {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
@ -440,28 +487,54 @@ fn person_one<'mw>(
|
|||||||
use schema::people::dsl::{people, slug};
|
use schema::people::dsl::{people, slug};
|
||||||
let c: &PgConnection = &req.db_conn();
|
let c: &PgConnection = &req.db_conn();
|
||||||
if let Ok(person) = people.filter(slug.eq(tslug)).first::<Person>(c) {
|
if let Ok(person) = people.filter(slug.eq(tslug)).first::<Person>(c) {
|
||||||
|
let from_date = query_date(req, "from");
|
||||||
|
let to_date = query_date(req, "to");
|
||||||
use schema::photo_people::dsl::{person_id, photo_id, photo_people};
|
use schema::photo_people::dsl::{person_id, photo_id, photo_people};
|
||||||
use schema::photos::dsl::{date, grade, id};
|
use schema::photos::dsl::{date, id};
|
||||||
return res.ok(|o| {
|
let photos = Photo::query(req.authorized_user().is_some()).filter(
|
||||||
templates::person(
|
id.eq_any(
|
||||||
o,
|
photo_people
|
||||||
req,
|
.select(photo_id)
|
||||||
&Photo::query(req.authorized_user().is_some())
|
.filter(person_id.eq(person.id)),
|
||||||
.filter(
|
),
|
||||||
id.eq_any(
|
);
|
||||||
photo_people
|
let photos = if let Some(from_date) = from_date {
|
||||||
.select(photo_id)
|
photos.filter(date.ge(from_date))
|
||||||
.filter(person_id.eq(person.id)),
|
} else {
|
||||||
),
|
photos
|
||||||
)
|
};
|
||||||
.order(
|
let photos = if let Some(to_date) = to_date {
|
||||||
(grade.desc().nulls_last(), date.desc().nulls_last()),
|
photos.filter(date.le(to_date))
|
||||||
)
|
} else {
|
||||||
.load(c)
|
photos
|
||||||
.unwrap(),
|
};
|
||||||
&person,
|
let photos = photos
|
||||||
)
|
.order(date.desc().nulls_last())
|
||||||
});
|
.load::<Photo>(c)
|
||||||
|
.unwrap();
|
||||||
|
if photos.len() < 42 {
|
||||||
|
return res.ok(|o| {
|
||||||
|
templates::person(
|
||||||
|
o,
|
||||||
|
req,
|
||||||
|
&photos.iter().map(PhotoLink::from).collect::<Vec<_>>(),
|
||||||
|
&person,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return res.ok(|o| {
|
||||||
|
let path = req.path_without_query().unwrap_or("/");
|
||||||
|
templates::person(
|
||||||
|
o,
|
||||||
|
req,
|
||||||
|
&split_to_groups(&photos)
|
||||||
|
.iter()
|
||||||
|
.map(|g| PhotoLink::for_group(g, path))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
&person,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res.not_found("Not a person")
|
res.not_found("Not a person")
|
||||||
}
|
}
|
||||||
|
43
src/server/splitlist.rs
Normal file
43
src/server/splitlist.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use models::Photo;
|
||||||
|
|
||||||
|
pub fn split_to_groups(photos: &[Photo]) -> Vec<&[Photo]> {
|
||||||
|
let wanted_groups = (photos.len() as f64).sqrt() as usize;
|
||||||
|
let mut groups = vec![&photos[..]];
|
||||||
|
while groups.len() < wanted_groups {
|
||||||
|
let i = find_largest(&groups);
|
||||||
|
let (a, b) = split(groups[i]);
|
||||||
|
groups[i] = a;
|
||||||
|
groups.insert(i + 1, b);
|
||||||
|
}
|
||||||
|
groups
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_largest(groups: &[&[Photo]]) -> usize {
|
||||||
|
let mut found = 0;
|
||||||
|
let mut largest = 0;
|
||||||
|
for (i, g) in groups.iter().enumerate() {
|
||||||
|
if g.len() > largest {
|
||||||
|
largest = g.len();
|
||||||
|
found = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
found
|
||||||
|
}
|
||||||
|
|
||||||
|
fn split(group: &[Photo]) -> (&[Photo], &[Photo]) {
|
||||||
|
let l = group.len();
|
||||||
|
let mut pos = 0;
|
||||||
|
let mut dist = 0;
|
||||||
|
for i in l / 8..l - l / 8 - 1 {
|
||||||
|
let tttt = timestamp(&group[i]) - timestamp(&group[i + 1]);
|
||||||
|
if tttt > dist {
|
||||||
|
dist = tttt;
|
||||||
|
pos = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
group.split_at(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timestamp(p: &Photo) -> i64 {
|
||||||
|
p.date.map(|d| d.timestamp()).unwrap_or(0)
|
||||||
|
}
|
@ -433,8 +433,11 @@ pub fn prev_image<'mw>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn from_date(req: &mut Request) -> Option<NaiveDateTime> {
|
fn from_date(req: &mut Request) -> Option<NaiveDateTime> {
|
||||||
|
query_date(req, "from")
|
||||||
|
}
|
||||||
|
pub fn query_date(req: &mut Request, name: &str) -> Option<NaiveDateTime> {
|
||||||
req.query()
|
req.query()
|
||||||
.get("from")
|
.get(name)
|
||||||
.and_then(|s| s.parse().ok())
|
.and_then(|s| s.parse().ok())
|
||||||
.and_then(|i: i32| {
|
.and_then(|i: i32| {
|
||||||
use schema::photos::dsl::{date, photos};
|
use schema::photos::dsl::{date, photos};
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
@use nickel::Request;
|
@use nickel::Request;
|
||||||
@use models::{Photo, Person};
|
@use models::Person;
|
||||||
@use templates::{page_base, img_link};
|
@use server::PhotoLink;
|
||||||
|
@use templates::{page_base, photo_link};
|
||||||
|
|
||||||
@(req: &Request, photos: &[Photo], person: &Person)
|
@(req: &Request, photos: &[PhotoLink], person: &Person)
|
||||||
@:page_base(req, &format!("Photos with {}", person.person_name), &[], {
|
@:page_base(req, &format!("Photos with {}", person.person_name), &[], {
|
||||||
<div class="group">
|
<div class="group">
|
||||||
@for p in photos {@:img_link(p)}
|
@for p in photos {@:photo_link(p)}
|
||||||
</div>
|
</div>
|
||||||
})
|
})
|
||||||
|
7
templates/photo_link.rs.html
Normal file
7
templates/photo_link.rs.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@use server::PhotoLink;
|
||||||
|
|
||||||
|
@(photo: &PhotoLink)
|
||||||
|
<p class="item">
|
||||||
|
<a href="@photo.href"><img src="/img/@photo.id-s.jpg"></a>
|
||||||
|
@if let &Some(ref d) = &photo.lable {<br/>@d}
|
||||||
|
</p>
|
Loading…
Reference in New Issue
Block a user