From 8ff6d351c4af25e3e7b3f882e2dec3b7f6f74d35 Mon Sep 17 00:00:00 2001 From: Denis Fedoseev Date: Sun, 9 Sep 2018 16:56:33 +0300 Subject: [PATCH] saving exif metadata --- fotostore.pl | 112 ++++++++++++++++--------- lib/FotoStore/DB.pm | 74 +++++++++++----- sql/deploy/albums.sql | 4 +- sql/deploy/exif_data.sql | 6 +- sql/revert/images@v1.0.0.sql | 5 ++ sql/sqitch.plan | 2 + sql/verify/images@v1.0.0.sql | 7 ++ templates/includes/images_list.html.ep | 45 +++++----- templates/layouts/base.html.ep | 4 +- 9 files changed, 168 insertions(+), 91 deletions(-) create mode 100644 sql/revert/images@v1.0.0.sql create mode 100644 sql/verify/images@v1.0.0.sql diff --git a/fotostore.pl b/fotostore.pl index 96da165..db56d2f 100755 --- a/fotostore.pl +++ b/fotostore.pl @@ -38,8 +38,8 @@ $scales_map->{$thumbs_size} = 1; #Sort and filter values for array of available scales my @scale_width = - map { $scales_map->{$_} == 1 ? $_ : undef } - sort { $a <=> $b } keys(%$scales_map); + map { $scales_map->{$_} == 1 ? $_ : undef } + sort { $a <=> $b } keys(%$scales_map); my $sha = Digest::SHA->new('sha256'); @@ -156,31 +156,31 @@ get '/get_images' => ( authenticated => 1 ) => sub { if (($page !~ /^\d+$/) || ($page <= 1)) { $page = 1} if (($items !~ /^\d+$/) || ($items <= 0)) { $items = 20} - + # process images list my $req_result = $db->get_files( $current_user->{'user_id'}, $items , $page); my $files_list = $req_result->{'images_list'}; my $pages_count = ceil($req_result->{'total_rows'}/$items); my $thumbs_dir = - File::Spec->catfile( $IMAGE_DIR, $current_user->{'user_id'}, - $thumbs_size ); + File::Spec->catfile( $IMAGE_DIR, $current_user->{'user_id'}, + $thumbs_size ); - my @images = map { $_->{'file_name'} } @$files_list; + my @images = map { $_->file_name } @$files_list; my $images = []; for my $img_item (@$files_list) { - my $file = $img_item->{'file_name'}; + my $file = $img_item->file_name; my $img_hash = {}; - $img_hash->{'id'} = $img_item->{'file_id'}; - $img_hash->{'filename'} = $img_item->{'original_filename'}; + $img_hash->{'id'} = $img_item->file_id; + $img_hash->{'filename'} = $img_item->original_filename; $img_hash->{'original_url'} = - File::Spec->catfile( '/', $IMAGE_BASE, $current_user->{'user_id'}, - $ORIG_DIR, $file ); + File::Spec->catfile( '/', $IMAGE_BASE, $current_user->{'user_id'}, + $ORIG_DIR, $file ); $img_hash->{'thumbnail_url'} = - File::Spec->catfile( '/', $IMAGE_BASE, $current_user->{'user_id'}, - $thumbs_size, $file ); + File::Spec->catfile( '/', $IMAGE_BASE, $current_user->{'user_id'}, + $thumbs_size, $file ); my @scaled = (); for my $scale (@scale_width) { @@ -196,14 +196,13 @@ get '/get_images' => ( authenticated => 1 ) => sub { } ); } - } $img_hash->{'scales'} = \@scaled; push( @$images, $img_hash ); - + } my $reply_data = { current_page => $page, items_per_page => $items, pages_count => $pages_count, images_list => $images }; @@ -252,32 +251,53 @@ post '/upload' => ( authenticated => 1 ) => sub { # Image file my $filename = sprintf( '%s.%s', create_hash( $image->slurp() ), $ext ); my $image_file = - File::Spec->catfile( get_path( $user_id, $ORIG_DIR ), $filename ); + File::Spec->catfile( get_path( $user_id, $ORIG_DIR ), $filename ); # Save to file $image->move_to($image_file); - - my $promise = store_image($image_file, $image->filename, $user_id); - + my $imager = Imager->new(); + $imager->read( file => $image_file ) or die $imager->errstr; + + my $promise = store_image($imager , $filename, $image->filename, $user_id); + #TODO: add errors handling Mojo::Promise->all($promise)->then(sub { + $log->debug(Dumper(\@_)); + my $res = shift; + save_tags($imager, $res->[1]); + $self->render( - json => { - files => [ - { - name => $image->filename, - size => $image->size, - url => sprintf( '/images/orig/%s', $filename ), - thumbnailUrl => sprintf( '/images/200/%s', $filename ), - } - ] - } - ); + json => { + files => [ + { + name => $image->filename, + size => $image->size, + url => sprintf( '/images/orig/%s', $filename ), + thumbnailUrl => sprintf( '/images/200/%s', $filename ), + } + ] + } + ); })->wait; } => 'upload'; +post '/album' => ( authenticated => 1 ) => sub { + my $self = shift; + + my $user_id = $self->current_user()->{'user_id'}; + my $album_name = $self->req->param('album_name'); + my $album_desc = $self->req->param('album_desc') || ''; + + my $album = $db->add_album($user_id, $album_name, $album_desc); + $self->render( + json => { album_id => $album->album_id, + album_name => $album->album_name + } + ) +}; + sub create_hash { my $data_to_hash = shift; @@ -295,7 +315,8 @@ sub get_path { } sub store_image { - my $image_file = shift; + my $imager = shift; + my $filename = shift; my $original_filename = shift; my $user_id = shift; @@ -303,12 +324,6 @@ sub store_image { # Process and store uploaded file in a separate process Mojo::IOLoop->subprocess( sub { - my $subprocess = shift; - - my $filename = fileparse($image_file); - my $imager = Imager->new(); - $imager->read( file => $image_file ) or die $imager->errstr; - #http://sylvana.net/jpegcrop/exif_orientation.html #http://myjaphoo.de/docs/exifidentifiers.html my $rotation_angle = $imager->tags( name => "exif_orientation" ) || 1; @@ -335,16 +350,17 @@ sub store_image { $scaled->write( file => File::Spec->catfile( get_path( $user_id, $scale ), $filename ) ) - or die $scaled->errstr; + or die $scaled->errstr; } - if ( !$db->add_file( $user_id, $filename, $original_filename ) ) { - + my $file_info = $db->add_file( $user_id, $filename, $original_filename ); + if ( !defined $file_info ) { $log->error(sprintf('Can\'t save file %s', $filename)); die sprintf('Can\'t save file %s', $filename); } - return $filename; + + return $file_info->file_id; }, sub { my ($subprocess, $err, @results) = @_; @@ -357,5 +373,19 @@ sub store_image { return $promise; } +sub save_tags { + my $image = shift; + my $db_file_id = shift; + +# $log->debug(Dumper($image->tags())); + my @tags = $image->tags(); +# $log->debug(Dumper(\@tags)); + for my $tag (@tags) { + $log->debug(sprintf("tag: [%s] [%s]", $tag->[0], $tag->[1])); + my $row = $db->save_tag($db_file_id, $tag->[0], $tag->[1]); +# $log->debug(Dumper($row)); + } +} + Mojo::IOLoop->start; app->start; diff --git a/lib/FotoStore/DB.pm b/lib/FotoStore/DB.pm index 4951676..0ae60c1 100644 --- a/lib/FotoStore/DB.pm +++ b/lib/FotoStore/DB.pm @@ -4,24 +4,30 @@ use v5.20; use strict; use warnings; -use feature qw(signatures); +use feature qw(signatures say); no warnings qw(experimental::signatures); +use Data::Dumper; +use DBIx::Struct; + + + sub new { my $class = shift; my $db_file = shift; - my $dbh = DBI->connect(sprintf('dbi:SQLite:dbname=%s', $db_file),"",""); + my $dbix = DBIx::Struct::connect(sprintf('dbi:SQLite:dbname=%s', $db_file),"",""); + my $self = { - dbh => $dbh, + dbix_connector => $dbix, }; bless $self, $class; return $self; } sub check_user ($self, $nickname, $password) { - my ($user_id) = $self->{'dbh'}->selectrow_array(q~select user_id from users where nickname=? and password=?~, undef, ($nickname, $password)); - return $user_id; + my $row = one_row('users', { nickname => $nickname, password => $password }); + return $row->user_id; } sub get_user ($self, $user_id) { @@ -33,31 +39,31 @@ sub get_user ($self, $user_id) { } sub _get_user_by_user_id ($self, $user_id) { - my $user_data = $self->{'dbh'}->selectrow_hashref(q~select user_id, nickname, fullname, timestamp from users where user_id=?~, {}, ($user_id)); - return $user_data; + my $row = one_row('users', {user_id => $user_id}) || return {}; + return {user_id => $row->user_id, nickname => $row->nickname, fullname => $row->fullname, timestamp => $row->timestamp}; } sub _get_user_by_username($self, $username) { - my $user_data = $self->{'dbh'}->selectrow_hashref(q~select user_id, nickname, fullname, timestamp from users where nickname=?~, {}, ($username)); - return $user_data; + my $row = one_row('users', {nickname => $username}) || return {}; + return {user_id => $row->user_id, nickname => $row->nickname, fullname => $row->fullname, timestamp => $row->timestamp}; } sub add_user($self, $username, $password, $fullname) { - my $rows = $self->{'dbh'}->do(q~insert into users (nickname, password, fullname) values (?, ?, ?)~, undef, ($username, $password, $fullname)); - if ($self->{'dbh'}->errstr) { - die $self->{'dbh'}->errstr; - } - return $rows; + my $row = new_row('users', nickname => $username, password => $password, fullname => $fullname); + return $row; } sub add_file($self, $user_id, $filename, $original_filename) { - my $rows = $self->{'dbh'}->do(q~insert into images (owner_id, file_name, original_filename) values (?, ?, ?)~, undef, ($user_id, $filename, $original_filename)); - if ($self->{'dbh'}->errstr) { - die $self->{'dbh'}->errstr; - } - return $rows; + + my $row = new_row('images', + owner_id => $user_id, + file_name => $filename, + original_filename => $original_filename + ); + + return $row; } sub get_files($self, $user_id, $items_count=20, $page=1) { @@ -67,10 +73,36 @@ sub get_files($self, $user_id, $items_count=20, $page=1) { $page = 1 if ($page < 1); my $start_at = --$page * $items_count; - my ($rows_count) = $self->{'dbh'}->selectrow_array(q~select count(*) from images where owner_id=? ~, undef , $user_id); - my $images_list = $self->{'dbh'}->selectall_arrayref(q~select * from images where owner_id=? order by created_time desc LIMIT ? OFFSET ? ~, { Slice => {} }, $user_id, $items_count, $start_at ); +# my ($rows_count) = $self->{'dbh'}->selectrow_array(q~select count(*) from images where owner_id=? ~, undef , $user_id); + my $rows_count = one_row(['images' => -count => 'file_id', -where => { 'owner_id' => $user_id}] ); + +# my $images_list = $self->{'dbh'}->selectall_arrayref(q~select * from images where owner_id=? order by created_time desc LIMIT ? OFFSET ? ~, { Slice => {} }, $user_id, $items_count, $start_at ); + my $images_list = all_rows([ + 'images' => + -where => { 'owner_id' => $user_id }, + -limit => $items_count, + -offset => $start_at + ]); return { total_rows => $rows_count, images_list => $images_list }; } +sub add_album($self, $user_id, $album_name, $album_desc) { + my $row = new_row('albums', name => $album_name, description => $album_desc, owner_id => $user_id); + return $row; +} + +sub save_tag($self, $db_file_id, $tag_name, $tag_value) { + say STDERR ("[$db_file_id][$tag_name][$tag_value]"); + eval { + my $row = new_row('exif_data', 'exif_tag' => $tag_name, 'tag_data' => $tag_value,'image_id' => $db_file_id, deleted => 0) || die "error!"; + say STDERR (Dumper($row)); + return $row; + }; + if ($@) { + say STDERR ("Error! $@"); + } +} + + 1; \ No newline at end of file diff --git a/sql/deploy/albums.sql b/sql/deploy/albums.sql index b81fbc5..c9a8f6b 100644 --- a/sql/deploy/albums.sql +++ b/sql/deploy/albums.sql @@ -2,7 +2,7 @@ BEGIN; -CREATE TABLE "albums" ( +CREATE TABLE `albums` ( `album_id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` STRING NOT NULL, `description` TEXT, @@ -10,6 +10,6 @@ CREATE TABLE "albums" ( `modified` DATETIME DEFAULT (CURRENT_TIMESTAMP), `deleted` BOOLEAN, `owner_id` INTEGER NOT NULL - ) + ); COMMIT; diff --git a/sql/deploy/exif_data.sql b/sql/deploy/exif_data.sql index be111ab..a639021 100644 --- a/sql/deploy/exif_data.sql +++ b/sql/deploy/exif_data.sql @@ -3,11 +3,11 @@ BEGIN; CREATE TABLE `exif_data` ( - `record_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `record_id` INTEGER PRIMARY KEY AUTOINCREMENT, `exif_tag` TEXT NOT NULL, `tag_data` TEXT NOT NULL, - `image_id` INTEGER, - `deleted` BOOLEAN + `image_id` INTEGER NOT NULL, + `deleted` BOOLEAN DEFAULT 0 ); COMMIT; diff --git a/sql/revert/images@v1.0.0.sql b/sql/revert/images@v1.0.0.sql new file mode 100644 index 0000000..7153600 --- /dev/null +++ b/sql/revert/images@v1.0.0.sql @@ -0,0 +1,5 @@ +BEGIN; + +DROP TABLE images; + +COMMIT; \ No newline at end of file diff --git a/sql/sqitch.plan b/sql/sqitch.plan index d7782a9..fdb73c4 100644 --- a/sql/sqitch.plan +++ b/sql/sqitch.plan @@ -11,3 +11,5 @@ user_albums [users albums] 2017-07-22T09:47:48Z Denis Fedoseev # Tag v1.0.0. images [images@v1.0.0] 2017-08-02T03:55:08Z Denis Fedoseev # Adds images.original_filename. @v1.1.0 2017-08-02T04:46:42Z Denis Fedoseev # Tag v1.1.0. + +exif_data 2018-08-19T08:04:49Z Denis Fedoseev # exif data table diff --git a/sql/verify/images@v1.0.0.sql b/sql/verify/images@v1.0.0.sql new file mode 100644 index 0000000..ca328d4 --- /dev/null +++ b/sql/verify/images@v1.0.0.sql @@ -0,0 +1,7 @@ +-- Verify fotostore:images on sqlite + +BEGIN; + +select file_id, owner_id, file_name, created_time from images where 0; + +ROLLBACK; \ No newline at end of file diff --git a/templates/includes/images_list.html.ep b/templates/includes/images_list.html.ep index cece072..89cea63 100644 --- a/templates/includes/images_list.html.ep +++ b/templates/includes/images_list.html.ep @@ -5,26 +5,7 @@ - +
@@ -109,7 +90,6 @@ xhr.onload = function () { var result = JSON.parse(xhr.responseText); self.imagesList = result.images_list; - console.dir(self.imagesList); self.pagesCount = result.pages_count; } xhr.send() @@ -125,4 +105,25 @@ } }); - \ No newline at end of file + + \ No newline at end of file diff --git a/templates/layouts/base.html.ep b/templates/layouts/base.html.ep index b978e6a..a9e0270 100644 --- a/templates/layouts/base.html.ep +++ b/templates/layouts/base.html.ep @@ -1,7 +1,7 @@ - Rough, Slow, Stupid, Contrary Photohosting + Simple image hosting @@ -14,7 +14,7 @@ - +