From 6ed42c0be783f454e0631164aa8f0514759b7b7b Mon Sep 17 00:00:00 2001 From: Rasmus Kaj Date: Tue, 9 Aug 2016 01:41:42 +0200 Subject: [PATCH] Add camera support. Store and show which camera each picture was taken with (if present in exif data). --- .../down.sql | 2 + .../up.sql | 9 ++++ src/findphotos.rs | 20 +++++-- src/main.rs | 8 ++- src/models.rs | 54 ++++++++++++++++++- src/readkpa.rs | 2 +- templates/details.tpl | 1 + 7 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 migrations/20160808022325_create_cameras_table/down.sql create mode 100644 migrations/20160808022325_create_cameras_table/up.sql diff --git a/migrations/20160808022325_create_cameras_table/down.sql b/migrations/20160808022325_create_cameras_table/down.sql new file mode 100644 index 0000000..d6f8b43 --- /dev/null +++ b/migrations/20160808022325_create_cameras_table/down.sql @@ -0,0 +1,2 @@ +ALTER TABLE photos DROP COLUMN camera_id; +DROP TABLE cameras; diff --git a/migrations/20160808022325_create_cameras_table/up.sql b/migrations/20160808022325_create_cameras_table/up.sql new file mode 100644 index 0000000..70542f1 --- /dev/null +++ b/migrations/20160808022325_create_cameras_table/up.sql @@ -0,0 +1,9 @@ +CREATE TABLE cameras ( + id SERIAL PRIMARY KEY, + manufacturer VARCHAR NOT NULL, + model VARCHAR NOT NULL +); + +CREATE UNIQUE INDEX cameras_idx ON cameras (manufacturer, model); + +ALTER TABLE photos ADD COLUMN camera_id INTEGER REFERENCES cameras (id); diff --git a/src/findphotos.rs b/src/findphotos.rs index 90acdea..c9ddb43 100644 --- a/src/findphotos.rs +++ b/src/findphotos.rs @@ -16,7 +16,7 @@ use std::path::Path; use dotenv::dotenv; use diesel::pg::PgConnection; use self::diesel::prelude::*; -use rphotos::models::{Modification, Photo}; +use rphotos::models::{Modification, Photo, Camera}; mod env; use env::{dburl, photos_dir}; @@ -61,8 +61,9 @@ fn save_photo(db: &PgConnection, exif: &ExifData) -> FindPhotoResult<()> { let photo = match try!(Photo::create_or_set_basics(db, file_path, - Some(try!(find_date(&exif))), - try!(find_rotation(&exif)))) { + Some(try!(find_date(&exif))), + try!(find_rotation(&exif)), + try!(find_camera(db, exif)))) { Modification::Created(photo) => { info!("Created {:?}", photo); photo @@ -103,6 +104,19 @@ fn save_photo(db: &PgConnection, Ok(()) } +fn find_camera(db: &PgConnection, exif: &ExifData) -> FindPhotoResult> { + if let (Some(maketag), Some(modeltag)) = (find_entry(exif, &ExifTag::Make), + find_entry(exif, &ExifTag::Model)) { + if let (TagValue::Ascii(make), TagValue::Ascii(model)) = + (maketag.clone().value, modeltag.clone().value) { + let cam = try!(Camera::get_or_create(db, &make, &model)); + return Ok(Some(cam)); + } + // TODO else Err(...?) + } + Ok(None) +} + type FindPhotoResult = Result; #[derive(Debug)] diff --git a/src/main.rs b/src/main.rs index c0e8d96..4911fd8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,7 +39,7 @@ use diesel::prelude::*; use diesel::pg::PgConnection; use chrono::naive::date::NaiveDate; -use rphotos::models::{Person, Photo, Place, Tag}; +use rphotos::models::{Camera, Person, Photo, Place, Tag}; mod env; use env::{dburl, env_or, jwt_key, photos_dir}; @@ -444,6 +444,12 @@ fn photo_details<'mw>(req: &mut Request, } } }, + camera: Option = { + use rphotos::schema::cameras::dsl::*; + tphoto.camera_id.map(|i| { + cameras.find(i).first(c).unwrap() + }) + }, time: String = match tphoto.date { Some(d) => d.format("%T").to_string(), None => "".to_string() diff --git a/src/models.rs b/src/models.rs index 34491b6..cf01176 100644 --- a/src/models.rs +++ b/src/models.rs @@ -4,6 +4,7 @@ use diesel::pg::PgConnection; use diesel::result::Error as DieselError; #[derive(Debug, Clone, Queryable)] +#[belongs_to(Camera)] pub struct Photo { pub id: i32, pub path: String, @@ -11,6 +12,7 @@ pub struct Photo { pub grade: Option, pub rotation: i16, pub is_public: bool, + pub camera_id: Option, } // NaiveDateTime isn't Encodable, so we have to implement this by hand. @@ -40,6 +42,7 @@ pub struct NewPhoto<'a> { pub path: &'a str, pub date: Option, pub rotation: i16, + pub camera_id: Option, } #[derive(Debug)] @@ -73,16 +76,19 @@ impl Photo { pub fn create_or_set_basics(db: &PgConnection, file_path: &str, exifdate: Option, - exifrotation: i16) + exifrotation: i16, + camera: Option) -> Result, DieselError> { use diesel; use diesel::prelude::*; use schema::photos::dsl::*; + let cameraid = camera.map(|c| c.id); if let Some(mut pic) = try!(photos.filter(path.eq(&file_path.to_string())) .first::(db) .optional()) { let mut change = false; + // TODO Merge updates to one update statement! if exifdate.is_some() && exifdate != pic.date { change = true; pic = try!(diesel::update(photos.find(pic.id)) @@ -95,6 +101,12 @@ impl Photo { .set(rotation.eq(exifrotation)) .get_result::(db)); } + if cameraid != pic.camera_id { + change = true; + pic = try!(diesel::update(photos.find(pic.id)) + .set(camera_id.eq(cameraid)) + .get_result::(db)); + } Ok(if change { Modification::Updated(pic) } else { @@ -105,6 +117,7 @@ impl Photo { path: &file_path, date: exifdate, rotation: exifrotation, + camera_id: cameraid, }; let pic = try!(diesel::insert(&pic) .into(photos) @@ -221,3 +234,42 @@ pub struct NewUser<'a> { pub username: &'a str, pub password: &'a str, } + +#[derive(Debug, Clone, Identifiable, RustcEncodable, Queryable)] +#[has_many(photos)] +pub struct Camera { + pub id: i32, + pub manufacturer: String, + pub model: String, +} +use super::schema::cameras; +#[insertable_into(cameras)] +pub struct NewCamera { + pub manufacturer: String, + pub model: String, +} + +impl Camera { + pub fn get_or_create(db: &PgConnection, + make: &str, + modl: &str) + -> Result { + use diesel; + use diesel::prelude::*; + use schema::cameras::dsl::*; + if let Some(camera) = try!(cameras.filter(manufacturer.eq(make)) + .filter(model.eq(modl)) + .first::(db) + .optional()) { + Ok(camera) + } else { + let camera = NewCamera { + manufacturer: make.to_string(), + model: modl.to_string(), + }; + diesel::insert(&camera) + .into(cameras) + .get_result(db) + } + } +} diff --git a/src/readkpa.rs b/src/readkpa.rs index 9ddcc0a..e799a8c 100644 --- a/src/readkpa.rs +++ b/src/readkpa.rs @@ -194,7 +194,7 @@ fn main() { .unwrap(); let date = find_image_date(attributes); photo = Some(match Photo::create_or_set_basics - (&db, &file, date, angle) + (&db, &file, date, angle, None) .expect("Create or update photo") { Modification::Created(photo) => { info!("Created {:?}", photo); diff --git a/templates/details.tpl b/templates/details.tpl index 3030b80..b8e41a6 100644 --- a/templates/details.tpl +++ b/templates/details.tpl @@ -35,5 +35,6 @@

Places: {{#places}}{{place_name}}, {{/places}}

Tags: {{#tags}}{{tag_name}}, {{/tags}}

{{#position}}

Position: {{x}} {{y}}

{{/position}} + {{#camera}}

Camera: {{model}} ({{manufacturer}})

{{/camera}}