diff --git a/lib/WebGUI/Asset/File.pm b/lib/WebGUI/Asset/File.pm index 1965103bd..6d223bf53 100644 --- a/lib/WebGUI/Asset/File.pm +++ b/lib/WebGUI/Asset/File.pm @@ -92,6 +92,24 @@ sub setPrivileges { ); } +#---------------------------------------------------------------------------- + +=head2 commit ( ) + +Override commit to remove all privileges for previous revisions' storage +locations + +=cut + +sub commit { + my ( $self, @args ) = @_; + + for my $rev ( grep { $_->get("revisionDate") < $self->get("revisionDate") } @{$self->getRevisions} ) { + $rev->getStorageLocation->trash; + } + + return $self->SUPER::commit( @args ); +} #------------------------------------------------------------------- @@ -430,7 +448,6 @@ sub processPropertiesFromFormPost { return undef; } - #------------------------------------------------------------------- =head2 purge @@ -479,6 +496,20 @@ sub purgeRevision { #---------------------------------------------------------------------------- +=head2 restore ( ) + +Override trash restore to restore storage location + +=cut + +sub restore { + my ( $self, @args ) = @_; + $self->setPrivileges; + return $self->SUPER::restore( @args ); +} + +#---------------------------------------------------------------------------- + =head2 setFile ( [pathtofile] ) Tells the asset to do all the postprocessing on the file (setting privs, thubnails, or whatever). @@ -561,6 +592,23 @@ sub setStorageLocation { } } +#---------------------------------------------------------------------------- + +=head2 trash ( ) + +Override to put the attached file in the trash too + +=cut + +sub trash { + my ( $self, @args ) = @_; + my $return = $self->SUPER::trash( @args ); + + $self->getStorageLocation->trash; + + return $return; +} + #------------------------------------------------------------------- =head2 update diff --git a/lib/WebGUI/Storage.pm b/lib/WebGUI/Storage.pm index 504778982..9901b2953 100644 --- a/lib/WebGUI/Storage.pm +++ b/lib/WebGUI/Storage.pm @@ -1706,36 +1706,7 @@ sub setPrivileges { } } - my $public; - for my $user (@{ $privs{users} }) { - if ($user eq '1') { - $public = 1; - } - } - for my $group (@{ $privs{groups} }) { - if ($group eq '1' || $group eq '7') { - $public = 1; - } - } - my $accessFile = JSON->new->encode( \%privs ); - - my $dirObj = $self->getPathClassDir(); - return undef if ! defined $dirObj; - $dirObj->recurse( - callback => sub { - my $obj = shift; - return unless $obj->is_dir; - my $rel = $obj->relative($dirObj); - - if ($public) { - $self->deleteFile($rel->file('.wgaccess')->stringify); - } - else { - $self->addFileFromScalar($rel->file('.wgaccess')->stringify, $accessFile); - } - } - ); - + return $self->writeAccess( %privs ); } @@ -1810,6 +1781,19 @@ sub tar { return $temp; } +#---------------------------------------------------------------------------- + +=head2 trash ( ) + +Set this storage location as trashed + +=cut + +sub trash { + my ( $self ) = @_; + return $self->writeAccess( state => "trash" ); +} + #------------------------------------------------------------------- =head2 untar ( filename [, storage ] ) @@ -1869,5 +1853,64 @@ sub getDirectoryId { return $self->{_pathParts}[2]; } +#---------------------------------------------------------------------------- + +=head2 writeAccess( pairs ) + +Write the given pairs to the wgaccess files in this storage location. + +If the storage location should be public, will remove all wgaccess files. + +Possible keys: + + users - an arrayref of userIds to allow access to + groups - an arrayref of groupIds to allow access to + assets - an arrayref of assetIds to validate permissions against + state - a string describing a special state. + valid values: "trash" - storage location is trashed + + +=cut + +sub writeAccess { + my ( $self, %privs ) = @_; + + my $public; + if ( $privs{users} ) { + for my $user (@{ $privs{users} }) { + if ($user eq '1') { + $public = 1; + } + } + } + if ( $privs{groups} ) { + for my $group (@{ $privs{groups} }) { + if ($group eq '1' || $group eq '7') { + $public = 1; + } + } + } + my $accessFile = JSON->new->encode( \%privs ); + + my $dirObj = $self->getPathClassDir(); + return undef if ! defined $dirObj; + $dirObj->recurse( + callback => sub { + my $obj = shift; + return unless $obj->is_dir; + my $rel = $obj->relative($dirObj); + + if ($public) { + $self->deleteFile($rel->file('.wgaccess')->stringify); + } + else { + $self->addFileFromScalar($rel->file('.wgaccess')->stringify, $accessFile); + } + } + ); + + return; +} + 1; diff --git a/lib/WebGUI/URL/Uploads.pm b/lib/WebGUI/URL/Uploads.pm index 000b3c3c1..b17de77dc 100644 --- a/lib/WebGUI/URL/Uploads.pm +++ b/lib/WebGUI/URL/Uploads.pm @@ -15,7 +15,7 @@ package WebGUI::URL::Uploads; =cut use strict; -use Apache2::Const -compile => qw(OK DECLINED NOT_FOUND AUTH_REQUIRED); +use Apache2::Const -compile => qw(OK DECLINED NOT_FOUND AUTH_REQUIRED FORBIDDEN); use WebGUI::Session; =head1 NAME @@ -61,6 +61,7 @@ sub handler { my @users; my @groups; my @assets; + my $state; if ($fileContents =~ /\A(?:\d+|[A-Za-z0-9_-]{22})\n(?:\d+|[A-Za-z0-9_-]{22})\n(?:\d+|[A-Za-z0-9_-]{22})/) { my @privs = split("\n", $fileContents); push @users, $privs[0]; @@ -71,8 +72,12 @@ sub handler { @users = @{ $privs->{users} }; @groups = @{ $privs->{groups} }; @assets = @{ $privs->{assets} }; + $state = $privs->{state}; } + return Apache2::Const::FORBIDDEN + if $state eq "trash"; + return Apache2::Const::OK if grep { $_ eq '1' } @users; diff --git a/t/Asset/File.t b/t/Asset/File.t index d446964c4..ba23841c4 100644 --- a/t/Asset/File.t +++ b/t/Asset/File.t @@ -25,7 +25,7 @@ use JSON; use Test::More; # increment this value for each test you create use Test::Deep; -plan tests => 13; +plan tests => 18; #TODO: This script tests certain aspects of WebGUI::Storage and it should not @@ -126,6 +126,42 @@ WebGUI::Test::addToCleanup( WebGUI::VersionTag->getWorking( $session ) ); is( $newRev->getStorageLocation->getFileContentsAsScalar('.wgaccess'), undef, "wgaccess doesn't exist" ); note( @{ $newRev->getStorageLocation->getFiles() } ); +#---------------------------------------------------------------------------- +# commit on new revision trashes old revision +$newRev->commit; +my $storage = $asset->getStorageLocation; +my $dir = $storage->getPathClassDir(); +ok(-e $dir->file('.wgaccess')->stringify, 'commit: .wgaccess file created'); +my $privs; +$privs = $storage->getFileContentsAsScalar('.wgaccess'); +is ($privs, '{"state":"trash"}', '... correct state'); + +#---------------------------------------------------------------------------- +# trash should update storage location +my $tag = WebGUI::VersionTag->getWorking( $session ); +$asset = $defaultAsset->addChild( $properties ); +$asset->getStorageLocation->addFileFromScalar($filename, $filename); +$asset->update({ + filename => $filename, +}); + +$tag->commit; +addToCleanup( $tag ); +$asset->trash; +my $storage = $asset->getStorageLocation; +my $dir = $storage->getPathClassDir(); +ok(-e $dir->file('.wgaccess')->stringify, 'trash: .wgaccess file created') + or note( $dir->file('.wgaccess')->stringify ); +my $privs; +$privs = $storage->getFileContentsAsScalar('.wgaccess'); +is ($privs, '{"state":"trash"}', '... correct state'); + +#---------------------------------------------------------------------------- +# restore should de-trash storage location +$asset->restore; +unlike( $storage->getFileContentsAsScalar('.wgaccess'), qr{"state"\:"trash"}, "wgaccess not trashed" ); + + ############################################ # # www_view diff --git a/t/Storage.t b/t/Storage.t index f5cb96a00..8fcfe419c 100644 --- a/t/Storage.t +++ b/t/Storage.t @@ -31,7 +31,7 @@ my $cwd = Cwd::cwd(); my ($extensionTests, $fileIconTests, $block_extension_tests) = setupDataDrivenTests($session); -plan tests => 141 +plan tests => 155 + scalar @{ $extensionTests } + scalar @{ $fileIconTests } + scalar @{ $block_extension_tests } @@ -518,6 +518,64 @@ foreach my $iconTest (@{ $fileIconTests }) { is( $storage1->getFileIconUrl($iconTest->{filename}), $iconTest->{iconUrl}, $iconTest->{comment} ); } +#---------------------------------------------------------------------------- +# writeAccess +my $shallowStorage = WebGUI::Storage->create($session); +addToCleanup($shallowStorage); +$shallowStorage->writeAccess( users => ["3"], groups => ["2"], assets => ["1"] ); +my $shallowDir = $shallowStorage->getPathClassDir(); +ok(-e $shallowDir->file('.wgaccess')->stringify, 'writeAccess: .wgaccess file created in shallow storage'); +my $privs; +$privs = $shallowStorage->getFileContentsAsScalar('.wgaccess'); +is ($privs, '{"assets":["1"],"groups":["2"],"users":["3"]}', '... correct group contents'); +$shallowStorage->deleteFile('.wgaccess'); + +my $deepStorage = WebGUI::Storage->create($session); +addToCleanup($deepStorage); +my $deepDir = $deepStorage->getPathClassDir(); +my $deepDeepDir = $deepDir->subdir('deep'); +my $errorStr; +$deepDeepDir->mkpath({ error => \$errorStr } ); +ok(-e $deepDeepDir->stringify, 'created storage directory with a subdirectory for testing'); + +$deepStorage->writeAccess( users => ["3"], groups => ["2"], assets => ["1"] ); +ok(-e $deepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage'); +ok(-e $deepDeepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage subdir'); + +$privs = $deepStorage->getFileContentsAsScalar('.wgaccess'); +is ($privs, '{"assets":["1"],"groups":["2"],"users":["3"]}', '... correct group contents, deep storage'); +$privs = $deepStorage->getFileContentsAsScalar('deep/.wgaccess'); +is ($privs, '{"assets":["1"],"groups":["2"],"users":["3"]}', '... correct group contents, deep storage subdir'); + +#---------------------------------------------------------------------------- +# trash +my $shallowStorage = WebGUI::Storage->create($session); +addToCleanup($shallowStorage); +$shallowStorage->trash; +my $shallowDir = $shallowStorage->getPathClassDir(); +ok(-e $shallowDir->file('.wgaccess')->stringify, 'trash: .wgaccess file created in shallow storage'); +my $privs; +$privs = $shallowStorage->getFileContentsAsScalar('.wgaccess'); +is ($privs, '{"state":"trash"}', '... correct state'); +$shallowStorage->deleteFile('.wgaccess'); + +my $deepStorage = WebGUI::Storage->create($session); +addToCleanup($deepStorage); +my $deepDir = $deepStorage->getPathClassDir(); +my $deepDeepDir = $deepDir->subdir('deep'); +my $errorStr; +$deepDeepDir->mkpath({ error => \$errorStr } ); +ok(-e $deepDeepDir->stringify, 'created storage directory with a subdirectory for testing'); + +$deepStorage->trash; +ok(-e $deepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage'); +ok(-e $deepDeepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage subdir'); + +$privs = $deepStorage->getFileContentsAsScalar('.wgaccess'); +is ($privs, '{"state":"trash"}', '... correct state contents, deep storage'); +$privs = $deepStorage->getFileContentsAsScalar('deep/.wgaccess'); +is ($privs, '{"state":"trash"}', '... correct state contents, deep storage subdir'); + #################################################### # # setPrivileges