diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index b5a408908..6de3cc697 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -14,6 +14,16 @@ - Updated to work with the new JSON 2.04 module. See gotcha.txt for details. - removed old CS based photo gallery prototype in favor of the new gallery asset + - Added i18n for Gallery (Search) template + - fix: Album description showing up in Photos when photo has no synopsis + - fix: Photo now shows correct confirmation screen + - fix: Photo now gets auto-committed according to Gallery approval workflow + - fix: Formatting problems in Album view + - fix: Photo and Album assets now retain their Owner after other users edit them. + - fix: Gallery::Utility migration now retains createdBy, creationDate, and ownerUserId. + - Testing Gallery::Utility a bit more thoroughly. + - fix: Photo EXIF data now gets cached correctly and sanitized for + references (since JSON won't store them and they're of no use to us anyway). 7.5.0 - rfe: Search Asset returns URLs diff --git a/docs/upgrades/packages-7.5.1/root_import_gallery-templates.wgpkg b/docs/upgrades/packages-7.5.1/root_import_gallery-templates.wgpkg new file mode 100644 index 000000000..983d614b4 Binary files /dev/null and b/docs/upgrades/packages-7.5.1/root_import_gallery-templates.wgpkg differ diff --git a/lib/WebGUI/Asset/File.pm b/lib/WebGUI/Asset/File.pm index 2442a31f4..7a561e3d6 100644 --- a/lib/WebGUI/Asset/File.pm +++ b/lib/WebGUI/Asset/File.pm @@ -326,8 +326,8 @@ sub processPropertiesFromFormPost { my $self = shift; my $session = $self->session; - my $errors = $self->SUPER::processPropertiesFromFormPost; - return $errors if $errors; + my $errors = $self->SUPER::processPropertiesFromFormPost || []; + return $errors if @$errors; if (my $storageId = $session->form->get('newFile','File')) { $session->errorHandler->info("Got a new file for asset " . $self->getId); diff --git a/lib/WebGUI/Asset/File/Image/Photo.pm b/lib/WebGUI/Asset/File/Image/Photo.pm index 1803cf858..fcb17a4d3 100644 --- a/lib/WebGUI/Asset/File/Image/Photo.pm +++ b/lib/WebGUI/Asset/File/Image/Photo.pm @@ -370,6 +370,21 @@ sub getDownloadFileUrl { #---------------------------------------------------------------------------- +=head2 getExifData ( ) + +Gets a hash reference of Exif data about this Photo. + +=cut + +sub getExifData { + my $self = shift; + + return unless $self->get('exifData'); + return from_json( $self->get('exifData') ); +} + +#---------------------------------------------------------------------------- + =head2 getGallery ( ) Gets the Gallery asset this Photo is a member of. @@ -413,12 +428,20 @@ sub getTemplateVars { my $session = $self->session; my $var = $self->get; my $owner = WebGUI::User->new( $session, $self->get("ownerUserId") ); + + # Fix 'undef' vars since HTML::Template does inheritence on them + for my $key ( qw( synopsis ) ) { + unless ( defined $var->{$key} ) { + $var->{ $key } = ''; + } + } $var->{ canComment } = $self->canComment; $var->{ canEdit } = $self->canEdit; $var->{ numberOfComments } = scalar @{ $self->getCommentIds }; $var->{ ownerUsername } = $owner->username; $var->{ url } = $self->getUrl; + $var->{ url_addArchive } = $self->getParent->getUrl('func=addArchive'), $var->{ url_delete } = $self->getUrl('func=delete'); $var->{ url_demote } = $self->getUrl('func=demote'); $var->{ url_edit } = $self->getUrl('func=edit'); @@ -439,8 +462,7 @@ sub getTemplateVars { } ### Format exif vars - my $exif = from_json( delete $var->{exifData} ); - $exif = ImageInfo( $self->getStorageLocation->getPath( $self->get("filename") ) ); + my $exif = $self->getExifData; for my $tag ( keys %$exif ) { # Hash of exif_tag => value $var->{ "exif_" . $tag } = $exif->{$tag}; @@ -593,13 +615,6 @@ sub processPropertiesFromFormPost { return $errors if @$errors; ### Passes all checks - # Fix if adding a new photo - if ( $form->get("assetId") eq "new" ) { - $self->update({ - ownerUserId => $self->session->user->userId, - }); - } - $self->requestAutoCommit; } @@ -677,8 +692,17 @@ sub updateExifDataFromFile { my $self = shift; my $storage = $self->getStorageLocation; - return undef; - my $info = ImageInfo( $storage->getPath( $self->get('filename') ) ); + my $exifTool = Image::ExifTool->new; + $exifTool->Options( PrintConv => 1 ); + my $info = $exifTool->ImageInfo( $storage->getPath( $self->get('filename') ) ); + + # Sanitize Exif data by removing keys with references as values + for my $key ( keys %$info ) { + if ( ref $info->{$key} ) { + delete $info->{$key}; + } + } + $self->update({ exifData => to_json( $info ), }); @@ -860,22 +884,30 @@ sub www_edit { return $self->session->privilege->locked unless $self->canEditIfLocked; # Prepare the template variables - my $var = { - url_addArchive => $self->getParent->getUrl('func=addArchive'), - }; + my $var = $self->getTemplateVars; # Generate the form if ($form->get("func") eq "add") { $var->{ form_start } = WebGUI::Form::formHeader( $session, { action => $self->getParent->getUrl('func=editSave;assetId=new;class='.__PACKAGE__), - }); + }) + . WebGUI::Form::hidden( $session, { + name => 'ownerUserId', + value => $session->user->userId, + }) + ; } else { $var->{ form_start } = WebGUI::Form::formHeader( $session, { action => $self->getUrl('func=editSave'), - }); + }) + . WebGUI::Form::hidden( $session, { + name => 'ownerUserId', + value => $self->get('ownerUserId'), + }) + ; } $var->{ form_start } .= WebGUI::Form::hidden( $session, { diff --git a/lib/WebGUI/Asset/Wobject/Gallery.pm b/lib/WebGUI/Asset/Wobject/Gallery.pm index ea85fd088..2503964e8 100644 --- a/lib/WebGUI/Asset/Wobject/Gallery.pm +++ b/lib/WebGUI/Asset/Wobject/Gallery.pm @@ -364,7 +364,7 @@ sub appendTemplateVarsSearchForm { $var->{ searchForm_className } = WebGUI::Form::radioList( $session, { name => "className", - value => $form->get("className"), + value => ( $form->get("className") || '' ), options => \%searchClassOptions, }); @@ -513,7 +513,6 @@ sub getAlbumIds { my $options = shift; my $orderBy = $options->{ orderBy } || "lineage ASC"; - $self->session->errorHandler->warn("ORDER BY: $orderBy"); my $assets = $self->getLineage(['descendants'], { @@ -914,11 +913,13 @@ sub www_search { . $db->quote( '%' . $form->get("description") . '%' ) ; } + + my $joinClass = [ + 'WebGUI::Asset::Wobject::GalleryAlbum', + 'WebGUI::Asset::File::Image::Photo', + ]; if ( $form->get("className") ) { - $where .= q{ AND asset.className IN ('} - . $db->quoteAndJoin( [$form->get('className','checkList')] ) - . q{)} - ; + $joinClass = [ $form->get('className') ]; } # Build a URL for the pagination @@ -939,7 +940,7 @@ sub www_search { url => $url, keywords => $keywords, where => $where, - joinClass => ['WebGUI::Asset::Wobject::GalleryAlbum', 'WebGUI::Asset::File::Image::Photo'], + joinClass => $joinClass, } ); $var->{ keywords } = $keywords; diff --git a/lib/WebGUI/Asset/Wobject/Gallery/Utility.pm b/lib/WebGUI/Asset/Wobject/Gallery/Utility.pm index 979ed9699..845871495 100644 --- a/lib/WebGUI/Asset/Wobject/Gallery/Utility.pm +++ b/lib/WebGUI/Asset/Wobject/Gallery/Utility.pm @@ -157,6 +157,8 @@ sub addAlbumFromThread { className => 'WebGUI::Asset::Wobject::GalleryAlbum', description => $thread->get('content'), menuTitle => $thread->get('menuTitle'), + createdBy => $thread->get('createdBy'), + creationDate => $thread->get('creationDate'), ownerUserId => $thread->get('ownerUserId'), synopsis => $thread->get('synopsis'), title => $thread->get('title'), @@ -180,12 +182,18 @@ sub addAlbumFromThread { next; } + # Get rid of that file extention + my ($title) = $filename =~ m{(.*)\.[^.]*$}; + my $file = $album->addChild({ className => $className, - menuTitle => $filename, + createdBy => $post->get('createdBy'), + creationDate => $post->get('creationDate'), + menuTitle => $title, ownerUserId => $post->get('ownerUserId'), - title => $filename, - url => $session->url->urlize( $album->get('url') . "/" . $filename ), + synopsis => $post->get('content'), + title => $title, + url => $session->url->urlize( $album->get('url') . "/" . $title ), userDefined1 => $post->get('userDefined1'), userDefined2 => $post->get('userDefined2'), userDefined3 => $post->get('userDefined3'), diff --git a/lib/WebGUI/Asset/Wobject/GalleryAlbum.pm b/lib/WebGUI/Asset/Wobject/GalleryAlbum.pm index 789cc4b75..ec664e7ac 100644 --- a/lib/WebGUI/Asset/Wobject/GalleryAlbum.pm +++ b/lib/WebGUI/Asset/Wobject/GalleryAlbum.pm @@ -494,12 +494,6 @@ sub processPropertiesFromFormPost { return $errors if @$errors; ### Passes all checks - # Fix if adding a new GalleryAlbum - if ( $form->get('assetId') eq "new" ) { - $self->update({ - ownerUserId => $self->session->user->userId, - }); - } $self->requestAutoCommit; } @@ -753,12 +747,20 @@ sub www_edit { $var->{ form_start } = WebGUI::Form::formHeader( $session, { action => $self->getParent->getUrl('func=editSave;assetId=new;class='.__PACKAGE__), + }) + . WebGUI::Form::hidden( $session, { + name => "ownerUserId", + value => $session->user->userId, }); } else { $var->{ form_start } = WebGUI::Form::formHeader( $session, { action => $self->getUrl('func=editSave'), + }) + . WebGUI::Form::hidden( $session, { + name => "ownerUserId", + value => $self->get("ownerUserId"), }); } $var->{ form_start } diff --git a/lib/WebGUI/i18n/English/Asset_Gallery.pm b/lib/WebGUI/i18n/English/Asset_Gallery.pm index 7ad690e72..9fe2e6a4d 100644 --- a/lib/WebGUI/i18n/English/Asset_Gallery.pm +++ b/lib/WebGUI/i18n/English/Asset_Gallery.pm @@ -562,6 +562,61 @@ our $I18N = { lastUpdated => 0, }, + 'template search title' => { + message => "Advanced Search", + lastUpdated => 0, + context => "Title for the www_search page. Used to show the Advanced search form", + }, + + 'template search field title' => { + message => "Title", + lastUpdated => 0, + context => "Label for the 'Title' input for the search form", + }, + + 'template search field description' => { + message => "Description", + lastUpdated => 0, + context => "Label for the 'Description' input for the search form", + }, + + 'template search field keywords' => { + message => "Tags", + lastUpdated => 0, + context => "Label for the 'Keywords' input for the search form. 'Tags' is used because Keywords may be confused with the generic, all-inclusive search box.", + }, + + 'template search field className' => { + message => "Search Type", + lastUpdated => 0, + context => "Label for the 'className' input for the search form. 'Type' is used because 'Class' has no meaning to a normal user.", + }, + + 'template search field creationDate' => { + message => "Date", + lastUpdated => 0, + context => "Label for the 'creation date' input for the search form", + }, + + 'template search to' => { + message => "to", + lastUpdated => 0, + context => "Joins the 'before' and 'after' parts of the Creation Date inputs.", + }, + + 'template search results for' => { + message => "Results for", + lastUpdated => 0, + context => "Title for the results section. 'for' leads into the string that was searched for.", + }, + + 'template by' => { + message => "By", + lastUpdated => 0, + context => "Lead-in for the user the album or photo was uploaded by", + }, + + }; 1; diff --git a/t/Asset/File/Image/Photo/exif.t b/t/Asset/File/Image/Photo/exif.t index f63c49cbd..0d680dd1e 100644 --- a/t/Asset/File/Image/Photo/exif.t +++ b/t/Asset/File/Image/Photo/exif.t @@ -48,6 +48,13 @@ my $photo ); $versionTag->commit; my $exif = ImageInfo( WebGUI::Test->getTestCollateralPath("lamp.jpg") ); +# Sanitize Exif data by removing keys with references as values +for my $key ( keys %$exif ) { + if ( ref $exif->{$key} ) { + delete $exif->{$key}; + } +} + $photo->setFile( WebGUI::Test->getTestCollateralPath("lamp.jpg") ); #---------------------------------------------------------------------------- @@ -65,8 +72,8 @@ plan tests => 2; my $var = $photo->getTemplateVars; cmp_deeply( - [ keys %$var ], superbagof( map { 'exif_' . $_ } keys %$exif ), - 'getTemplateVars gets a hash of all exif tags', + [ keys %$var ], superbagof( map { unless (ref $exif->{ $_ }) { 'exif_' . $_ } } keys %$exif ), + 'getTemplateVars gets a hash of all valid exif tags', ); is_deeply( diff --git a/t/Asset/Wobject/Gallery/Utility/addAlbum.t b/t/Asset/Wobject/Gallery/Utility/addAlbum.t index a6fe57cce..70a1c751f 100644 --- a/t/Asset/Wobject/Gallery/Utility/addAlbum.t +++ b/t/Asset/Wobject/Gallery/Utility/addAlbum.t @@ -49,11 +49,11 @@ for (0..2) { push @threads, $collab->addChild({ className => 'WebGUI::Asset::Post::Thread', content => "content$_", - menuTitle => "menuTitle$_", + menuTitle => "menuTitle$_", ownerUserId => "3$_", synopsis => "synopsis$_", title => "title$_", - userDefined1 => "userDefined1$_", + userDefined1 => "$_", # This is important. Used to detect which File is from which Thread userDefined2 => "userDefined2$_", userDefined3 => "userDefined3$_", userDefined4 => "userDefined4$_", @@ -69,10 +69,10 @@ my @posts; push @{$posts[0]}, $threads[0]->addChild({ className => 'WebGUI::Asset::Post', content => "content00", - menuTitle => "menuTitle00", + menuTitle => "menuTitle00", synopsis => "synopsis00", title => "title00", - userDefined1 => "userDefined100", + userDefined1 => "00", # This is important. Used to detect which File is from which Post userDefined2 => "userDefined200", userDefined3 => "userDefined300", userDefined4 => "userDefined400", @@ -85,6 +85,8 @@ $posts[0][0]->getStorageLocation->addFileFromFilesystem( # Thread fields mapped to album fields that should be migrated my %threadFields = ( content => "description", + createdBy => 'createdBy', + creationDate => 'creationDate', menuTitle => "menuTitle", ownerUserId => "ownerUserId", synopsis => "synopsis", @@ -96,6 +98,19 @@ my %threadFields = ( userDefined5 => "userDefined5", ); +# Post fields mapped to photo fields that should be migrated +my %postFields = ( + content => "synopsis", + createdBy => 'createdBy', + creationDate => 'creationDate', + ownerUserId => "ownerUserId", + userDefined1 => "userDefined1", + userDefined2 => "userDefined2", + userDefined3 => "userDefined3", + userDefined4 => "userDefined4", + userDefined5 => "userDefined5", +); + #---------------------------------------------------------------------------- # Tests @@ -105,7 +120,15 @@ my $threadPostTests = 6 * ( 1 + scalar @{ $posts[0] } ); # addAlbumFromThread adds 1 test for each field in %threadFields my $threadFieldTests = 1 * scalar keys %threadFields; -plan tests => 9 + $threadPostTests + $threadFieldTests; +# addAlbumFromThread adds 1 test for each field in %postFields +my $postFieldTests = 1 * ( scalar keys %postFields ) + * ( 1 + scalar @{ $posts[0] } ); + +plan tests => 10 + + $threadPostTests + + $threadFieldTests + + $postFieldTests + ; #---------------------------------------------------------------------------- # Test use @@ -158,19 +181,28 @@ is( "addAlbumFromThread adds one file for each attachment to the thread or posts of the thread", ); -# 6 tests for each post/file -# TODO: Test that post-to-file fields are migrated properly, but how? +# 6 tests for each post/file + postFields tests my $albumUrl = $album->get('url'); for my $fileId ( @{$album->getFileIds} ) { my $file = WebGUI::Asset->newByDynamicClass( $session, $fileId ); - is( - $file->get('revisionDate'), $threads[0]->get('revisionDate'), - "addAlbumFromThread adds files with same revisionDate as thread", - ); - is( - $file->get('ownerUserId'), $threads[0]->get('ownerUserId'), - "addAlbumFromThread adds files with same ownerUserId as thread", - ); + + # Find which Thread or Post this file corresponds to + my $post; + if ( length $file->get('userDefined1') == 1 ) { + # Is a thread, get it + $post = $threads[ $file->get('userDefined1') ]; + } + else { + my @index = split //, $file->get('userDefined1'); + $post = $posts[ $index[0] ][ $index[1] ]; + } + + for my $oldField ( sort keys %postFields ) { + is ( $file->get( $postFields{ $oldField } ), $post->get( $oldField ), + "addAlbumFromThread migrates Post $oldField to File $postFields{$oldField}", + ); + } + like( $file->get('url'), qr/^$albumUrl/, "addAlbumFromThread add files with urls that begin with GalleryAlbum url", @@ -181,8 +213,17 @@ for my $fileId ( @{$album->getFileIds} ) { $file->getStorageLocation->getFiles, superbagof($file->get('filename')), "Storage location contains the filename" ); + # Test that title and menuTitle do not contain file extention + my ($title) = $file->get('filename') =~ m{(.*)\.[^.]*$}; + is( $file->get('title'), $title, + "Title doesn't contain the file extention" + ); + is( $file->get('menuTitle'), $title, + "Menu title doesn't contain the file extention" + ); } + #---------------------------------------------------------------------------- # Test addAlbumFromCollaboration $gallery = $node->addChild({ className => 'WebGUI::Asset::Wobject::Gallery' });