diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 542abdaa5..f41265ec2 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -2,6 +2,9 @@ - added #11477: No synopsis in asset now means no synopsis in search index - added #11007: Added drag'n'drop sorting in Gallery Album Edit View (Bernd Kalbfuß-Zimmermann) - added Better comment rating icons. + - fixed #11520: Wiki Locked + - fixed Missing Template variables for the Wiki Page view template. + - added #10944: Wiki Keyword Page 7.9.2 - added: Workflow to extend recurring Calendar events 2 years from the diff --git a/docs/gotcha.txt b/docs/gotcha.txt index e434138bf..790d62dde 100644 --- a/docs/gotcha.txt +++ b/docs/gotcha.txt @@ -17,9 +17,15 @@ save you many hours of grief. - Moose - CHI +7.9.3 +-------------------------------------------------------------------- + * Test:Deep, which had been an optional dependency for testing, has been used + in components of the core for a while, since the release of the new Survey. + Test::Deep version 0.095 or higher is now required. + 7.9.2 -------------------------------------------------------------------- - * new dependency: DateTime::Event::ICal + * new dependency: DateTime::Event::ICal 0.10 or higher 7.9.0 -------------------------------------------------------------------- diff --git a/docs/upgrades/packages-7.9.3/default-wiki-page.wgpkg b/docs/upgrades/packages-7.9.3/default-wiki-page.wgpkg new file mode 100644 index 000000000..54846118b Binary files /dev/null and b/docs/upgrades/packages-7.9.3/default-wiki-page.wgpkg differ diff --git a/lib/WebGUI/Asset/File.pm b/lib/WebGUI/Asset/File.pm index 6b8887c4d..85088f2b0 100644 --- a/lib/WebGUI/Asset/File.pm +++ b/lib/WebGUI/Asset/File.pm @@ -119,10 +119,19 @@ A hash reference of optional parameters. None at this time. sub applyConstraints { my $self = shift; - $self->getStorageLocation->setPrivileges($self->ownerUserId, $self->groupIdView, $self->groupIdEdit); + $self->setPrivileges; $self->setSize; } +sub setPrivileges { + my $self = shift; + $self->getStorageLocation->setPrivileges( + $self->ownerUserId, + $self->groupIdView, + $self->groupIdEdit, + ); +} + #------------------------------------------------------------------- diff --git a/lib/WebGUI/Asset/File/GalleryFile.pm b/lib/WebGUI/Asset/File/GalleryFile.pm index 78e96e9be..f812a69ba 100644 --- a/lib/WebGUI/Asset/File/GalleryFile.pm +++ b/lib/WebGUI/Asset/File/GalleryFile.pm @@ -1178,5 +1178,10 @@ sub www_view { return "chunked"; } +sub setPrivileges { + my $self = shift; + $self->getStorageLocation->setPrivileges($self); +} + 1; # Who knew the truth would be so obvious? diff --git a/lib/WebGUI/Asset/WikiPage.pm b/lib/WebGUI/Asset/WikiPage.pm index ae601abd6..a8c22fb1e 100644 --- a/lib/WebGUI/Asset/WikiPage.pm +++ b/lib/WebGUI/Asset/WikiPage.pm @@ -230,13 +230,17 @@ Get the common template vars for this asset sub getTemplateVars { my ( $self ) = @_; - my $i18n = WebGUI::International->new($self->session, "Asset_WikiPage"); - my $wiki = $self->getWiki; - my $owner = WebGUI::User->new( $self->session, $self->ownerUserId ); - my $keywords = WebGUI::Keyword->new($self->session)->getKeywordsForAsset({ + my $session = $self->session; + my $i18n = WebGUI::International->new($session, "Asset_WikiPage"); + my $wiki = $self->getWiki; + my $owner = WebGUI::User->new( $session, $self->ownerUserId ); + my $keyObj = WebGUI::Keyword->new($session); + + my $keywords = $keyObj->getKeywordsForAsset({ asset => $self, asArrayRef => 1, }); + my @keywordsLoop = (); foreach my $word (@{$keywords}) { push @keywordsLoop, { @@ -270,11 +274,35 @@ sub getTemplateVars { $self->scrubContent, {skipTitles => [$self->title]}, ), + isKeywordPage => $self->isKeywordPage, isSubscribed => $self->isSubscribed, subscribeUrl => $self->getSubscribeUrl, unsubscribeUrl => $self->getUnsubscribeUrl, owner => $owner->get('alias'), }; + my @keyword_pages = (); + if ($var->{isKeywordPage}) { + my $paginator = $keyObj->getMatchingAssets({ + startAsset => $self->getWiki, + keyword => $self->get('title'), + usePaginator => 1, + }); + PAGE: foreach my $assetId (@{ $paginator->getPageData }) { + next PAGE if $assetId->{assetId} eq $self->getId; + my $asset = WebGUI::Asset->newByDynamicClass($session, $assetId->{assetId}); + next PAGE unless $asset; + push @keyword_pages, { + title => $asset->getTitle, + url => $asset->getUrl, + }; + } + $paginator->appendTemplateVars($var); + @keyword_pages = map { $_->[1] } + sort + map { [ lc $_->{title}, $_ ] } + @keyword_pages; + } + $var->{keyword_page_loop} = \@keyword_pages; return $var; } @@ -312,6 +340,24 @@ around indexContent => sub { #------------------------------------------------------------------- +=head2 isKeywordPage + +Returns a boolean indicating whether or not the name of this WikiPage matches any keyword in the Wiki that +contains it. + +=cut + +sub isKeywordPage { + my $self = shift; + my $keywords = WebGUI::Keyword->new($self->session)->getMatchingAssets({ + asset => $self->getWiki, + keyword => $self->get('title'), + }); + return scalar @{ $keywords }; +} + +#------------------------------------------------------------------- + =head2 preparePageTemplate This is essentially prepareView, but is smart and will only do the template diff --git a/lib/WebGUI/Help/Asset_WikiPage.pm b/lib/WebGUI/Help/Asset_WikiPage.pm index f0f61076f..dc11d5976 100644 --- a/lib/WebGUI/Help/Asset_WikiPage.pm +++ b/lib/WebGUI/Help/Asset_WikiPage.pm @@ -48,6 +48,9 @@ our $HELP = { { tag => 'wiki page asset template variables', namespace => 'Asset_WikiPage' }, + { tag => 'pagination template variables', + namespace => 'WebGUI' + }, ], variables => [ { name => 'viewLabel', @@ -78,6 +81,16 @@ our $HELP = { }, { 'name' => 'editContent', }, { 'name' => 'content', }, + { 'name' => 'keywordsLoop', + 'variables' => [ + { 'name' => 'keyword', + 'description' => 'keyword title', + }, + { 'name' => 'url', + 'description' => 'keyword url', + }, + ], + }, { name => 'isSubscribed', description => 'help isSubscribed', @@ -94,6 +107,17 @@ our $HELP = { name => 'owner', description => 'help owner', }, + { 'name' => 'isKeywordPage', }, + { 'name' => 'keyword_page_loop', + 'variables' => [ + { 'name' => 'title', + 'description' => 'keyword page title', + }, + { 'name' => 'url', + 'description' => 'keyword page url', + }, + ], + }, ], related => [], }, diff --git a/lib/WebGUI/Storage.pm b/lib/WebGUI/Storage.pm index be9f434b1..c988d1b73 100644 --- a/lib/WebGUI/Storage.pm +++ b/lib/WebGUI/Storage.pm @@ -27,6 +27,7 @@ use Path::Class::Dir; use Storable (); use WebGUI::Utility qw(isIn); use WebGUI::Paths; +use JSON (); =head1 NAME @@ -1666,10 +1667,42 @@ The groupId that is allowed to edit the files in this storage location. =cut sub setPrivileges { - my $self = shift; - my $owner = shift; - my $viewGroup = shift; - my $editGroup = shift; + my $self = shift; + my %privs = ( + users => [], + groups => [], + assets => [], + ); + if (@_ == 3 && !ref $_[0] && !ref $_[1] && !ref $_[0]) { + push @{ $privs{users} }, $_[0]; + push @{ $privs{groups} }, @_[1,2]; + } + else { + for my $object (@_) { + if ($object->isa('WebGUI::User')) { + push @{ $privs{users} }, $object->getId; + } + elsif ($object->isa('WebGUI::Group')) { + push @{ $privs{groups} }, $object->getId; + } + elsif ($object->isa('WebGUI::Asset')) { + push @{ $privs{assets} }, $object->getId; + } + } + } + + 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; @@ -1679,11 +1712,11 @@ sub setPrivileges { return unless $obj->is_dir; my $rel = $obj->relative($dirObj); - if ($owner eq '1' || $viewGroup eq '1' || $viewGroup eq '7' || $editGroup eq '1' || $editGroup eq '7') { + if ($public) { $self->deleteFile($rel->file('.wgaccess')->stringify); } else { - $self->addFileFromScalar($rel->file('.wgaccess')->stringify,$owner."\n".$viewGroup."\n".$editGroup); + $self->addFileFromScalar($rel->file('.wgaccess')->stringify, $accessFile); } } ); diff --git a/lib/WebGUI/URL/Uploads.pm b/lib/WebGUI/URL/Uploads.pm index c07efc9c6..bea5a99f7 100644 --- a/lib/WebGUI/URL/Uploads.pm +++ b/lib/WebGUI/URL/Uploads.pm @@ -47,38 +47,57 @@ The Apache request handler for this package. sub handler { my ($request, $server, $config) = @_; - $request->push_handlers(PerlAccessHandler => sub { - if (-e $request->filename) { - my $path = $request->filename; - $path =~ s/^(\/.*\/).*$/$1/; - if (-e $path.".wgaccess") { - my $fileContents; - open(my $FILE, "<" ,$path.".wgaccess"); - while (my $line = <$FILE>) { - $fileContents .= $line; - } - close($FILE); - my @privs = split("\n", $fileContents); - unless ($privs[1] eq "7" || $privs[1] eq "1") { - my $session = $request->pnotes('wgSession'); - unless (defined $session) { - $session = WebGUI::Session->open($config->getFilename, $request, $server); - } - my $hasPrivs = ($session->var->get("userId") eq $privs[0] || $session->user->isInGroup($privs[1]) || $session->user->isInGroup($privs[2])); - $session->close(); - if ($hasPrivs) { - return Apache2::Const::OK; - } - else { - return Apache2::Const::AUTH_REQUIRED; - } - } - } - return Apache2::Const::OK; - } + $request->push_handlers(PerlAccessHandler => sub { + my $path = $request->filename; + return Apache2::Const::NOT_FOUND + unless -e $path; + $path =~ s{[^/]*$}{}; + return Apache2::Const::OK + unless -e $path . '.wgaccess'; + + open my $FILE, '<' , $path . '.wgaccess'; + my $fileContents = do { local $/; <$FILE> }; + close($FILE); + my @users; + my @groups; + my @assets; + 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]; + push @groups, @privs[1,2]; + } else { - return Apache2::Const::NOT_FOUND; - } + my $privs = JSON->new->decode($fileContents); + @users = @{ $privs->{users} }; + @groups = @{ $privs->{groups} }; + @assets = @{ $privs->{assets} }; + } + + return Apache2::Const::OK + if grep { $_ eq '1' } @users; + + return Apache2::Const::OK + if grep { $_ eq '1' || $_ eq '7' } @groups; + + my $session = $request->pnotes('wgSession'); + unless (defined $session) { + $session = WebGUI::Session->open($config->getFilename, $request, $server); + } + + my $userId = $session->var->get('userId'); + + return Apache2::Const::OK + if grep { $_ eq $userId } @users; + + my $user = $session->user; + + return Apache2::Const::OK + if grep { $user->isInGroup($_) } @groups; + + return Apache2::Const::OK + if grep { WebGUI::Asset->new($session, $_)->canView } @assets; + + return Apache2::Const::AUTH_REQUIRED; } ); return Apache2::Const::OK; } diff --git a/lib/WebGUI/VersionTag.pm b/lib/WebGUI/VersionTag.pm index 15c3b35dd..4c451a00f 100644 --- a/lib/WebGUI/VersionTag.pm +++ b/lib/WebGUI/VersionTag.pm @@ -486,15 +486,15 @@ sub getWorking { #First see if there is already a version tag $tag = $stow->get(q{versionTag}); - return $tag if $tag; + return $tag if ($tag && !$tag->isLocked); $tagId = $session->scratch()->get(q{versionTag}); if ($tagId) { $tag = $class->new($session, $tagId); - - $stow->set(q{versionTag}, $tag); - - return $tag; + unless ($tag->isLocked) { + $stow->set(q{versionTag}, $tag); + return $tag; + } } #No tag found. Create or reclaim one? @@ -523,10 +523,10 @@ sub getWorking { # For now, we only reclaim if 1 tag open. if (scalar @openTags == 1) { $tag = $openTags[0]; - - $tag->setWorking(); - - return $tag; + unless ($tag->isLocked) { + $tag->setWorking(); + return $tag; + } } } elsif ($mode eq q{siteWide}) { @@ -534,7 +534,7 @@ sub getWorking { OPENTAG: foreach my $openTag (@{WebGUI::VersionTag->getOpenTags($session)}) { - if ($openTag->get(q{isSiteWide})) { + if ($openTag->get(q{isSiteWide}) && !$openTag->isLocked) { $tag = $openTag; @@ -563,6 +563,16 @@ sub getWorking { #------------------------------------------------------------------- +=head2 isLocked ( ) + +Returns boolean value indicating whether tag is locked + +=cut + +sub isLocked { $_[0]{_data}{isLocked} } + +#------------------------------------------------------------------- + =head2 leaveTag ( ) Make the user leave their current tag. @@ -782,6 +792,7 @@ Sets this tag as the working tag for the current user. sub setWorking { my $self = shift; + return if $self->isLocked; $self->session->scratch->set("versionTag",$self->getId); $self->session->stow->set("versionTag", $self); } diff --git a/lib/WebGUI/i18n/English/Asset_WikiPage.pm b/lib/WebGUI/i18n/English/Asset_WikiPage.pm index e49d21113..0c1663dbe 100644 --- a/lib/WebGUI/i18n/English/Asset_WikiPage.pm +++ b/lib/WebGUI/i18n/English/Asset_WikiPage.pm @@ -291,6 +291,24 @@ our $I18N = context => q{Help for template variable}, }, + 'keywordsLoop' => { + message => q{A loop containing all keywords for this page is tagged with.}, + lastUpdated => 0, + context => q{Help for template variable}, + }, + + 'keyword title' => { + message => q{The name of this keyword.}, + lastUpdated => 0, + context => q{Help for template variable}, + }, + + 'keyword url' => { + message => q{The URL to view all pages tagged with this keyword. The URL will have the gateway URL prepended to it.}, + lastUpdated => 0, + context => q{Help for template variable}, + }, + 'help owner' => { message => q{The username of the owner of the page}, lastUpdated => 0, @@ -309,12 +327,36 @@ our $I18N = context => 'Body text for help page', }, - 'isFeatured label' => { message => q{Feature this on the front page}, lastUpdated => 0, context => 'Label for asset property', }, + + 'isKeywordPage' => { + message => q{A boolean that is true if this page is a keyword page.}, + lastUpdated => 0, + context => 'template variable help', + }, + + 'keyword_page_loop' => { + message => q{If this page is a keyword page, then this loop will contain a list of all pages tagged with this page's keyword. The pagination variables will apply to the list of pages in this loop. If this page is not a keyword page, the loop will be blank, and the pagination variables will not be present.}, + lastUpdated => 0, + context => 'template variable help', + }, + + 'keyword page title' => { + message => q{The title of a page that has this keyword.}, + lastUpdated => 0, + context => 'template variable help', + }, + + 'keyword page url' => { + message => q{The URL to a page that has this keyword. The URL will have the gateway URL prepended to it.}, + lastUpdated => 0, + context => 'template variable help', + }, + }; 1; diff --git a/sbin/changeIobStatus.pl b/sbin/changeIobStatus.pl index 77c3ed9f1..2f5b97209 100755 --- a/sbin/changeIobStatus.pl +++ b/sbin/changeIobStatus.pl @@ -1,179 +1,179 @@ -#!/usr/bin/env perl - -#------------------------------------------------------------------- -# WebGUI is Copyright 2001-2009 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 -#------------------------------------------------------------------- - -use strict; -use Getopt::Long; -use Pod::Usage; -use WebGUI::Paths -inc; -use WebGUI::Session; -use WebGUI::User; -use WebGUI::Inbox; - -$|=1; - -my $configFile; -my $help; -my $quiet; -my $whatsHappening = "Automatically signed out."; -my $newStatus = "Out"; -my $currentStatus = "In"; -my $userMessage = "You were logged out of the In/Out Board automatically."; -my $userMessageFile; - - -GetOptions( - 'configfile=s'=>\$configFile, - 'help'=>\$help, - 'quiet'=>\$quiet, - 'whatsHappening:s'=>\$whatsHappening, - 'userMessage:s'=>\$userMessage, - 'userMessageFile:s'=>\$userMessageFile, - 'currentStatus:s'=>\$currentStatus, - 'newStatus:s'=>\$newStatus -); - -pod2usage( verbose => 2 ) if $help; -pod2usage() unless $configFile; - -print "Starting up...\n" unless ($quiet); -my $session = WebGUI::Session->open($configFile); - -if ($userMessageFile) { - print "Opening message file.." unless ($quiet); - if (open(FILE,"<".$userMessageFile)) { - print "OK\n" unless ($quiet); - my $contents; - while () { - $contents .= $_; - } - close(FILE); - if (length($contents) == 0) { - print "Message file empty, reverting to original message.\n"; - } else { - $userMessage = $contents; - } - } else { - print "Failed to open message file.\n"; - } -} - -print "Searching for users with a status of $currentStatus ...\n" unless ($quiet); -my $userList; -my $now = time(); -my $inbox = WebGUI::Inbox->new($session); -my $sth = $session->db->read("select userId,assetId from InOutBoard_status where status=?",[$currentStatus]); -while (my ($userId,$assetId) = $sth->array) { - my $user = WebGUI::User->new($session, $userId); - print "\tFound user ".$user->username."\n" unless ($quiet); - $userList .= $user->username." (".$userId.")\n"; - $session->db->write("update InOutBoard_status set dateStamp=?, message=?, status=? where userId=? and assetId=?",[$now, $whatsHappening, $newStatus, $userId, $assetId]); - $session->db->write("insert into InOutBoard_statusLog (userId, createdBy, dateStamp, message, status, assetId) values (?,?,?,?,?,?)", - [$userId,3,$now, $whatsHappening, $newStatus, $assetId]); - $inbox->addMessage({ - userId=>$userId, - subject=>"IOB Update", - message=>$userMessage - }); -} - -if (length($userList) > 0) { - print "Alerting admins of changes\n" unless ($quiet); - my $message = "The following users had their status changed:\n\n".$userList; - $inbox->addMessage({ - groupId=>3, - subject=>"IOB Update", - message=>$userMessage - }); -} - -print "Cleaning up..." unless ($quiet); -$session->var->end; -$session->close; -print "OK\n" unless ($quiet); - -__END__ - -=head1 NAME - -changeIobStatus - Automate WebGUI's InOut Board User status switching. - -=head1 SYNOPSIS - - changeIobStatus --configFile config.conf - [--currentStatus status] - [--newStatus status] - [--userMessage text|--userMessageFile pathname] - [--whatsHappening text] - [--quiet] - - changeIobStatus --help - -=head1 DESCRIPTION - -This WebGUI utility script helps you switch one or more user status -in the InOut Board (IOB). For instance, you might want to run it -from cron each night to automatically mark out all users that haven't -already marked out. - -=over - -=item B<--configFile config.conf> - -The WebGUI config file to use. Only the file name needs to be specified, -since it will be looked up inside WebGUI's configuration directory. -This parameter is required. - -=item B<--currentStatus status> - -Check users in the IOB having B status. If left unspecified, -it will default to C. - -=item B<--newStatus status> - -Change users status in the IOB to B status. If left unspecified, -it will default to C. - -=item B<--userMessage msg> - -Text of the message to be sent to the user after changing the status. -If left unspecified it will default to - - You were logged out of the In/Out Board automatically. - -=item B<--userMessageFile pathname> - -Pathname to a file whose contents will be sent to the user after changing -the status. Using this option overrides whatever messages is set -with B<--userMessage> (see above). - -=item B<--whatsHappening text> - -The message attached to the InOut Board when changing status. If left -unspecified it defaults to - - Automatically signed out. - -=item B<--quiet> - -Disable all output unless there's an error. - -=item B<--help> - -Shows this documentation, then exits. - -=back - -=head1 AUTHOR - -Copyright 2001-2009 Plain Black Corporation. - -=cut +#!/usr/bin/env perl + +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2009 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 +#------------------------------------------------------------------- + +use strict; +use WebGUI::Paths -inc; +use Getopt::Long; +use Pod::Usage; +use WebGUI::Session; +use WebGUI::User; +use WebGUI::Inbox; + +$|=1; + +my $configFile; +my $help; +my $quiet; +my $whatsHappening = "Automatically signed out."; +my $newStatus = "Out"; +my $currentStatus = "In"; +my $userMessage = "You were logged out of the In/Out Board automatically."; +my $userMessageFile; + + +GetOptions( + 'configfile=s'=>\$configFile, + 'help'=>\$help, + 'quiet'=>\$quiet, + 'whatsHappening:s'=>\$whatsHappening, + 'userMessage:s'=>\$userMessage, + 'userMessageFile:s'=>\$userMessageFile, + 'currentStatus:s'=>\$currentStatus, + 'newStatus:s'=>\$newStatus +); + +pod2usage( verbose => 2 ) if $help; +pod2usage() unless $configFile; + +print "Starting up...\n" unless ($quiet); +my $session = WebGUI::Session->open($webguiRoot,$configFile); + +if ($userMessageFile) { + print "Opening message file.." unless ($quiet); + if (open(FILE,"<".$userMessageFile)) { + print "OK\n" unless ($quiet); + my $contents; + while () { + $contents .= $_; + } + close(FILE); + if (length($contents) == 0) { + print "Message file empty, reverting to original message.\n"; + } else { + $userMessage = $contents; + } + } else { + print "Failed to open message file.\n"; + } +} + +print "Searching for users with a status of $currentStatus ...\n" unless ($quiet); +my $userList; +my $now = time(); +my $inbox = WebGUI::Inbox->new($session); +my $sth = $session->db->read("select userId,assetId from InOutBoard_status where status=?",[$currentStatus]); +while (my ($userId,$assetId) = $sth->array) { + my $user = WebGUI::User->new($session, $userId); + print "\tFound user ".$user->username."\n" unless ($quiet); + $userList .= $user->username." (".$userId.")\n"; + $session->db->write("update InOutBoard_status set dateStamp=?, message=?, status=? where userId=? and assetId=?",[$now, $whatsHappening, $newStatus, $userId, $assetId]); + $session->db->write("insert into InOutBoard_statusLog (userId, createdBy, dateStamp, message, status, assetId) values (?,?,?,?,?,?)", + [$userId,3,$now, $whatsHappening, $newStatus, $assetId]); + $inbox->addMessage({ + userId=>$userId, + subject=>"IOB Update", + message=>$userMessage + }); +} + +if (length($userList) > 0) { + print "Alerting admins of changes\n" unless ($quiet); + my $message = "The following users had their status changed:\n\n".$userList; + $inbox->addMessage({ + groupId=>3, + subject=>"IOB Update", + message=>$userMessage + }); +} + +print "Cleaning up..." unless ($quiet); +$session->var->end; +$session->close; +print "OK\n" unless ($quiet); + +__END__ + +=head1 NAME + +changeIobStatus - Automate WebGUI's InOut Board User status switching. + +=head1 SYNOPSIS + + changeIobStatus --configFile config.conf + [--currentStatus status] + [--newStatus status] + [--userMessage text|--userMessageFile pathname] + [--whatsHappening text] + [--quiet] + + changeIobStatus --help + +=head1 DESCRIPTION + +This WebGUI utility script helps you switch one or more user status +in the InOut Board (IOB). For instance, you might want to run it +from cron each night to automatically mark out all users that haven't +already marked out. + +=over + +=item B<--configFile config.conf> + +The WebGUI config file to use. Only the file name needs to be specified, +since it will be looked up inside WebGUI's configuration directory. +This parameter is required. + +=item B<--currentStatus status> + +Check users in the IOB having B status. If left unspecified, +it will default to C. + +=item B<--newStatus status> + +Change users status in the IOB to B status. If left unspecified, +it will default to C. + +=item B<--userMessage msg> + +Text of the message to be sent to the user after changing the status. +If left unspecified it will default to + + You were logged out of the In/Out Board automatically. + +=item B<--userMessageFile pathname> + +Pathname to a file whose contents will be sent to the user after changing +the status. Using this option overrides whatever messages is set +with B<--userMessage> (see above). + +=item B<--whatsHappening text> + +The message attached to the InOut Board when changing status. If left +unspecified it defaults to + + Automatically signed out. + +=item B<--quiet> + +Disable all output unless there's an error. + +=item B<--help> + +Shows this documentation, then exits. + +=back + +=head1 AUTHOR + +Copyright 2001-2009 Plain Black Corporation. + +=cut diff --git a/sbin/fileImport.pl b/sbin/fileImport.pl index 4300e5bf7..e71dfc5ae 100755 --- a/sbin/fileImport.pl +++ b/sbin/fileImport.pl @@ -11,8 +11,6 @@ #------------------------------------------------------------------- use strict; - - use File::Path; use File::stat; use FileHandle; diff --git a/sbin/galleryImport.pl b/sbin/galleryImport.pl index 5d1321a74..9f4b7bbec 100755 --- a/sbin/galleryImport.pl +++ b/sbin/galleryImport.pl @@ -11,6 +11,16 @@ # ------------------------------------------------------------------- use strict; +use File::Basename (); +use File::Spec; + +my $webguiRoot; +BEGIN { + $webguiRoot = File::Spec->rel2abs(File::Spec->catdir(File::Basename::dirname(__FILE__), File::Spec->updir)); + unshift @INC, File::Spec->catdir($webguiRoot, 'lib'); +} + +$|=1; use Carp qw( carp croak ); use File::Find; use Getopt::Long; diff --git a/sbin/installClass.pl b/sbin/installClass.pl index 58cbc000d..11b94d966 100755 --- a/sbin/installClass.pl +++ b/sbin/installClass.pl @@ -12,6 +12,15 @@ #------------------------------------------------------------------- use strict; +use File::Basename (); +use File::Spec; + +my $webguiRoot; +BEGIN { + $webguiRoot = File::Spec->rel2abs(File::Spec->catdir(File::Basename::dirname(__FILE__), File::Spec->updir)); + unshift @INC, File::Spec->catdir($webguiRoot, 'lib'); +} + use Getopt::Long; use Pod::Usage; use WebGUI::Paths -inc; diff --git a/sbin/maintenanceMode.pl b/sbin/maintenanceMode.pl index 72053a221..3fef97df1 100755 --- a/sbin/maintenanceMode.pl +++ b/sbin/maintenanceMode.pl @@ -10,7 +10,6 @@ # http://www.plainblack.com info@plainblack.com #------------------------------------------------------------------- - use strict; use Getopt::Long; use Pod::Usage; diff --git a/sbin/testEnvironment.pl b/sbin/testEnvironment.pl index 636856a92..7a4dc6868 100755 --- a/sbin/testEnvironment.pl +++ b/sbin/testEnvironment.pl @@ -10,15 +10,16 @@ # http://www.plainblack.com info@plainblack.com #------------------------------------------------------------------- +use strict; +use File::Basename (); +use File::Spec; -our $webguiRoot; - +my $webguiRoot; BEGIN { - $webguiRoot = ".."; - unshift (@INC, $webguiRoot."/lib"); + $webguiRoot = File::Spec->rel2abs(File::Spec->catdir(File::Basename::dirname(__FILE__), File::Spec->updir)); + unshift @INC, File::Spec->catdir($webguiRoot, 'lib'); } -use strict; use CPAN; use Getopt::Long; use Pod::Usage; @@ -65,7 +66,7 @@ checkModule("HTTP::Request", 1.40 ); checkModule("HTTP::Headers", 1.61 ); checkModule("Test::More", 0.82, 2 ); checkModule("Test::MockObject", 1.02, 2 ); -checkModule("Test::Deep", 0.095, 2 ); +checkModule("Test::Deep", 0.095, ); checkModule("Test::Exception", 0.27, 2 ); checkModule("Test::Class", 0.31, 2 ); checkModule("Pod::Coverage", 0.19, 2 ); diff --git a/sbin/thumbnailer.pl b/sbin/thumbnailer.pl index 303a0b5a9..4fe33e77c 100755 --- a/sbin/thumbnailer.pl +++ b/sbin/thumbnailer.pl @@ -15,6 +15,7 @@ # thumbnails. #----------------------------------------- +use strict; use File::stat; use File::Find (); use Getopt::Long; diff --git a/t/Asset/WikiPage.t b/t/Asset/WikiPage.t index 85b923bda..3a92d7e00 100644 --- a/t/Asset/WikiPage.t +++ b/t/Asset/WikiPage.t @@ -16,7 +16,8 @@ use lib "$FindBin::Bin/../lib"; use WebGUI::Test; use WebGUI::Session; -use Test::More tests => 17; # increment this value for each test you create +use Test::More tests => 29; # increment this value for each test you create +use Test::Deep; use WebGUI::Asset::Wobject::WikiMaster; use WebGUI::Asset::WikiPage; @@ -27,12 +28,12 @@ my $versionTag = WebGUI::VersionTag->getWorking($session); $versionTag->set({name=>"Wiki Test"}); addToCleanup($versionTag); -my $wiki = $node->addChild({className=>'WebGUI::Asset::Wobject::WikiMaster'}); +my $wiki = $node->addChild({className=>'WebGUI::Asset::Wobject::WikiMaster', title => 'Wiki Test', url => 'wikitest'}); +my @autoCommitCoda = (undef, undef, {skipAutoCommitWorkflows => 1, skipNotification => 1}); $versionTag->commit; my $wikipage = $wiki->addChild( {className=>'WebGUI::Asset::WikiPage'}, - undef, undef, - {skipAutoCommitWorkflows => 1, skipNotification => 1} + @autoCommitCoda, ); # Wikis create and autocommit a version tag when a child is added. Lets get the name so we can roll it back. @@ -90,3 +91,55 @@ $comments = $wikipage->get('comments'); is($comments->[0]{comment}, $secondComment, "you can delete a comment"); is($wikipage->get('averageCommentRating'), 1, 'average rating is adjusted after deleting a comment'); + +################## +# This section tests hierarchical keywords support +################## + +# +## setup some more wiki pages +my $properties = { + className=>'WebGUI::Asset::WikiPage', + content => 'Now is the time for all good men to come to the aid of their country', + title => 'Keyword', + keywords => 'keyword' +}; +my $wikipage2 = $wiki->addChild($properties, @autoCommitCoda); +isa_ok($wikipage2, 'WebGUI::Asset::WikiPage'); + +$properties = { + className=>'WebGUI::Asset::WikiPage', + content => 'The quick brown fox jumps over the lazy dog.', + title => 'Fox', + keywords => 'keyword' +}; +my $wikipage3 = $wiki->addChild($properties, @autoCommitCoda); +isa_ok($wikipage3, 'WebGUI::Asset::WikiPage'); + +# Test keywords support +my $keywords = $wikipage2->get('keywords'); +is($keywords,$properties->{'keywords'}, 'Keywords match'); + +# Test isKeywordPage() +ok $wikipage2->isKeywordPage(), "'".$wikipage2->get('title')."' is a keyword page"; +my $templateVars = $wikipage2->getTemplateVars; +ok $templateVars->{isKeywordPage}, 'isKeywordPage template var, true'; +cmp_deeply + $templateVars->{keyword_page_loop}, + [ + { title => 'Fox', url => '/wikitest/fox', }, + ], + 'populated keyword_page_loop, sorted by title'; +ok ! $wikipage3->isKeywordPage(), "'".$wikipage3->get('title')."' is not a keyword page"; +$templateVars = $wikipage3->getTemplateVars; +ok ! $templateVars->{isKeywordPage}, 'isKeywordPage template var, false'; +cmp_deeply $templateVars->{keyword_page_loop}, [], 'empty keyword_page_loop'; + +$wikipage3->update({keywords => $wikipage3->get('keywords').',Fox'}); +ok $wikipage3->isKeywordPage(), "'".$wikipage3->get('title')."' is now a keyword page"; +$templateVars = $wikipage3->getTemplateVars; +ok $templateVars->{isKeywordPage}, 'isKeywordPage template var, false'; +cmp_deeply + $templateVars->{keyword_page_loop}, + [ ], + 'empty keyword_page_loop, self is not put into the loop'; diff --git a/t/Asset/Wobject/WikiMaster/featured.t b/t/Asset/Wobject/WikiMaster/featured.t index c070bfb44..ef0d98bab 100644 --- a/t/Asset/Wobject/WikiMaster/featured.t +++ b/t/Asset/Wobject/WikiMaster/featured.t @@ -69,9 +69,5 @@ cmp_deeply( "appendFeaturedPageVars returns correct variables, prefixed with 'featured_'", ); -#---------------------------------------------------------------------------- -# Cleanup -END { -} #vim:ft=perl diff --git a/t/Macro/PageUrl.t b/t/Macro/PageUrl.t index dd6853b64..97d9cb4df 100644 --- a/t/Macro/PageUrl.t +++ b/t/Macro/PageUrl.t @@ -65,7 +65,3 @@ $output = WebGUI::Macro::PageUrl::process($session, '/sub/page', 'query=this'); like($output, qr{/sub/page\?noCache=\d+:\d+;query=this$}, 'checking that the query arg works with preventProxyCache'); } - -END { - # See note in the Slash_gateway macro test about this. -} diff --git a/t/Storage.t b/t/Storage.t index 5264622a1..37c726f9a 100644 --- a/t/Storage.t +++ b/t/Storage.t @@ -32,7 +32,7 @@ my $cwd = Cwd::cwd(); my ($extensionTests, $fileIconTests) = setupDataDrivenTests($session); -my $numTests = 134; # increment this value for each test you create +my $numTests = 136; # increment this value for each test you create plan tests => $numTests + scalar @{ $extensionTests } + scalar @{ $fileIconTests }; my $uploadDir = $session->config->get('uploadsPath'); @@ -508,7 +508,7 @@ my $shallowDir = $shallowStorage->getPathClassDir(); ok(-e $shallowDir->file('.wgaccess')->stringify, 'setPrivilege: .wgaccess file created in shallow storage'); my $privs; $privs = $shallowStorage->getFileContentsAsScalar('.wgaccess'); -is ($privs, "3\n3\n3", '... correct group contents'); +is ($privs, '{"assets":[],"groups":["3","3"],"users":["3"]}', '... correct group contents'); $shallowStorage->deleteFile('.wgaccess'); my $deepStorage = WebGUI::Storage->create($session); @@ -524,9 +524,21 @@ ok(-e $deepDir->file('.wgaccess')->stringify, '.wgaccess file created in dee ok(-e $deepDeepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage subdir'); $privs = $deepStorage->getFileContentsAsScalar('.wgaccess'); -is ($privs, "3\n3\n3", '... correct group contents, deep storage'); +is ($privs, '{"assets":[],"groups":["3","3"],"users":["3"]}', '... correct group contents, deep storage'); $privs = $deepStorage->getFileContentsAsScalar('deep/.wgaccess'); -is ($privs, "3\n3\n3", '... correct group contents, deep storage subdir'); +is ($privs, '{"assets":[],"groups":["3","3"],"users":["3"]}', '... correct group contents, deep storage subdir'); + +{ + my $storage = WebGUI::Storage->create($session); + addToCleanup($storage); + my $asset = WebGUI::Asset->getRoot($session); + $storage->setPrivileges( $asset ); + my $accessFile = $storage->getPathClassDir->file('.wgaccess'); + ok(-e $accessFile, 'setPrivilege: .wgaccess file created for asset permissions'); + my $privs = $accessFile->slurp; + is ($privs, '{"assets":["' . $asset->getId . '"],"groups":[],"users":[]}', '... correct asset contents'); +} + #################################################### # diff --git a/t/VersionTag.t b/t/VersionTag.t index 95e8b305f..389d5f620 100644 --- a/t/VersionTag.t +++ b/t/VersionTag.t @@ -14,7 +14,7 @@ use lib "$FindBin::Bin/lib"; use WebGUI::Test; use WebGUI::Session; use WebGUI::VersionTag; -use Test::More tests => 74; # increment this value for each test you create +use Test::More tests => 81; # increment this value for each test you create my $session = WebGUI::Test->session; @@ -105,14 +105,36 @@ $tag->clearWorking; ok(!defined getWorking(1), 'working tag unset'); ok(!scalar $tag->get('isLocked'), 'tag is initially unlocked'); +ok(!$tag->isLocked,'accessor for isLocked works on false'); $tag->lock; ok(scalar $tag->get('isLocked'), 'tag is locked'); +ok($tag->isLocked, 'accessor for isLocked works on true'); ok_open($tag->getId, 0, 'locked tag'); $tag->unlock; ok(!scalar $tag->get('isLocked'), 'tag is again unlocked'); ok_open($tag->getId, 1, 'unlocked tag'); -# TODO: test interaction between lock/unlock and working tags +# test interaction between lock/unlock and working tags +my $locker = WebGUI::VersionTag->create($session); +$locker->setWorking(); +is getWorking(1), $locker, 'working tag is the one we are about to lock'; + +$locker->lock(); +ok !defined getWorking(1), 'lock clears working'; + +my $unlocked = WebGUI::VersionTag->create($session); +$unlocked->setWorking(); +is getWorking(1), $unlocked, 'working tag is fresh'; +$locker->setWorking(); +is getWorking(1), $unlocked, 'setWorking on locked tag does nothing'; +$unlocked->clearWorking; +$unlocked->rollback; + +$session->stow->set(versionTag => $locker); +$session->scratch->set(versionTag => $locker->getId); +isnt getWorking(1), $locker, 'getWorking never returns locked tag'; +$locker->clearWorking; +$locker->rollback; my $tagAgain1 = WebGUI::VersionTag->new($session, $tag->getId); isa_ok($tagAgain1, 'WebGUI::VersionTag', 'tag retrieved again while valid');