Database based caching via diesel & SQLite added.
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -169,3 +169,6 @@ dist
 | 
			
		||||
# Stores VSCode versions used for testing VSCode extensions
 | 
			
		||||
.vscode-test
 | 
			
		||||
 | 
			
		||||
# SQLite
 | 
			
		||||
*.sqlite3
 | 
			
		||||
*.db
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								Cargo.toml
									
									
									
									
									
								
							@@ -1,15 +1,25 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "curators"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
authors = ["Micha Glave <mig@xilab.net>"]
 | 
			
		||||
authors = ["Micha Glave <coding@migmedia.de>"]
 | 
			
		||||
description = "An image gallery, defined by plain files."
 | 
			
		||||
edition = "2018"
 | 
			
		||||
exclude = [".travis.yml", ".gitignore", "test-data/**"]
 | 
			
		||||
description = "Image Gallery. Defined by plain files."
 | 
			
		||||
name = "curators"
 | 
			
		||||
readme = "README.md"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
toml = "0.5"
 | 
			
		||||
actix-rt = "1.0"
 | 
			
		||||
actix-web = "2.0"
 | 
			
		||||
diesel = { version ="1.4", features = ["sqlite", "r2d2", "uuid", "chrono"]  }
 | 
			
		||||
uuid = { version="0.7",  features = ["v5"] }
 | 
			
		||||
dotenv = "0.15"
 | 
			
		||||
env_logger = "0.7"
 | 
			
		||||
futures = "0.3"
 | 
			
		||||
kamadak-exif = "0.5"
 | 
			
		||||
listenfd = "0.3"
 | 
			
		||||
structopt = "0.3"
 | 
			
		||||
#exempi = "2.5.0"
 | 
			
		||||
strum = "0.18.0"
 | 
			
		||||
strum_macros = "0.18.0"
 | 
			
		||||
kamadak-exif = "0.5"
 | 
			
		||||
toml = "0.5"
 | 
			
		||||
chrono = "0.4"
 | 
			
		||||
anyhow = "1"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								README.md
									
									
									
									
									
								
							@@ -1,10 +1,27 @@
 | 
			
		||||
# curators
 | 
			
		||||
# curators - Picture data long-term archive
 | 
			
		||||
 | 
			
		||||
Image Gallery. Defined by plain files.
 | 
			
		||||
 | 
			
		||||
## Problem definition:
 | 
			
		||||
 | 
			
		||||
Managing many images from different sources is a challenge. Either there is a quantity limit
 | 
			
		||||
by storage space or program (iPhoto), vendor lock or security issues throughout the environment.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Goal:
 | 
			
		||||
Image management for multiple (competing) users. Purely file-based, non-destructive, based on standards (as much as possible). Using
 | 
			
		||||
Image management for multiple (competing) users. Purely file-based, non-destructive, based on standards (as much as
 | 
			
		||||
possible). Using
 | 
			
		||||
 | 
			
		||||
* [Exif](https://de.wikipedia.org/wiki/Exchangeable_Image_File_Format)
 | 
			
		||||
* [IPTC](https://de.wikipedia.org/wiki/IPTC-IIM-Standard)
 | 
			
		||||
* [XMP](https://de.wikipedia.org/wiki/Extensible_Metadata_Platform) 
 | 
			
		||||
* [XMP](https://de.wikipedia.org/wiki/Extensible_Metadata_Platform)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
##  Principles:
 | 
			
		||||
 | 
			
		||||
* Original file is not changed.
 | 
			
		||||
* Meta-data are next to the image file
 | 
			
		||||
	* description of contents: people / faces, place, tags
 | 
			
		||||
	* Authorization
 | 
			
		||||
	* Reshaping (crop, color correction)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								diesel.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								diesel.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
# For documentation on how to configure this file,
 | 
			
		||||
# see diesel.rs/guides/configuring-diesel-cli
 | 
			
		||||
 | 
			
		||||
[print_schema]
 | 
			
		||||
file = "src/schema.rs"
 | 
			
		||||
							
								
								
									
										0
									
								
								migrations/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								migrations/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								migrations/2020-06-15-200823_images/down.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								migrations/2020-06-15-200823_images/down.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
DROP TABLE IF EXISTS images;
 | 
			
		||||
							
								
								
									
										12
									
								
								migrations/2020-06-15-200823_images/up.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								migrations/2020-06-15-200823_images/up.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
CREATE TABLE images (
 | 
			
		||||
  id VARCHAR(40) PRIMARY KEY NOT NULL,
 | 
			
		||||
  path VARCHAR(500) NOT NULL,
 | 
			
		||||
  title VARCHAR(200),
 | 
			
		||||
  last_changed TIMESTAMP NOT NULL,
 | 
			
		||||
  published BOOLEAN NOT NULL DEFAULT 'f'
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
INSERT INTO images (id, path, title, last_changed, published) VALUES
 | 
			
		||||
('8e153cab-7dc9-46c7-9a72-91e56ac174ca', './BlueSquare.jpg', 'Blaues Quadrat', '2020-05-27 13:33:56.747473', false );
 | 
			
		||||
INSERT INTO images (id, path, title, last_changed, published) VALUES
 | 
			
		||||
('ea01f5cd-a532-4232-810c-bae977cc4336', './Canon_40D.jpg', 'Canon 40d', '2020-05-27 13:33:56.747473', false );
 | 
			
		||||
							
								
								
									
										18
									
								
								src/bin/listdb.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/bin/listdb.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
extern crate curators;
 | 
			
		||||
 | 
			
		||||
use anyhow::{Context, Result};
 | 
			
		||||
use curators::database::*;
 | 
			
		||||
use curators::models::Image;
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let results = load_images();
 | 
			
		||||
    println!("Displaying {} images", results.len());
 | 
			
		||||
    for img in results {
 | 
			
		||||
        println!("{:?} ", img);
 | 
			
		||||
    }
 | 
			
		||||
    let p = Path::new(r"./BlueSquare.jpg").canonicalize().unwrap();
 | 
			
		||||
    println!("{:?}", Image::try_from(&p));
 | 
			
		||||
    let p = Path::new(r"./Canon_40D.jpg").canonicalize().unwrap();
 | 
			
		||||
    println!("{:?}", Image::try_from(&p));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								src/database.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/database.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
use diesel;
 | 
			
		||||
use diesel::prelude::*;
 | 
			
		||||
use diesel::sqlite::SqliteConnection;
 | 
			
		||||
 | 
			
		||||
use crate::models::Image;
 | 
			
		||||
use dotenv::dotenv;
 | 
			
		||||
use std::env;
 | 
			
		||||
 | 
			
		||||
pub fn establish_connection() -> SqliteConnection {
 | 
			
		||||
    dotenv().ok();
 | 
			
		||||
 | 
			
		||||
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
 | 
			
		||||
    SqliteConnection::establish(&database_url)
 | 
			
		||||
        .expect(&format!("Error connecting to {}", database_url))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn load_images() -> Vec<Image> {
 | 
			
		||||
    use crate::schema::images::dsl::*;
 | 
			
		||||
 | 
			
		||||
    let connection = establish_connection();
 | 
			
		||||
    images
 | 
			
		||||
        .filter(published.eq(false))
 | 
			
		||||
        .limit(50)
 | 
			
		||||
        .load::<Image>(&connection)
 | 
			
		||||
        .expect("Error loading images")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/handling.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/handling.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
use snafu::{ensure, Backtrace, ErrorCompat, ResultExt, Snafu};
 | 
			
		||||
use std::{
 | 
			
		||||
    fs,
 | 
			
		||||
    path::{Path, PathBuf},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Snafu)]
 | 
			
		||||
pub enum Error {
 | 
			
		||||
    #[snafu(display("Could not open config from {}: {}", filename.display(), source))]
 | 
			
		||||
    OpenConfig {
 | 
			
		||||
        filename: PathBuf,
 | 
			
		||||
        source: std::io::Error,
 | 
			
		||||
    },
 | 
			
		||||
    #[snafu(display("Could not save config to {}: {}", filename.display(), source))]
 | 
			
		||||
    SaveConfig {
 | 
			
		||||
        filename: PathBuf,
 | 
			
		||||
        source: std::io::Error,
 | 
			
		||||
    },
 | 
			
		||||
    #[snafu(display("Could not read file {}: {}", filename.display(), source))]
 | 
			
		||||
    OpenFile {
 | 
			
		||||
        filename: PathBuf,
 | 
			
		||||
        source: std::io::Error,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate diesel;
 | 
			
		||||
extern crate anyhow;
 | 
			
		||||
extern crate dotenv;
 | 
			
		||||
 | 
			
		||||
pub mod database;
 | 
			
		||||
pub mod models;
 | 
			
		||||
pub mod schema;
 | 
			
		||||
							
								
								
									
										53
									
								
								src/models.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/models.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
use crate::schema::images;
 | 
			
		||||
 | 
			
		||||
use anyhow::{Context, Result};
 | 
			
		||||
use chrono::NaiveDateTime;
 | 
			
		||||
use std::ffi::OsString;
 | 
			
		||||
use std::{
 | 
			
		||||
    fs,
 | 
			
		||||
    path::{Path, PathBuf},
 | 
			
		||||
    time::{SystemTime, UNIX_EPOCH},
 | 
			
		||||
};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Queryable, Insertable, Identifiable)]
 | 
			
		||||
pub struct Image {
 | 
			
		||||
    pub id: String,
 | 
			
		||||
    pub path: String,
 | 
			
		||||
    pub title: Option<String>,
 | 
			
		||||
    pub last_changed: NaiveDateTime,
 | 
			
		||||
    pub published: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Image {
 | 
			
		||||
    pub fn try_from(path: &Path) -> anyhow::Result<Self> {
 | 
			
		||||
        let abs_path = path.canonicalize().context("Path not valid!")?;
 | 
			
		||||
        let os_path = abs_path.clone().into_os_string();
 | 
			
		||||
        let path_str = os_path.into_string().expect(&format!(
 | 
			
		||||
            "Converting path-name problem! {:?}",
 | 
			
		||||
            path.display()
 | 
			
		||||
        ));
 | 
			
		||||
        let uuid = Uuid::new_v5(&Uuid::NAMESPACE_URL, &path_str.as_bytes());
 | 
			
		||||
        let metadata = abs_path
 | 
			
		||||
            .metadata()
 | 
			
		||||
            .context(format!("Unable to load Metadata for: {}", path.display()))?;
 | 
			
		||||
        let time = match metadata.modified() {
 | 
			
		||||
            Ok(t) => t,
 | 
			
		||||
            Err(_) => metadata.created().context(format!(
 | 
			
		||||
                "Unable to read created-timestamp of: {}",
 | 
			
		||||
                path.display()
 | 
			
		||||
            ))?,
 | 
			
		||||
        };
 | 
			
		||||
        let mtime = time.duration_since(UNIX_EPOCH).unwrap();
 | 
			
		||||
        Ok(Image {
 | 
			
		||||
            id: uuid.to_string(),
 | 
			
		||||
            path: path_str.to_string(),
 | 
			
		||||
            title: None,
 | 
			
		||||
            last_changed: NaiveDateTime::from_timestamp(
 | 
			
		||||
                mtime.as_secs() as i64,
 | 
			
		||||
                mtime.subsec_nanos() as u32,
 | 
			
		||||
            ),
 | 
			
		||||
            published: false,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								src/schema.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/schema.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
table! {
 | 
			
		||||
    images (id) {
 | 
			
		||||
        id -> Text,
 | 
			
		||||
        path -> Text,
 | 
			
		||||
        title -> Nullable<Text>,
 | 
			
		||||
        last_changed -> Timestamp,
 | 
			
		||||
        published -> Bool,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user