diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 787f8feec..c89eabf89 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -1,5 +1,6 @@ 7.5.11 - fix: template variable isUncommitted is not documented in the help + - fix: Event is no longer editable by anyone who can add events 7.5.10 - fix: Syntax error in GetCsMail diff --git a/lib/WebGUI/Asset/Event.pm b/lib/WebGUI/Asset/Event.pm index 91e8704dc..0c60d9eaa 100644 --- a/lib/WebGUI/Asset/Event.pm +++ b/lib/WebGUI/Asset/Event.pm @@ -180,16 +180,26 @@ sub canAdd { #################################################################### -=head2 canEdit +=head2 canEdit ( [userId] ) -Returns true if a user can edit this asset. This uses the canEditEvent -from the parent Calendar. +Returns true if the given userId can edit this asset. If userId is not given, +the userId of the current session is used. + +Users can edit this event if they are the owner of the event, or if they are +allowed to edit the parent Calendar. =cut sub canEdit { my $self = shift; - return $self->getParent->canAddEvent; + my $userId = shift; + + if ( !$userId ) { + $userId = $self->session->user->userId; + } + + return 1 if ( $userId eq $self->get('ownerUserId') ); + return $self->getParent->canEdit( $userId ); } diff --git a/lib/WebGUI/Asset/Wobject/Calendar.pm b/lib/WebGUI/Asset/Wobject/Calendar.pm index 74e4f7d37..b0e671173 100644 --- a/lib/WebGUI/Asset/Wobject/Calendar.pm +++ b/lib/WebGUI/Asset/Wobject/Calendar.pm @@ -370,7 +370,7 @@ sub appendTemplateVarsDateTime { #---------------------------------------------------------------------------- -=head2 canEdit +=head2 canEdit ( [userId] ) Returns true if the user can edit this asset. @@ -381,24 +381,33 @@ around the canEdit check when www_editSave is being used to add an asset). sub canEdit { my $self = shift; + my $userId = shift || $self->session->user->userId; my $form = $self->session->form; - my $user = $self->session->user; # Account for new events - return 1 if ($self->canAddEvent && $form->process("func") eq "add"); return 1 if ( - $self->canAddEvent + $self->canAddEvent( $userId ) + && $form->process("func") eq "add" + ); + return 1 if ( + $self->canAddEvent( $userId ) && $form->process("assetId") eq "new" && $form->process("func") eq "editSave" && $form->process("class") eq "WebGUI::Asset::Event" ); - return $self->SUPER::canEdit() + # Who can edit the Calendar can do everything + if ( $self->SUPER::canEdit( $userId ) ) { + return 1; + } + + # Fails all checks + return 0; } #---------------------------------------------------------------------------- -=head2 canAddEvent +=head2 canAddEvent ( [userId] ) Returns true if able to add events. Checks to make sure that the Calendar has been committed at least once. Checks to make sure that @@ -409,7 +418,13 @@ the calendar, or the group that can edit events in the calendar). sub canAddEvent { my $self = shift; - + my $userId = shift; + + my $user = $userId + ? WebGUI::User->new( $self->session, $userId ) + : $self->session->user + ; + # Events can only be added after the Calendar has been committed once return 0 if ( $self->get("status") ne "approved" @@ -417,8 +432,7 @@ sub canAddEvent { ); return 1 if ( - $self->session->user->isInGroup($self->get("groupIdEventEdit")) - || $self->SUPER::canEdit + $user->isInGroup($self->get("groupIdEventEdit")) ); } diff --git a/lib/WebGUI/Utility/Gallery.pm b/lib/WebGUI/Utility/Gallery.pm index 365553fea..0b0fb72f4 100644 --- a/lib/WebGUI/Utility/Gallery.pm +++ b/lib/WebGUI/Utility/Gallery.pm @@ -50,6 +50,10 @@ This module is B to be used by the Gallery asset itself! my $thread = WebGUI::Asset::Post::Thread->new( ... ); $utility->addAlbumFromThread( $gallery, $thread ); + # Add a single album from a Folder asset + my $folder = WebGUI::Asset::Wobject::Folder->new( ... ); + $utility->addAlbumFromFolder( $gallery, $folder ); + # Add a single album from a filesystem branch $utility->addAlbumFromFilesystem( $gallery, "/Users/Doug/Photos" ); @@ -131,6 +135,72 @@ sub addAlbumFromFilesystem { #---------------------------------------------------------------------------- +=head2 addAlbumFromFolder ( gallery, folder ) + +Add an album from a Folder asset filled with File assets. C is an +instance of a Gallery asset. C is an instance of a Folder asset. + +=cut + +sub addAlbumFromFolder { + my $class = shift; + my $gallery = shift; + my $folder = shift; + + croak "First argument must be Gallery asset" + unless blessed $gallery && $gallery->isa('WebGUI::Asset::Wobject::Gallery'); + croak "Second argument must be Folder asset" + unless blessed $folder && $folder->isa('WebGUI::Asset::Wobject::Folder'); + + my $session = $gallery->session; + my $addOptions = { skipAutoCommitWorkflows => 1 }; + + # Create the new album + my $album = $gallery->addChild({ + className => 'WebGUI::Asset::Wobject::GalleryAlbum', + description => $folder->get('description'), + menuTitle => $folder->get('menuTitle'), + createdBy => $folder->get('createdBy'), + creationDate => $folder->get('creationDate'), + ownerUserId => $folder->get('ownerUserId'), + synopsis => $folder->get('synopsis'), + title => $folder->get('title'), + url => $session->url->urlize( $gallery->get('url') . "/" . $folder->get('title') ), + }, undef, $folder->get('revisionDate'), $addOptions ); + + my $fileIds + = $folder->getLineage( ['children'], { + joinClass => 'WebGUI::Asset::File', + } ); + + for my $fileId ( @{ $fileIds } ) { + my $oldFile = WebGUI::Asset->newByDynamicClass( $session, $fileId ); + my $oldStorage = $oldFile->getStorageLocation; + my $className = $gallery->getAssetClassForFile( $oldStorage->getPath( $oldFile->get('filename') ) ); + if ( !$className ) { + warn "Skipping " . $oldFile->get('filename') . " Gallery doesn't handle this file type"; + next; + } + + my $newFile = $album->addChild({ + className => $className, + createdBy => $oldFile->get('createdBy'), + creationDate => $oldFile->get('creationDate'), + menuTitle => $oldFile->get('menuTitle'), + ownerUserId => $oldFile->get('ownerUserId'), + synopsis => $oldFile->get('synopsis'), + title => $oldFile->get('title'), + url => $session->url->urlize( $album->get('url') . "/" . $oldFile->get('menuTitle') ), + }, undef, $oldFile->get('revisionDate'), $addOptions ); + + $newFile->setFile( $oldStorage->getPath( $oldFile->get('filename') ) ); + } + + return undef; +} + +#---------------------------------------------------------------------------- + =head2 addAlbumFromThread ( gallery, thread ) Add an album to the gallery from the given Collaboration System thread. diff --git a/sbin/migrateFolderToGallery.pl b/sbin/migrateFolderToGallery.pl new file mode 100644 index 000000000..78eb4519a --- /dev/null +++ b/sbin/migrateFolderToGallery.pl @@ -0,0 +1,138 @@ + +use lib "../lib"; +use strict; +use Getopt::Long; +use Pod::Usage; +use WebGUI::Utility::Gallery; +use WebGUI::Session; + +my $session = start(); + +my $folder = getFolderFromArgs(); +my $gallery = getGalleryFromArgs(); + +WebGUI::Utility::Gallery->addAlbumFromFolder( $gallery, $folder ); + +finish($session); + +#---------------------------------------------------------------------------- +# getFolderFromArgs +# Gets the folder from the arguments. The argument can be +# either an assetId or an absolute URL +sub getFolderFromArgs { + my $asset; + my $arg = $ARGV[0]; + if ( $arg =~ m{^/} ) { + $asset = WebGUI::Asset->newByUrl( $session, $arg ); + } + else { + $asset = WebGUI::Asset->newByDynamicClass( $session, $arg ); + } + + unless ( $asset && $asset->isa('WebGUI::Asset::Wobject::Folder') ) { + pod2usage("$0: First argument must be a Folder asset"); + } + + return $asset; +} + +#---------------------------------------------------------------------------- +# getGalleryFromArgs +# Gets the Gallery from the arguments. The argument can be either an assetId +# or an absolute URL +sub getGalleryFromArgs { + my $asset; + my $arg = $ARGV[1]; + if ( $arg =~ m{^/} ) { + $asset = WebGUI::Asset->newByUrl( $session, $arg ); + } + else { + $asset = WebGUI::Asset->newByDynamicClass( $session, $arg ); + } + + unless ( $asset && $asset->isa('WebGUI::Asset::Wobject::Gallery') ) { + pod2usage("$0: Second argument must be a Gallery asset"); + } + + return $asset; +} + +#---------------------------------------------------------------------------- +sub start { + $| = 1; #disable output buffering + my ($configFile, $help); + GetOptions( + 'configFile=s' => \$configFile, + 'help' => \$help, + ); + + # Show usage + if ($help) { + pod2usage(1); + } + + unless ($configFile) { + pod2usage("$0: Must specify a --configFile"); + } + + my $session = WebGUI::Session->open("..",$configFile); + $session->user({userId=>3}); + + my $versionTag = WebGUI::VersionTag->getWorking($session); + $versionTag->set({name => 'Migrate Folder to Gallery'}); + + return $session; +} + +#---------------------------------------------------------------------------- +sub finish { + my $session = shift; + + my $versionTag = WebGUI::VersionTag->getWorking($session); + $versionTag->commit; + + $session->var->end; + $session->close; +} + + +=head1 NAME + +migrateFolderToGallery.pl -- Migrate a Folder into a Gallery + +=head1 SYNOPSIS + +migrateFolderToGallery.pl --configFile= + +=head1 ARGUMENTS + +=over + +=item folder + +A Folder URL or asset ID. The URL must be an absolute URL, and +so must begin with a "/". + +=item gallery + +A Gallery URL or asset ID. The URL must be an absolute URL, and so much begin +with a "/". + +=back + +=head1 OPTIONS + +=over + +=item configFile + +The WebGUI config file to use. + +=back + +=head1 DESCRIPTION + +This script migrates a Folder into a gallery album. It +uses C for its major features. + + diff --git a/t/Asset/Event/permissions.t b/t/Asset/Event/permissions.t new file mode 100644 index 000000000..4dbeb78c8 --- /dev/null +++ b/t/Asset/Event/permissions.t @@ -0,0 +1,86 @@ +# vim:syntax=perl +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2008 Plain Black Corporation. +#------------------------------------------------------------------- +# Please read the legal notices (docs/legal.txt) and the license +# (docs/license.txt) that came with this distribution before using +# this software. +#------------------------------------------------------------------ +# http://www.plainblack.com info@plainblack.com +#------------------------------------------------------------------ + +# Write a little about what this script tests. +# +# + +use FindBin; +use strict; +use lib "$FindBin::Bin/../../lib"; +use Test::More; +use WebGUI::Test; # Must use this before any other WebGUI modules +use WebGUI::Test::Maker::Permission; +use WebGUI::Session; + +#---------------------------------------------------------------------------- +# Init +my $session = WebGUI::Test->session; +my $maker = WebGUI::Test::Maker::Permission->new; +my $node = WebGUI::Asset->getImportNode( $session ); + +$session->user({ userId => 3 }); +my @versionTags = (); +push @versionTags, WebGUI::VersionTag->getWorking($session); +$versionTags[-1]->set({name=>"Photo Test, add Gallery, Album and 1 Photo"}); + +my $registeredUser = WebGUI::User->new( $session, "new" ); + +# Make a Calendar to add events do +my $calendar = $node->addChild({ + className => 'WebGUI::Asset::Wobject::Calendar', + groupIdView => '7', # Everyone + groupIdEdit => '3', # Admins + groupIdEventEdit => '2', # Registered Users +}); + +$versionTags[-1]->commit; + +# Arguments for when adding events +my @addArgs = ( undef, undef, { skipAutoCommitWorkflows => 1 } ); + +my $event; + +#---------------------------------------------------------------------------- +# Tests + +plan tests => 12; # Increment this number for each test you create + +#---------------------------------------------------------------------------- +# Test permissions of an event added by the Admin +push @versionTags, WebGUI::VersionTag->getWorking($session); +$versionTags[-1]->set({name=>"Photo Test, add Gallery, Album and 1 Photo"}); +$event = $calendar->addChild({ + className => 'WebGUI::Asset::Event', + ownerUserId => 3, +}, @addArgs); + +$maker->prepare( { + object => $event, + method => 'canView', + pass => [ '1', '3', $registeredUser, ], + fail => [ ], +} )->run; +$maker->prepare( { + object => $event, + method => 'canEdit', + pass => [ '3', ], + fail => [ '1', $registeredUser, ], +} )->run; + +#---------------------------------------------------------------------------- +# Cleanup +END { + for my $tag ( @versionTags ) { + $tag->rollback; + } + $registeredUser->delete; +} diff --git a/t/Utility/Gallery/addAlbum.t b/t/Utility/Gallery/addAlbumFromCollaboration.t similarity index 98% rename from t/Utility/Gallery/addAlbum.t rename to t/Utility/Gallery/addAlbumFromCollaboration.t index cc199fd79..e4ef0adea 100644 --- a/t/Utility/Gallery/addAlbum.t +++ b/t/Utility/Gallery/addAlbumFromCollaboration.t @@ -258,10 +258,6 @@ is( "addAlbumFromCollaboration creates one album per thread", ); -#---------------------------------------------------------------------------- -# Test addAlbumFromFilesystem -# TODO!!! - #---------------------------------------------------------------------------- # Cleanup END { diff --git a/t/Utility/Gallery/addAlbumFromFolder.t b/t/Utility/Gallery/addAlbumFromFolder.t new file mode 100644 index 000000000..ea280932a --- /dev/null +++ b/t/Utility/Gallery/addAlbumFromFolder.t @@ -0,0 +1,180 @@ +# $vim:syntax=perl +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2008 Plain Black Corporation. +#------------------------------------------------------------------- +# Please read the legal notices (docs/legal.txt) and the license +# (docs/license.txt) that came with this distribution before using +# this software. +#------------------------------------------------------------------ +# http://www.plainblack.com info@plainblack.com +#------------------------------------------------------------------ + +# Test the addAlbum* methods from the Gallery::Utility class +# +# + +use strict; +use FindBin; +use lib "$FindBin::Bin/../../lib"; +use Test::More; +use Test::Deep; +use WebGUI::Test; +use WebGUI::Asset; +use WebGUI::Session; + +#---------------------------------------------------------------------------- +# Init +my $session = WebGUI::Test->session; +my $node = WebGUI::Asset->getImportNode( $session ); + +# Add arguments to avoid autocommit workflows +my @addArgs = ( undef, undef, { skipAutoCommitWorkflows => 1 } ); + +my @versionTags; +push @versionTags, WebGUI::VersionTag->getWorking( $session ); + +# Generate a Gallery to import into +my $gallery; +my $album; + +# Generate a folder to import +my $folder + = $node->addChild({ + className => 'WebGUI::Asset::Wobject::Folder', + }); + +my @files; +for (0..2) { + push @files, $folder->addChild({ + className => 'WebGUI::Asset::File::Image', + menuTitle => "menuTitle$_", + ownerUserId => "3$_", + synopsis => "synopsis$_", + title => "title$_", # This is important. Used to detect which GalleryFile is from which File + filename => 'lamp.jpg', + }, @addArgs); + $files[-1]->getStorageLocation->addFileFromFilesystem( + WebGUI::Test->getTestCollateralPath('lamp.jpg') + ); +} + +# File to GalleryFile field mappings. Should be mostly the same +my %fileField = ( + title => "title", + menuTitle => "menuTitle", + synopsis => "synopsis", + ownerUserId => "ownerUserId", + filename => "filename", +); + +# Folder to GalleryAlbum field mappings. +my %folderField = ( + title => "title", + menuTitle => "menuTitle", + description => "description", + createdBy => 'createdBy', + creationDate => 'creationDate', + ownerUserId => 'ownerUserId', + synopsis => 'synopsis', +); + +#---------------------------------------------------------------------------- +# Tests + +# 1 test for each file + file field tests +my $fileTests = scalar @files * ( 3 + scalar keys %fileField ); + +# 1 test for each item in folderField +my $folderTests = scalar keys %folderField; + +plan tests => 10 + + $fileTests + + $folderTests + ; + +#---------------------------------------------------------------------------- +# Test use +my $utility = 'WebGUI::Utility::Gallery'; +use_ok($utility); + +#---------------------------------------------------------------------------- +# Test addAlbumFromFolder +$gallery = $node->addChild({ className => 'WebGUI::Asset::Wobject::Gallery' }); + +ok( + !eval{ $utility->addAlbumFromFolder( "", $folder ); 1}, + "addAlbumFromFolder croaks if first argument is not a Gallery asset", +); + +ok( + !eval{ $utility->addAlbumFromFolder( $gallery, "" ); 1}, + "addAlbumFromFolder croaks if second argument is not a Folder asset", +); + +$utility->addAlbumFromFolder( $gallery, $folder ); + +is( + scalar @{ $gallery->getAlbumIds }, 1, + "addAlbumFromFolder creates a new album", +); + +$album = WebGUI::Asset->newByDynamicClass( $session, $gallery->getAlbumIds->[0] ); + +is( + $album->get('revisionDate'), $folder->get('revisionDate'), + "addAlbumFromFolder creates album with same revisionDate as folder", +); + +my $galleryUrl = $gallery->get('url'); +like( + $album->get('url'), qr/^$galleryUrl/, + "addAlbumFromFolder creates album with url that begins with gallery's url", +); + +# 1 test for each field in %folderField +for my $oldField ( sort keys %folderField ) { + is( $album->get( $folderField{ $oldField } ), $folder->get( $oldField ), + "addAlbumFromFolder migrates Folder $oldField to GalleryAlbum $folderField{$oldField}", + ); +} + +is( + scalar @{ $album->getFileIds }, $folder->getChildCount, + "addAlbumFromFolder adds one file for each File in the Folder", +); + +# 4 tests for each file + fileField tests +my $albumUrl = $album->get('url'); +for my $fileId ( @{$album->getFileIds} ) { + my $newFile = WebGUI::Asset->newByDynamicClass( $session, $fileId ); + + # Find which File this was in the original Folder + ( my $index ) = $newFile->get('title') =~ /title(\d+)/; + my $oldFile = $files[ $index ]; + + for my $oldField ( sort keys %fileField ) { + is ( $newFile->get( $fileField{ $oldField } ), $oldFile->get( $oldField ), + "addAlbumFromFolder migrates File $oldField to GalleryFile $fileField{$oldField}", + ); + } + + like( + $newFile->get('url'), qr/^$albumUrl/, + "addAlbumFromFolder add files with urls that begin with GalleryAlbum url", + ); + isa_ok( $newFile->getStorageLocation, 'WebGUI::Storage', 'Storage location exists' ); + ok( $newFile->get('filename'), '"filename" property was set' ); + cmp_deeply( + $newFile->getStorageLocation->getFiles, superbagof($newFile->get('filename')), + "Storage location contains the filename" + ); +} + + +#---------------------------------------------------------------------------- +# Cleanup +END { + for my $tag ( @versionTags ) { + $tag->rollback; + } +}