Merge commit '63865eb39f' into WebGUI8. up to 7.9.11

This commit is contained in:
Colin Kuskie 2010-08-13 11:52:08 -07:00
commit 7b218942b3
72 changed files with 3085 additions and 407 deletions

View file

@ -1,4 +1,21 @@
7.9.11
- fixed #11755: New cart does not update shipping methods correctly
- fixed #11757: Update the USPS International driver for new country names
- fixed #11753: PayPal Plugin - Shipping not factored into total in paypal
- fixed #11588: CMSmatrix - Comparing certain products ends in data errors
- fixed #11765: WebGUI/Asset/Wobject/Navigation.pm still uses obsolete PBtmpl0000000000000048
- fixed #11766: Userlist problem / WebGUI 7.8.24
- fixed #11759: email template missing
- fixed #11769: WebGUI::Asset::File::ZipArchive specifies a default template of ''
- fixed #11758: formatting on account stuff is wrong
- fixed #11770: Starter needs to set all account plugins
- fixed #11771: Default Newsletter template not set
- fixed #11432: DataTable date input
- fixed #11772: Metadata in Post doesn't set default value correctly
- fixed #11768: Edit Branch does not update File wgaccess permissions
- added Asset Report Asset allowing creation of reports based on Asset Properties.
- fixed #11773: Pluggable allows arbitrary module loading
- fixed #11774: UserList SQL injection
7.9.10
- fixed #11721: spamStopWords not in WebGUI.conf.original
@ -8,6 +25,8 @@
- fixed #11742: linktag FilePump macro not xhtml valid
- fixed #11744: Default DataForm list template does not contain pagination
- fixed #11683: URL with UTF8 (for äÄöÖüÜß)
- added option for sort order of Alphabetically on title to StoryArchive, StoryTopic and Keyword
- fixed #11747: Empty StoryTopics throw a fatal error when viewed
7.9.9
- fixed #11693: Shopping cart does not show for visitor user

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,529 @@
#!/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
#-------------------------------------------------------------------
our ($webguiRoot);
BEGIN {
$webguiRoot = "../..";
unshift (@INC, $webguiRoot."/lib");
}
use strict;
use Getopt::Long;
use WebGUI::Session;
use WebGUI::Storage;
use WebGUI::Asset;
use WebGUI::Asset::WikiPage;
use WebGUI::Shop::AddressBook;
use WebGUI::Shop::Pay;
use WebGUI::Workflow;
use WebGUI::Utility;
my $toVersion = "7.9.11"; # make this match what version you're going to
my $quiet; # this line required
my $session = start(); # this line required
# upgrade functions go here
##7.9.1-.2
addSortItemsSCColumn($session);
addExtensionWorkflow($session);
##7.9.2-.3
reindexSiteForDefaultSynopsis( $session );
addTopLevelWikiKeywords( $session );
##7.9.3-.4
addWikiSubKeywords($session);
addSynopsistoEachWikiPage($session);
dropVisitorAddressBooks($session);
alterCartTable($session);
alterAddressBookTable($session);
addWizardHandler( $session );
addTemplateExampleImage( $session );
addPayDriverTemplates( $session );
##7.9.4-.5
modifySortItems( $session );
addRejectNoticeSetting($session);
installNewCSUnsubscribeTemplate($session);
##7.9.5-.6
addIndexForInbox($session);
##7.9.7-.8
addTwitterAuth( $session );
##7.9.8-.9
migrateAttachmentsToJson( $session );
##7.9.9-.10
alterStoryArchiveTable($session);
##7.9.10-.11
alterStoryTopicTable($session);
addAssetReport($session);
finish($session); # this line required
#----------------------------------------------------------------------------
# Describe what our function does
#sub exampleFunction {
# my $session = shift;
# print "\tWe're doing some stuff here that you should know about... " unless $quiet;
# # and here's our code
# print "DONE!\n" unless $quiet;
#}
#----------------------------------------------------------------------------
sub addExtensionWorkflow {
print "\tAdding calendar event extension to weekly maintenence..."
unless $quiet;
my $workflow = WebGUI::Workflow->new($session, 'pbworkflow000000000002');
my $activity = $workflow->addActivity('WebGUI::Workflow::Activity::ExtendCalendarRecurrences');
$activity->set(title => 'Extend Calendar Recurrences');
$activity->set(description => 'Create events for live recurrences up to two years from the current date');
print "Done\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addSortItemsSCColumn {
my $session = shift;
print "\tAdding sort items switch to Syndicated Content... " unless $quiet;
my $sth = $session->db->read('DESCRIBE `SyndicatedContent`');
while (my ($col) = $sth->array) {
if ($col eq 'sortItems') {
print "Skipped.\n" unless $quiet;
return;
}
}
$session->db->write('ALTER TABLE SyndicatedContent ADD COLUMN sortItems BOOL DEFAULT 1');
print "Done.\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addTopLevelWikiKeywords {
my $session = shift;
print "\tAdding top level keywords page to WikiMaster... " unless $quiet;
my $sth = $session->db->read('DESCRIBE `WikiMaster`');
while (my ($col) = $sth->array) {
if ($col eq 'topLevelKeywords') {
print "Skipped.\n" unless $quiet;
return;
}
}
$session->db->write('ALTER TABLE WikiMaster ADD COLUMN topLevelKeywords LONGTEXT');
print "Done.\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Reindex the site to clear out default synopsis
sub reindexSiteForDefaultSynopsis {
my $session = shift;
print "\tRe-indexing site to clear out default synopses... " unless $quiet;
my $rs = $session->db->read("select assetId, className from asset where state='published'");
my @searchableAssetIds;
while (my ($id, $class) = $rs->array) {
my $asset = WebGUI::Asset->new($session,$id,$class);
if (defined $asset && $asset->get("state") eq "published" && ($asset->get("status") eq "approved" || $asset->get("status") eq "archived")) {
$asset->indexContent;
push (@searchableAssetIds, $id);
}
}
# delete indexes of assets that are no longer searchable
my $list = $session->db->quoteAndJoin(\@searchableAssetIds) if scalar(@searchableAssetIds);
$session->db->write("delete from assetIndex where assetId not in (".$list.")") if $list;
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Add example images to templates
sub addTemplateExampleImage {
my $session = shift;
print "\tAdding example image field to template... " unless $quiet;
$session->db->write( q{
ALTER TABLE template ADD storageIdExample CHAR(22)
} );
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addWizardHandler {
my ( $sesssion ) = @_;
print "\tAdding WebGUI::Wizard... " unless $quiet;
if ( !grep { $_ eq 'WebGUI::Content::Wizard' } @{$session->config->get('contentHandlers')} ) {
# Find the place of Operation and add before
my @handlers = ();
for my $handler ( @{$session->config->get('contentHandlers')} ) {
if ( $handler eq 'WebGUI::Content::Operation' ) {
push @handlers, 'WebGUI::Content::Wizard';
}
push @handlers, $handler;
}
$session->config->set('contentHandlers',\@handlers);
}
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addWikiSubKeywords {
my $session = shift;
print "\tAdd the WikiMaster sub-keywords table... " unless $quiet;
# and here's our code
$session->db->write(<<EOSQL);
CREATE TABLE IF NOT EXISTS WikiMasterKeywords (
assetId CHAR(22) binary not null,
keyword CHAR(64) not null,
subKeyword CHAR(64),
PRIMARY KEY (`assetId`,`keyword`, `subKeyword`),
KEY `assetId` (`assetId`),
KEY `keyword` (`keyword`),
KEY `subKeyword` (`subKeyword`)
)
EOSQL
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addSynopsistoEachWikiPage {
my $session = shift;
print "\tAdd a synopsis to each wiki page this may take a while... " unless $quiet;
my $pager = WebGUI::Asset::WikiPage->getIsa($session);
PAGE: while (1) {
my $page = eval {$pager->()};
next PAGE if Exception::Class->caught();
last PAGE unless $page;
my ($synopsis) = $page->getSynopsisAndContent(undef, $page->get('content'));
$page->update({synopsis => $synopsis});
}
# and here's our code
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub dropVisitorAddressBooks {
my $session = shift;
print "\tDrop AddressBooks owned by Visitor... " unless $quiet;
my $sth = $session->db->read(q|SELECT addressBookId FROM addressBook where userId='1'|);
BOOK: while (my ($addressBookId) = $sth->array) {
my $book = eval { WebGUI::Shop::AddressBook->new($session, $addressBookId); };
next BOOK if Exception::Class->caught();
$book->delete;
}
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub alterAddressBookTable {
my $session = shift;
print "\tDrop sessionId from the Address Book database table... " unless $quiet;
# and here's our code
$session->db->write("ALTER TABLE addressBook DROP COLUMN sessionId");
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub alterCartTable {
my $session = shift;
print "\tAdd billing address column to the Cart table... " unless $quiet;
# and here's our code
$session->db->write("ALTER TABLE cart ADD COLUMN billingAddressId CHAR(22)");
$session->db->write("ALTER TABLE cart ADD COLUMN gatewayId CHAR(22)");
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addPayDriverTemplates {
my $session = shift;
print "\tAdd templates to the Payment Drivers that need them... " unless $quiet;
# and here's our code
my $pay = WebGUI::Shop::Pay->new($session);
my @gateways = @{ $pay->getPaymentGateways };
GATEWAY: foreach my $gateway (@gateways) {
next GATEWAY unless $gateway;
my $properties = $gateway->get;
if ($gateway->isa('WebGUI::Shop::PayDriver::Cash')) {
$properties->{summaryTemplateId} = '30h5rHxzE_Q0CyI3Gg7EJw';
}
elsif ($gateway->isa('WebGUI::Shop::PayDriver::ITransact')) {
##Nothing to do. This template was only changed, not added.
}
elsif ($gateway->isa('WebGUI::Shop::PayDriver::Ogone')) {
$properties->{summaryTemplateId} = 'jysVZeUR0Bx2NfrKs5sulg';
}
elsif ($gateway->isa('WebGUI::Shop::PayDriver::PayPal::PayPalStd')) {
$properties->{summaryTemplateId} = '300AozDaeveAjB_KN0ljlQ';
}
elsif ($gateway->isa('WebGUI::Shop::PayDriver::PayPal::ExpressCheckout')) {
$properties->{summaryTemplateId} = 'GqnZPB0gLoZmqQzYFaq7bg';
}
else {
die "Unknown payment driver type found. Unable to automatically upgrade.\n";
}
$gateway->update($properties);
}
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Changes sortItems to a SelectBox
sub modifySortItems {
my $session = shift;
print "\tUpdating SyndicatedContent...\n" unless $quiet;
require WebGUI::Form::SelectBox;
print "\t\tModifying table...\n" unless $quiet;
my $type = WebGUI::Form::SelectBox->getDatabaseFieldType;
$session->db->write("ALTER TABLE SyndicatedContent MODIFY sortItems $type");
print "\t\tConverting old values..." unless $quiet;
$session->db->write(q{
UPDATE SyndicatedContent
SET sortItems = 'none'
WHERE sortItems <> '1'
});
$session->db->write(q{
UPDATE SyndicatedContent
SET sortItems = 'pubDate_des'
WHERE sortItems = '1'
});
# and here's our code
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Adds setting which allows users to set whether or not to send reject notices
sub addRejectNoticeSetting {
my $session = shift;
print "\tAdding reject notice setting... " unless $quiet;
$session->setting->add('sendRejectNotice',1);
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub installNewCSUnsubscribeTemplate {
my $session = shift;
print "\tAdding new unsubscribe template to the CS... " unless $quiet;
$session->db->write(q|ALTER TABLE Collaboration ADD COLUMN unsubscribeTemplateId CHAR(22) NOT NULL|);
$session->db->write(q|UPDATE Collaboration set unsubscribeTemplateId='default_CS_unsubscribe'|);
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Add keys and indicies to groupGroupings to help speed up group queries
sub addIndexForInbox {
my $session = shift;
print "\tAdding index to inbox_messageState... " unless $quiet;
my $sth = $session->db->read('show create table inbox_messageState');
my ($field,$stmt) = $sth->array;
$sth->finish;
unless ($stmt =~ m/KEY `userId_deleted_isRead`/i) {
$session->db->write("alter table inbox_messageState add index userId_deleted_isRead (userId,deleted,isRead)");
}
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Add twitter auth and macro
sub addTwitterAuth {
my $session = shift;
print "\tAdding twitter auth method... " unless $quiet;
$session->config->addToArray( 'authMethods', 'Twitter' );
$session->config->addToHash( 'macros', "TwitterLogin" => "TwitterLogin" );
$session->setting->set( 'twitterEnabled', 0 );
$session->setting->set( 'twitterTemplateIdChooseUsername', 'mfHGkp6t9gdclmzN33OEnw' );
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Move Template attachments to JSON collateral
sub migrateAttachmentsToJson {
my $session = shift;
print "\tMoving template attachments to JSON... " unless $quiet;
# and here's our code
$session->db->write(
"ALTER TABLE template ADD attachmentsJson LONGTEXT"
);
my $attach; # hashref (template) of hashrefs (revisionDate)
# of arrayrefs (attachments) of hashrefs (attachment)
my $sth = $session->db->read( "SELECT * FROM template_attachments" );
while ( my $row = $sth->hashRef ) {
push @{ $attach->{ $row->{templateId} }{ $row->{revisionDate} } }, {
url => $row->{url},
type => $row->{type},
};
}
for my $templateId ( keys %{ $attach } ) {
for my $revisionDate ( keys %{ $attach->{$templateId} } ) {
my $data = $attach->{$templateId}{$revisionDate};
my $asset = WebGUI::Asset->newByDynamicClass( $session, $templateId, $revisionDate );
$asset->update({ attachmentsJson => JSON->new->encode( $data ) });
}
}
$session->db->write(
"DROP TABLE template_attachments"
);
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Describe what our function does
sub alterStoryArchiveTable {
my $session = shift;
print "\tAdd story sort order column to the StoryAcrhive table... " unless $quiet;
my $sth = $session->db->read('DESCRIBE `StoryArchive`');
while (my ($col) = $sth->array) {
if ($col eq 'storySortOrder') {
print "Skipped.\n" unless $quiet;
return;
}
}
$session->db->write("ALTER TABLE StoryArchive ADD COLUMN storySortOrder CHAR(22)");
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Describe what our function does
sub alterStoryTopicTable {
my $session = shift;
print "\tAdd story sort order column to the StoryTopic table... " unless $quiet;
my $sth = $session->db->read('DESCRIBE `StoryTopic`');
while (my ($col) = $sth->array) {
if ($col eq 'storySortOrder') {
print "Skipped.\n" unless $quiet;
return;
}
}
$session->db->write("ALTER TABLE StoryTopic ADD COLUMN storySortOrder CHAR(22)");
$session->db->write("UPDATE StoryTopic SET storySortOrder = 'Chronologically' WHERE storySortOrder IS NULL");
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Describe what our function does
sub addAssetReport {
my $session = shift;
print "\tAdding Asset Report Asset ... " unless $quiet;
#Add the database table
$session->db->write(q{
CREATE TABLE `AssetReport` (
`assetId` char(22) character set utf8 collate utf8_bin NOT NULL,
`revisionDate` bigint(20) NOT NULL,
`settings` mediumtext,
`templateId` char(22) character set utf8 collate utf8_bin default NULL,
`paginateAfter` bigint(20) default NULL,
PRIMARY KEY (`assetId`,`revisionDate`)
)
});
#Add the asset to the config file
$session->config->addToHash( "assets", "WebGUI::Asset::Wobject::AssetReport", { category => "utilities" } );
print "DONE!\n" unless $quiet;
}
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
#----------------------------------------------------------------------------
# Add a package to the import node
sub addPackage {
my $session = shift;
my $file = shift;
# Make a storage location for the package
my $storage = WebGUI::Storage->createTemp( $session );
$storage->addFileFromFilesystem( $file );
# Import the package into the import node
my $package = eval {
my $node = WebGUI::Asset->getImportNode($session);
$node->importPackage( $storage, {
overwriteLatest => 1,
clearPackageFlag => 1,
setDefaultTemplate => 1,
} );
};
if ($package eq 'corrupt') {
die "Corrupt package found in $file. Stopping upgrade.\n";
}
if ($@ || !defined $package) {
die "Error during package import on $file: $@\nStopping upgrade\n.";
}
return;
}
#-------------------------------------------------
sub start {
my $configFile;
$|=1; #disable output buffering
GetOptions(
'configFile=s'=>\$configFile,
'quiet'=>\$quiet
);
my $session = WebGUI::Session->open($webguiRoot,$configFile);
$session->user({userId=>3});
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->set({name=>"Upgrade to ".$toVersion});
return $session;
}
#-------------------------------------------------
sub finish {
my $session = shift;
updateTemplates($session);
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->commit;
$session->db->write("insert into webguiVersion values (".$session->db->quote($toVersion).",'upgrade',".time().")");
$session->close();
}
#-------------------------------------------------
sub updateTemplates {
my $session = shift;
print "\tUpdating packages.\n" unless ($quiet);
addPackage( $session, 'packages-7.8.24-7.9.11/merged.wgpkg' );
}
#vim:ft=perl

View file

@ -1,123 +0,0 @@
#!/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
#-------------------------------------------------------------------
our ($webguiRoot);
BEGIN {
$webguiRoot = "../..";
unshift (@INC, $webguiRoot."/lib");
}
use strict;
use Getopt::Long;
use WebGUI::Session;
use WebGUI::Storage;
use WebGUI::Asset;
my $toVersion = '7.9.11';
my $quiet; # this line required
my $session = start(); # this line required
# upgrade functions go here
finish($session); # this line required
#----------------------------------------------------------------------------
# Describe what our function does
#sub exampleFunction {
# my $session = shift;
# print "\tWe're doing some stuff here that you should know about... " unless $quiet;
# # and here's our code
# print "DONE!\n" unless $quiet;
#}
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
#----------------------------------------------------------------------------
# Add a package to the import node
sub addPackage {
my $session = shift;
my $file = shift;
print "\tUpgrading package $file\n" unless $quiet;
# Make a storage location for the package
my $storage = WebGUI::Storage->createTemp( $session );
$storage->addFileFromFilesystem( $file );
# Import the package into the import node
my $package = eval {
my $node = WebGUI::Asset->getImportNode($session);
$node->importPackage( $storage, {
overwriteLatest => 1,
clearPackageFlag => 1,
setDefaultTemplate => 1,
} );
};
if ($package eq 'corrupt') {
die "Corrupt package found in $file. Stopping upgrade.\n";
}
if ($@ || !defined $package) {
die "Error during package import on $file: $@\nStopping upgrade\n.";
}
return;
}
#-------------------------------------------------
sub start {
my $configFile;
$|=1; #disable output buffering
GetOptions(
'configFile=s'=>\$configFile,
'quiet'=>\$quiet
);
my $session = WebGUI::Session->open($webguiRoot,$configFile);
$session->user({userId=>3});
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->set({name=>"Upgrade to ".$toVersion});
return $session;
}
#-------------------------------------------------
sub finish {
my $session = shift;
updateTemplates($session);
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->commit;
$session->db->write("insert into webguiVersion values (".$session->db->quote($toVersion).",'upgrade',".time().")");
$session->close();
}
#-------------------------------------------------
sub updateTemplates {
my $session = shift;
return undef unless (-d "packages-".$toVersion);
print "\tUpdating packages.\n" unless ($quiet);
opendir(DIR,"packages-".$toVersion);
my @files = readdir(DIR);
closedir(DIR);
my $newFolder = undef;
foreach my $file (@files) {
next unless ($file =~ /\.wgpkg$/);
# Fix the filename to include a path
$file = "packages-" . $toVersion . "/" . $file;
addPackage( $session, $file );
}
}
#vim:ft=perl

View file

@ -620,6 +620,9 @@
"WebGUI::Asset::Wobject::Article" : {
"category" : "basic"
},
"WebGUI::Asset::Wobject::AssetReport" : {
"category" : "utilities"
},
"WebGUI::Asset::Wobject::Search" : {
"category" : "basic"
},
@ -682,7 +685,10 @@
},
"WebGUI::Asset::Wobject::Map" : {
"category" : "basic"
}
},
"WebGUI::Asset::Wobject::AssetReport" : {
"category" : "utilities"
},
},
#

View file

@ -267,6 +267,7 @@ property skipNotification => (
autoGenerate => 0,
noFormPost => 1,
fieldType => 'yesNo',
default => 0,
);
has session => (
@ -394,6 +395,7 @@ require WebGUI::ProgressBar;
use WebGUI::Search::Index;
use WebGUI::TabForm;
use WebGUI::Utility;
use WebGUI::PassiveAnalytics::Logging;
=head1 NAME
@ -657,6 +659,80 @@ If specified, stores it, but also updates extraHeadTagsPacked with the packed ve
#-------------------------------------------------------------------
=head2 dispatch ( $fragment )
Based on the URL and query parameters in the current request, call internal methods
like www_view, www_edit, etc. If no query parameter is present, then it returns the output
from the www_view method. If the requested method does not exist in the object, it returns
the output from the www_view method.
=head3 $fragment
Any leftover part of the requested URL.
=cut
sub dispatch {
my ($self, $fragment) = @_;
return undef if $fragment;
my $session = $self->session;
my $state = $self->get('state');
##Only allow interaction with assets in certain states
return if $state ne 'published' && $state ne 'archived' && !$session->var->isAdminOn;
my $func = $session->form->param('func') || 'view';
my $viewing = $func eq 'view' ? 1 : 0;
my $sub = $self->can('www_'.$func);
if (!$sub && $func ne 'view') {
$sub = $self->can('www_view');
$viewing = 1;
}
return undef unless $sub;
my $output = eval { $self->$sub(); };
if (my $e = Exception::Class->caught('WebGUI::Error::ObjectNotFound::Template')) {
#WebGUI::Error::ObjectNotFound::Template
$session->log->error(sprintf "%s templateId: %s assetId: %s", $e->error, $e->templateId, $e->assetId);
}
elsif ($@) {
my $message = $@;
$session->log->warn("Couldn't call method www_".$func." on asset for url: ".$session->url->getRequestedUrl." Root cause: ".$message);
}
return $output if $output || $viewing;
##No output, try the view method instead
$output = eval { $self->www_view };
if (my $e = Exception::Class->caught('WebGUI::Error::ObjectNotFound::Template')) {
$session->log->error(sprintf "%s templateId: %s assetId: %s", $e->error, $e->templateId, $e->assetId);
return "chunked";
}
elsif ($@) {
warn "logged another warn: $@";
my $message = $@;
$session->log->warn("Couldn't call method www_view on asset for url: ".$session->url->getRequestedUrl." Root cause: ".$@);
return "chunked";
}
return $output;
}
#-------------------------------------------------------------------
=head2 drawExtraHeadTags ( )
Draw the Extra Head Tags. Done with a customDrawMethod because the Template
will override this.
=cut
sub drawExtraHeadTags {
my ($self, $params) = @_;
return WebGUI::Form::codearea($self->session, {
name => $params->{name},
value => $self->get($params->{name}),
defaultValue => undef,
});
}
#-------------------------------------------------------------------
=head2 fixUrl ( [value] )
Returns a URL, removing invalid characters and making it unique by

View file

@ -101,6 +101,7 @@ override addRevision => sub {
if ($newSelf->storageId && $newSelf->storageId eq $self->storageId) {
my $newStorage = $self->getStorageClass->get($self->session, $self->storageId)->copy;
$newSelf->update({storageId => $newStorage->getId});
$newSelf->applyConstraints;
}
return $newSelf;

View file

@ -1733,6 +1733,7 @@ sub www_edit {
name => "metadata_".$meta->{$field}{fieldId},
uiLevel => 5,
value => $meta->{$field}{value},
defaultValue => $meta->{$field}{defaultValue},
extras => qq/title="$meta->{$field}{description}"/,
options => $options,
fieldType => $fieldType,

View file

@ -0,0 +1,245 @@
package WebGUI::Asset::Wobject::AssetReport;
$VERSION = "1.0.0";
#-------------------------------------------------------------------
# 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 Tie::IxHash;
use WebGUI::International;
use WebGUI::Paginator;
use WebGUI::Utility;
use WebGUI::Form::AssetReportQuery;
use Moose;
use WebGUI::Definition::Asset;
extends 'WebGUI::Asset::Wobject';
define assetName => ['assetName', 'Asset_AssetReport.pm'];
define tableName => 'AssetReport';
property settings => (
tab => 'properties',
fieldType => 'AssetReportQuery',
default => undef,
label => '',
);
property templateId => (
tab => "display",
fieldType => "template",
namespace => "AssetReport",
default => "sJtcUCfn0CVbKdb4QM61Yw",
label => ["templateId label", 'Asset_AssetReport.pm'],
hoverHelp => ["templateId description", 'Asset_AssetReport.pm'],
);
property paginateAfter => (
tab => 'display',
fieldType => 'integer',
default => 25,
label => [ 'paginateAfter label' , 'Asset_AssetReport.pm'],
hoverHelp => [ 'paginateAfter description' , 'Asset_AssetReport.pm'],
);
#-------------------------------------------------------------------
=head2 canAdd ( session )
Class method to verify that the user has the privileges necessary to add this type of asset. Return a boolean.
Override this method to ensure that admin is the default group.
Only allow admins to add AssetReport as AssetReport currently bypasses normal
asset security measures.
=head3 session
The session variable.
=cut
sub canAdd {
my $class = shift;
my $session = shift;
$class->SUPER::canAdd($session, undef, '3');
}
#----------------------------------------------------------------------------
=head2 prepareView ( )
Prepare the view. Add stuff to HEAD.
=cut
around prepareView => sub {
my $orig = shift;
my $self = shift;
$self->$orig(@_);
my $session = $self->session;
# Prepare the template
my $template = WebGUI::Asset::Template->new( $session, $self->templateId );
if (!$template) {
WebGUI::Error::ObjectNotFound::Template->throw(
error => qq{Template not found},
templateId => $self->get("templateId"),
assetId => $self->getId,
);
}
$template->prepare;
$self->{_template} = $template;
return;
};
#----------------------------------------------------------------------------
=head2 getTemplateVars ( )
Get template variables common to all views of the Asset Report.
=cut
sub getTemplateVars {
my $self = shift;
my $session = $self->session;
my $db = $session->db;
my $var = $self->get;
#Build the lineage query
my $settings = JSON->new->decode($self->settings);
#TO DO - ADD CACHE CONTROL
my $assetId = $settings->{startNode};
my $asset = WebGUI::Asset->newById($session,$assetId);
my $rules = {};
$rules->{'isa'} = $settings->{className};
#Build where condition
my $condition = $settings->{anySelect};
$rules->{'whereClause'} = undef;
my $where = $settings->{where};
foreach my $key (sort(keys %{$where})) {
my $clause = $where->{$key};
my $prop = $self->secure_identifier($clause->{propSelect});
my $op = $self->validate_clause($clause->{opSelect});
my $value = $db->quote($clause->{valText});
$rules->{'whereClause'} .= qq{ $condition } if ($key > 1);
$rules->{'whereClause'} .= qq{$prop $op $value};
}
if($rules->{'whereClause'}) {
$rules->{'joinClass'} = $settings->{className};
}
#Build the order by condition
my $order = $settings->{order};
my @order = sort(keys %{$order});
if(scalar(@order)) {
$rules->{'orderByClause'} = undef;
foreach my $key (@order) {
my $orderBy = $order->{$key};
my $orderSelect = $self->secure_identifier($orderBy->{orderSelect});
my $dirSelect = (lc($orderBy->{dirSelect}) eq "desc") ? "DESC" : "ASC";
$rules->{'orderByClause'} .= q{, } if($key > 1);
$rules->{'orderByClause'} .= qq{$orderSelect $dirSelect};
}
}
if($settings->{'limit'}) {
$rules->{'limit'} = $settings->{'limit'};
}
my $sql = $asset->getLineageSql(["descendants"],$rules);
my $p = WebGUI::Paginator->new($session,$self->getUrl,$self->paginateAfter);
$p->setDataByQuery($sql);
#Build the data for all the assets on the page
$var->{'asset_loop'} = [];
my $data = $p->getPageData;
ROW: foreach my $row (@{$data}) {
my $returnAsset = eval { WebGUI::Asset->newById($session, $row->{assetId}); };
next ROW if Exception::Class->caught();
push(@{$var->{'asset_loop'}}, $returnAsset->get);
}
#Append template variables
$p->appendTemplateVars($var);
return $var;
}
#----------------------------------------------------------------------------
=head2 secure_identifier ( identifier )
Checks the identifier and passes back a secure string.
=cut
sub secure_identifier {
my $self = shift;
my $db = $self->session->db;
my $identifier = shift;
my @parts = split(/\./,$identifier);
if(scalar(@parts) > 1) {
my $table = $parts[0];
my $column = $parts[1];
$identifier = $db->dbh->quote_identifier($table).".".$db->dbh->quote_identifier($column);
}
else {
$identifier = $db->dbh->quote_identifier($identifier);
}
return $identifier;
}
#----------------------------------------------------------------------------
=head2 validate_clause ( clause )
validates a clause against valid types. Returns "=" if no match is found.
=cut
sub validate_clause {
my $self = shift;
my $clause = shift;
my $ops = WebGUI::Form::AssetReportQuery->getOps();
unless ($ops->{$clause}) {
$clause = "=";
}
return $clause;
}
#----------------------------------------------------------------------------
=head2 view ( )
method called by the www_view method. Returns a processed template
to be displayed within the page style.
=cut
sub view {
my $self = shift;
my $var = $self->getTemplateVars;
return $self->processTemplate( $var, undef, $self->{_template} );
}
1;

View file

@ -61,6 +61,14 @@ sub _newsletterCategories_options {
return $session->db->buildHashRef("select fieldId, fieldName from metaData_properties where fieldType in ('selectBox', 'checkList', 'radioList') order by fieldName");
}
# XXX TODO: Do this in Moose instead, if we can.
# # Change the default Collaboration template
# for my $def ( @$definition ) {
# if ( exists $def->{properties}->{collaborationTemplateId} ) {
# $def->{properties}->{collaborationTemplateId}->{defaultValue} = 'newslettercs0000000001';
# }
# }
use WebGUI::Form;
use WebGUI::International;
use WebGUI::Utility;

View file

@ -24,6 +24,7 @@ property data => (
fieldType => 'DataTable',
default => undef,
label => '',
dateFormat => \&getDateFormat,
);
property templateId => (
tab => "display",
@ -120,6 +121,41 @@ sub getDataTemplateVars {
#----------------------------------------------------------------------------
=head2 getDateFormat ( )
Get the current date format for the current user in a strftime format that YUI can
understand.
=cut
sub getDateFormat {
my ( $self ) = @_;
my $dateFormat
= WebGUI::DateTime->new( $self->session )->webguiToStrftime( $self->session->user->get('dateFormat') );
# Special handle %_varmonth_ super special WebGUI field that strftime doesn't have
$dateFormat =~ s/%_varmonth_/%m/g;
return $dateFormat;
}
#----------------------------------------------------------------------------
=head2 getEditTabs ( )
Add a tab for the data table.
=cut
sub getEditTabs {
my $self = shift;
my $i18n = WebGUI::International->new( $self->session, "Asset_DataTable" );
return ( $self->SUPER::getEditTabs, [ "data" => $i18n->get("tab label data") ], );
}
#----------------------------------------------------------------------------
=head2 getTemplateVars ( )
Get the template vars for this asset.
@ -159,6 +195,7 @@ sub prepareView {
name => $self->getId,
value => $self->data,
defaultValue => undef,
dateFormat => $self->getDateFormat,
}
);
$dt->prepare;

View file

@ -1123,7 +1123,6 @@ sub www_getCompareFormData {
$parameter->{value} = $form->process($param);
my $attributeId = $param;
$attributeId =~ s/^search_//;
$attributeId =~ s/_____/-/g;
$parameter->{attributeId} = $attributeId;
push(@searchParamList, $db->quote($parameter->{attributeId}) );
push(@searchParams, $parameter);
@ -1175,20 +1174,17 @@ sub www_getCompareFormData {
$checked = 'checked';
}
}
$result->{assetId} =~ s/-/_____/g;
push @results, $result if $checked eq 'checked';
}
}
else {
foreach my $result (@{$self->getListings}) {
$result->{assetId} =~ s/-/_____/g;
push @results, $result;
}
}
}
else {
foreach my $result (@{$self->getListings}) {
$result->{assetId} =~ s/-/_____/g;
if(WebGUI::Utility::isIn($result->{assetId},@listingIds)){
$result->{checked} = 'checked';
}
@ -1233,7 +1229,6 @@ sub www_getCompareListData {
my @responseFields = ("attributeId", "name", "description","fieldType", "checked");
foreach my $listingId (@listingIds){
$listingId =~ s/_____/-/g;
my $listing = WebGUI::Asset::MatrixListing->newById($session,$listingId);
$listing->incrementCounter("compares");
my $listingId_safe = $listingId;

View file

@ -49,6 +49,23 @@ property storyTemplateId => (
namespace => 'Story',
default => 'TbDcVLbbznPi0I0rxQf2CQ',
);
property storySortOrder => (
fieldType => "selectBox",
tab => 'display',
default => 'Chronologically',
options => \&_storySortOrder_options,
label => ['sortAlphabeticallyChronologically', 'Asset_StoryArchive'],
hoverHelp => ['sortAlphabeticallyChronologically description', 'Asset_StoryArchive'],
);
sub _storySortOrder_options {
my $session = shift->session;
my $i18n = WebGUI::International->new($session, 'Asset_StoryArchive');
return {
Alphabetically => $i18n->get('alphabetically'),
Chronologically => $i18n->get('chronologically'),
};
}
with 'WebGUI::Role::Asset::RssFeed';
@ -147,10 +164,11 @@ sub viewTemplateVariables {
my $wordList = WebGUI::Keyword::string2list($self->keywords);
my $key = WebGUI::Keyword->new($session);
my $p = $key->getMatchingAssets({
keywords => $wordList,
isa => 'WebGUI::Asset::Story',
usePaginator => 1,
rowsPerPage => $numberOfStories,
sortOrder => $self->get('storySortOrder') || 'Chronologically',
keywords => $wordList,
isa => 'WebGUI::Asset::Story',
usePaginator => 1,
rowsPerPage => $numberOfStories,
});
my $storyIds = $p->getPageData();
$var->{story_loop} = [];
@ -180,7 +198,7 @@ sub viewTemplateVariables {
push @{$var->{story_loop}}, $storyVars;
}
if ($self->{_standAlone}) {
if ($self->{_standAlone} and @$storyIds) {
my $topStoryData = $storyIds->[0];
shift @{ $var->{story_loop} };
##Note, this could have saved from the loop above, but this looks more clean and encapsulated to me.

View file

@ -350,7 +350,8 @@ sub view {
my $self = shift;
my $form = $self->session->form;
my $url = $self->session->url;
my $url = $self->session->url;
my $dbh = $self->session->db->dbh;
my $i18n = WebGUI::International->new($self->session, "Asset_UserList");
my (%var, @users, @profileField_loop, @profileFields);
my ($user, $sth, $sql, $profileField);
@ -432,7 +433,6 @@ sub view {
# Query user profile data. Exclude the visitor account and users that have been deactivated.
$sql = "select distinct users.userId, users.userName, userProfileData.publicProfile ";
# Include remaining profile fields in the query
my $dbh = $self->session->db->dbh;
foreach my $profileField (@profileFields){
$sql .= ", userProfileData." . $dbh->quote_identifier($profileField->{fieldName});
}
@ -441,22 +441,22 @@ sub view {
my $constraint;
my @profileSearchFields = ();
my $searchType = $form->process('searchType') || 'or';
my $searchType = lc $form->process('searchType') eq 'and' ? 'and' : 'or';
if ($form->process('search')){
# Normal search with one keyword takes precedence over other search options
if($form->process('limitSearch')){
# Normal search with one keyword in a limited number of fields
foreach my $profileField (@profileFields){
if ($form->process('includeInSearch_'.$profileField->{fieldName})){
push(@profileSearchFields,'userProfileData.'.$profileField->{fieldName}
.' like "%'.$form->process('search').'%"');
push(@profileSearchFields, 'userProfileData.'.$dbh->quote_identifier($profileField->{fieldName})
.' like '. $dbh->quote('%'.$form->process('search').'%'));
}
}
}
else{
# Normal search with one keyword in all fields
$constraint = "(".join(' or ', map {'userProfileData.'.$_->{fieldName}
.' like "%'.$form->process('search').'%"'} @profileFields).")";
$constraint = "(".join(' or ', map {'userProfileData.'.$dbh->quote_identifier($_->{fieldName})
.' like '.$dbh->quote('%'.$form->process('search').'%')} @profileFields).")";
}
}
elsif ($form->process('searchExact')){
@ -465,15 +465,15 @@ sub view {
# Exact search with one keyword in a limited number of fields
foreach my $profileField (@profileFields){
if ($form->process('includeInSearch_'.$profileField->{fieldName})){
push(@profileSearchFields,'userProfileData.'.$profileField->{fieldName}
.' like "'.$form->process('search').'"');
push(@profileSearchFields,'userProfileData.'.$dbh->quote_identifier($profileField->{fieldName})
.' like '.$dbh->quote($form->process('search')));
}
}
}
else{
# Exact search with one keyword in all fields
$constraint = "(".join(' or ', map {'userProfileData.'.$_->{fieldName}
.' like "'.$form->process('searchExact').'"'} @profileFields).")";
$constraint = "(".join(' or ', map {'userProfileData.'.$dbh->quote_identifier($_->{fieldName})
.' like ' . $dbh->quote($form->process('searchExact'))} @profileFields).")";
}
}
else{
@ -481,12 +481,12 @@ sub view {
foreach my $profileField (@profileFields){
# Exact search has precedence over normal search
if ($form->process('searchExact_'.$profileField->{fieldName})){
push(@profileSearchFields,'userProfileData.'.$profileField->{fieldName}
.' like "'.$form->process('searchExact_'.$profileField->{fieldName}).'"');
push(@profileSearchFields,'userProfileData.'.$dbh->quote_identifier($profileField->{fieldName})
.' like '. $dbh->quote($form->process('searchExact_'.$profileField->{fieldName})));
}
elsif ($form->process('search_'.$profileField->{fieldName})){
push(@profileSearchFields,'userProfileData.'.$profileField->{fieldName}
.' like "%'.$form->process('search_'.$profileField->{fieldName}).'%"');
push(@profileSearchFields,'userProfileData.'.$dbh->quote_identifier($profileField->{fieldName})
.' like '. $dbh->quote('%'.$form->process('search_'.$profileField->{fieldName})));
}
}
}
@ -495,14 +495,17 @@ sub view {
}
$sql .= " and ".$constraint if ($constraint);
my $sortBy = $form->process('sortBy') || $self->sortBy || 'users.username';
my $sortBy = $form->process('sortBy') || $self->sortBy || 'users.username';
my $sortOrder = $form->process('sortOrder') || $self->sortOrder || 'asc';
if (lc $sortOrder ne 'desc') {
$sortOrder = 'asc';
}
my @sortByUserProperties = ('dateCreated', 'lastUpdated', 'karma', 'userId');
if(isIn($sortBy,@sortByUserProperties)){
$sortBy = 'users.'.$sortBy;
}
$sortBy = join '.', map { $self->session->db->quoteIdentifier($_) } split /\./, $sortBy;
$sortBy = join '.', map { $dbh->quote_identifier($_) } split /\./, $sortBy;
$sql .= " order by ".$sortBy." ".$sortOrder;
my $paginatePage = $form->param('pn') || 1;

View file

@ -554,7 +554,11 @@ sub getKeywordHierarchy {
my $datum = {
title => $keyword, ##Note, same as keyword
url => $self->getUrl('func=byKeyword;keyword='.$keyword),
descendants => scalar @{ $assetKeyword->getMatchingAssets( { startAsset => $self, keyword => $keyword, }) },
descendants => scalar @{ $assetKeyword->getMatchingAssets( {
startAsset => $self,
keyword => $keyword,
sortOrder => 'Alphabetically',
}) },
};
##Prevent recursion if seen again
if (! $seen->{$keyword}++) {

View file

@ -19,6 +19,7 @@ use LWP::MediaTypes qw(guess_media_type);
use Time::HiRes;
use WebGUI::Asset;
use WebGUI::PassiveAnalytics::Logging;
use URI;
=head1 NAME
@ -41,6 +42,57 @@ These subroutines are available from this package:
#-------------------------------------------------------------------
=head2 dispatch ( $session, $assetUrl )
Attempts to return the output from an asset, based on its url. All permutations of the
URL are tried, to find an asset that matches. If it finds an Asset, then it calls the
dispatch method on it. An Asset's dispatch always returns SOMETHING, so if a matching
asset is found, this is the last stop.
=head3 $session
A WebGUI::Session object.
=head4 $assetUrl
The URL for this request.
=cut
sub dispatch {
my $session = shift;
my $assetUrl = shift;
return undef unless $assetUrl;
my $permutations = getUrlPermutations($assetUrl);
foreach my $url (@{ $permutations }) {
if (my $asset = getAsset($session, $url)) {
##Passive Analytics Logging
WebGUI::PassiveAnalytics::Logging::log($session, $asset);
# display from cache if page hasn't been modified.
if ($session->user->isVisitor
&& !$session->http->ifModifiedSince($asset->getContentLastModified, $session->setting->get('maxCacheTimeout'))) {
$session->http->setStatus("304","Content Not Modified");
$session->http->sendHeader;
$session->close;
return "chunked";
}
my $fragment = $assetUrl;
$fragment =~ s/$url//;
$session->asset($asset);
my $output = eval { $asset->dispatch($fragment); };
return $output if defined $output;
}
}
if ($session->var->isAdminOn) {
my $asset = WebGUI::Asset->newByUrl($session, $session->url->getRefererUrl) || WebGUI::Asset->getDefault($session);
return $asset->addMissing($assetUrl);
}
return undef;
}
#-------------------------------------------------------------------
=head2 getAsset ( session [, assetUrl ] )
Returns an asset based upon the requested asset URL, or optionally pass one in.
@ -73,6 +125,36 @@ sub getRequestedAssetUrl {
#-------------------------------------------------------------------
=head2 getUrlPermutations ( $url )
Returns an array reference of permutations for the URL.
=head3 $url
The URL to permute.
=cut
sub getUrlPermutations {
my $url = shift;
my @permutations = ();
return \@permutations if !$url;
if ($url =~ /\.\w+$/) {
push @permutations, $url;
$url =~ s/\.\w+$//;
}
my $uri = URI->new($url);
my @fragments = $uri->path_segments();
FRAG: while (@fragments) {
last FRAG if $fragments[-1] eq '';
push @permutations, join "/", @fragments;
pop @fragments;
}
return \@permutations;
}
#-------------------------------------------------------------------
=head2 handler ( session )
The content handler for this package.
@ -85,26 +167,28 @@ sub handler {
my $output = "";
if (my $perfLog = $errorHandler->performanceLogger) { #show performance indicators if required
my $t = [Time::HiRes::gettimeofday()];
$output = page($session);
$perfLog->({ time => Time::HiRes::tv_interval($t), type => 'Page'});
}
else {
my $asset = getAsset($session, getRequestedAssetUrl($session));
# display from cache if page hasn't been modified.
if ($var->get("userId") eq "1"
&& defined $asset
&& !$http->ifModifiedSince($asset->getContentLastModified, $session->setting->get('maxCacheTimeout'))) {
$http->setStatus(304);
$http->sendHeader;
return "chunked";
$output = dispatch($session, getRequestedAssetUrl($session));
$t = Time::HiRes::tv_interval($t) ;
if ($output =~ /<\/title>/) {
$output =~ s/<\/title>/ : ${t} seconds<\/title>/i;
}
# return the page.
else {
$output = page($session, undef, $asset);
else {
# Kludge.
my $mimeType = $http->getMimeType();
if ($mimeType eq 'text/css') {
$session->output->print("\n/* Page generated in $t seconds. */\n");
}
elsif ($mimeType =~ m{text/html}) {
$session->output->print("\nPage generated in $t seconds.\n");
}
else {
# Don't apply to content when we don't know how
# to modify it semi-safely.
}
}
}
else {
$output = dispatch($session, getRequestedAssetUrl($session));
}
my $filename = $http->getStreamedFile();
@ -122,89 +206,4 @@ sub handler {
return $output;
}
#-------------------------------------------------------------------
=head2 page ( session , [ assetUrl ] )
Processes operations (if any), then tries the requested method on the asset corresponding to the requested URL. If that asset fails to be created, it tries the default page.
=head3 session
The current WebGUI::Session object.
=head3 assetUrl
Optionally pass in a URL to be loaded.
=cut
sub page {
my $session = shift;
my $assetUrl = getRequestedAssetUrl($session, shift);
my $asset = shift || getAsset($session, $assetUrl);
my $output = undef;
if (defined $asset) {
my $method = "view";
if ($session->form->param("func")) {
$method = $session->form->param("func");
unless ($method =~ /^[A-Za-z0-9]+$/) {
$session->errorHandler->security("to call a non-existent method $method on $assetUrl");
$method = "view";
}
}
##Passive Analytics Logging
WebGUI::PassiveAnalytics::Logging::log($session, $asset);
$output = tryAssetMethod($session,$asset,$method);
$output = tryAssetMethod($session,$asset,"view") unless ($output || ($method eq "view"));
}
if ($output eq "") {
if ($session->var->isAdminOn) { # they're expecting it to be there, so let's help them add it
my $asset = WebGUI::Asset->newByUrl($session, $session->url->getRefererUrl);
if (Exception::Class->caught()) {
$asset = WebGUI::Asset->getDefault($session);
}
$output = $asset->addMissing($assetUrl);
}
}
return $output;
}
#-------------------------------------------------------------------
=head2 tryAssetMethod ( session )
Tries an asset method on the requested asset. Tries the "view" method if that method fails.
=head3 session
The current WebGUI::Session object.
=cut
sub tryAssetMethod {
my $session = shift;
my $asset = shift;
my $method = shift;
my $state = $asset->get("state");
return undef if ($state ne "published" && $state ne "archived" && !$session->var->isAdminOn); # can't interact with an asset if it's not published
$session->asset($asset);
my $methodToTry = "www_".$method;
my $output = eval{$asset->$methodToTry()};
if (my $e = Exception::Class->caught('WebGUI::Error::ObjectNotFound::Template')) {
$session->errorHandler->error(sprintf "%s templateId: %s assetId: %s", $e->error, $e->templateId, $e->assetId);
}
elsif ($@) {
$session->errorHandler->warn("Couldn't call method ".$method." on asset for url: ".$session->url->getRequestedUrl." Root cause: ".$@);
if ($method ne "view") {
$output = tryAssetMethod($session,$asset,'view');
} else {
# fatals return chunked
$output = 'chunked';
}
}
return $output;
}
1;

View file

@ -486,6 +486,63 @@ sub session {
=head2 webguiToStrftime ( format )
Change a WebGUI format into a Strftime format.
NOTE: %M in WebGUI's format has no equivalent in strftime format, so it will
be replaced with "_varmonth_". Do something with it.
=cut
sub webguiToStrftime {
my ( $self, $format ) = @_;
$format ||= "%z %Z";
my $session = $self->session;
my $temp;
#--- date format preference
$temp = $session->user->profileField('dateFormat') || '%y-%M-%D';
$format =~ s/\%z/$temp/g;
#--- time format preference
$temp = $session->user->profileField('timeFormat') || '%H:%n %p';
$format =~ s/\%Z/$temp/g;
#--- convert WebGUI date formats to DateTime formats
my %conversion = (
"c" => "B",
"C" => "b",
"d" => "d",
"D" => "e",
"h" => "I",
"H" => "l",
"j" => "H",
"J" => "k",
"m" => "m",
"M" => "_varmonth_",
"n" => "M",
"t" => "Z",
"O" => "z",
"p" => "P",
"P" => "p",
"s" => "S",
"V" => "V",
"w" => "A",
"W" => "a",
"y" => "Y",
"Y" => "y"
);
$format =~ s/\%(\w)/\~$1/g;
foreach my $key (keys %conversion) {
my $replacement = $conversion{$key};
$format =~ s/\~$key/\%$replacement/g;
}
return $format;
}
#######################################################################
=head2 webguiDate ( format )
@ -527,53 +584,14 @@ sub webguiDate {
my $self = shift;
my $session = $self->session;
return undef unless ($session);
my $format = shift || "%z %Z";
my $temp;
#---date format preference
$temp = $session->user->profileField('dateFormat') || '%y-%M-%D';
$format =~ s/\%z/$temp/g;
#---time format preference
$temp = $session->user->profileField('timeFormat') || '%H:%n %p';
$format =~ s/\%Z/$temp/g;
#--- convert WebGUI date formats to DateTime formats
my %conversion = (
"c" => "B",
"C" => "b",
"d" => "d",
"D" => "e",
"h" => "I",
"H" => "l",
"j" => "H",
"J" => "k",
"m" => "m",
"M" => "_varmonth_",
"n" => "M",
"t" => "Z",
"O" => "z",
"p" => "P",
"P" => "p",
"s" => "S",
"V" => "V",
"w" => "A",
"W" => "a",
"y" => "Y",
"Y" => "y"
);
$format =~ s/\%(\w)/\~$1/g;
foreach my $key (keys %conversion) {
my $replacement = $conversion{$key};
$format =~ s/\~$key/\%$replacement/g;
}
my $format = $self->webguiToStrftime( shift || "%z %Z" );
#--- %M
my $datestr = $self->strftime($format);
$temp = int($self->month);
my $temp = int($self->month);
$datestr =~ s/\%_varmonth_/$temp/g;
#--- return
return $datestr;
}

View file

@ -0,0 +1,424 @@
package WebGUI::Form::AssetReportQuery;
use strict;
use base 'WebGUI::Form::Control';
use JSON;
use WebGUI::International;
use WebGUI::Utility;
=head1 NAME
WebGUI::Form::AssetReportQuery -- Builds a form to collect query information used by Asset Report
=head1 SYNOPSIS
=head1 DESCRIPTION
=head1 METHODS
=cut
#-------------------------------------------------------------------
=head2 getDatabaseFieldType ( )
Returns "MEDIUMTEXT".
=cut
sub getDatabaseFieldType {
return "MEDIUMTEXT";
}
#----------------------------------------------------------------------------
=head2 getAnyList
Get the operator list.
=cut
sub getAnyList {
my $self = shift;
my $i18n = $self->i18n;
tie my %options, 'Tie::IxHash', (
'or' => $i18n->get("any option"),
'and' => $i18n->get("all option"),
);
return \%options;
}
#----------------------------------------------------------------------------
=head2 getDirs
Get the direction list.
=cut
sub getDirs {
my $self = shift;
my $i18n = $self->i18n;
tie my %options, 'Tie::IxHash', (
'asc' => $i18n->get("ascending option"),
'desc' => $i18n->get("descending option"),
);
return \%options;
}
#----------------------------------------------------------------------------
=head2 getOps
Get the operator list.
=cut
sub getOps {
my $self = shift;
tie my %options, 'Tie::IxHash', (
'=' => '=',
'<>' => '<>',
'>' => '>',
'>=' => '>=',
'<' => '<',
'<=' => '<=',
'LIKE' => 'LIKE',
'NOT LIKE' => 'NOT LIKE',
'IS NULL' => 'IS NULL',
'IS NOT NULL' => 'IS NOT NULL',
);
return \%options;
}
#----------------------------------------------------------------------------
=head2 getValue ()
Get the value of the form
=cut
sub getValue {
my $self = shift;
my $session = $self->session;
my $form = $session->form;
my $propCount = $form->process("propCount","hidden");
my $orderCount = $form->process("orderCount","hidden");
if($propCount) {
my $where = {};
my $whereCount = 1;
for(my $i = 0; $i < $propCount; $i++ ) {
my $propSelect = $form->process("propSelect_".$i,"selectBox");
if($propSelect ne "") {
my $opSelect = $form->process("opSelect_".$i,"selectBox");
my $valText = $form->process("valText_".$i,"text");
$where->{$whereCount} = {
propSelect => $propSelect,
opSelect => $opSelect,
valText => $valText,
};
$whereCount++;
}
}
my $orderBy = {};
my $orderByCount = 1;
for(my $i = 0; $i < $orderCount; $i++ ) {
my $orderSelect = $form->process("orderSelect_".$i,"selectBox");
if($orderSelect ne "") {
my $dirSelect = $form->process("dirSelect_".$i,"selectBox");
$orderBy->{$orderByCount} = {
"orderSelect" => $orderSelect,
"dirSelect" => $dirSelect,
};
$orderByCount++;
}
}
my $jsonHash = {
isNew => "false",
className => $form->process("className","selectBox"),
startNode => $form->process("startNode","asset"),
anySelect => $form->process("anySelect","selectBox"),
where => $where,
whereCount => $whereCount,
order => $orderBy,
orderCount => $orderByCount,
limit => $form->process("limit","integer"),
};
my $jsonStr = JSON->new->canonical->encode($jsonHash);
#Set the value in the form
$self->set('value',$jsonStr);
}
return $self->get('value') || $self->get('defaultValue');
}
#-------------------------------------------------------------------
=head2 i18n
Returns the i18n object for the form
=cut
sub i18n {
my $self = shift;
my $session = $self->session;
unless ($self->{_i18n}) {
$self->{_i18n}
= WebGUI::International->new($session,'Form_AssetReportQuery');
}
return $self->{_i18n};
}
#----------------------------------------------------------------------------
=head2 toHtml
Render the form control.
=cut
sub toHtml {
my $self = shift;
my $session = $self->session;
my $db = $session->db;
my $style = $session->style;
my $i18n = $self->i18n;
#Build a JSON Array of all the possible classes and their fields
my $json = {};
#Get all of the classes being used in the WebGUI instance
my $classes = $db->buildArrayRef(q{
SELECT
distinct className
FROM
asset
ORDER BY
className
});
#Hard code these for now
my %asset = (
"asset.creationDate" => $i18n->get("creationDate (asset)"),
"asset.createdBy" => $i18n->get("createdBy (asset)"),
"asset.stateChanged" => $i18n->get("stateChanged (asset)"),
"asset.stateChangedBy" => $i18n->get("stateChangedBy (asset)"),
"asset.isLockedBy" => $i18n->get("isLockedBy (asset)"),
);
#Get the fields from the definition of each class
foreach my $class (@{$classes}) {
my $definitions = $class->definition($session);
tie my %fields, "Tie::IxHash", ();
foreach my $definition (@{$definitions}) {
my $properties = $definition->{properties};
my $tableName = $definition->{tableName};
foreach my $property (keys %{$properties}) {
my $key = $tableName.".".$property;
$fields{$key} = qq{$property ($tableName)};
}
}
%fields = (%asset,%fields);
%fields = WebGUI::Utility::sortHash(%fields);
$json->{$class} = \%fields;
}
#Encode the JSON and add it to the end of the body
my $first_row_error_msg = $i18n->get("first_row_error_msg");
my $jsonStr = JSON->new->encode($json);
$style->setRawHeadTags(qq|<script type="text/javascript">var classValues = $jsonStr; </script>|);
my $jsonData = $self->get("value") || q|{ "isNew" : "true" }|;
$style->setRawHeadTags(qq|<script type="text/javascript">var dataValues = $jsonData; var first_row_error_msg = '$first_row_error_msg';</script>|);
$session->style->setScript($session->url->extras("yui-webgui/build/form/assetReportQuery.js"),{ type=>"text/javascript" });
#Decode JSON data for filling in some of the fields
my $jsonDataHash = JSON->new->decode($jsonData);
#Class select list
my $classSelect = WebGUI::Form::selectBox($session,{
name =>"className",
value => "",
options => {},
extras => q{onchange="loadClassName(this.value);"},
});
#Start Node
my $startNode = WebGUI::Form::asset($session,{
name =>"startNode",
value => $jsonDataHash->{startNode},
});
#Any Select
my $anySelect = WebGUI::Form::selectBox($session, {
name => "anySelect",
value => $jsonDataHash->{anySelect},
options => $self->getAnyList,
});
#Property Select
my $propSelect = WebGUI::Form::selectBox($session,{
name => "propSelect",
value => "",
options => { ""=>$i18n->get("choose one option") },
});
#Op Select
my $opSelect = WebGUI::Form::selectBox( $session, {
name => "opSelect",
value => "",
options => $self->getOps,
});
#Value Test
my $valText = WebGUI::Form::text($session,{
name => "valText"
});
#Delete Button
my $deleteButton = WebGUI::Form::button($session,{
value => "-",
extras => q{id="deleteButton_formId"}
});
#Add Button
my $addButton = WebGUI::Form::button($session,{
value => "+",
extras => q{ onclick="addRow(document.getElementById('row_1'),document.getElementById('whereBody'),'propCount_id');" },
});
#Order Select
my $orderSelect = WebGUI::Form::selectBox($session,{
name => "orderSelect",
value => "",
options => { ""=>$i18n->get("choose one option") },
});
#Dir Select
my $dirSelect = WebGUI::Form::selectBox($session, {
name => "dirSelect",
value => "",
options => $self->getDirs,
});
#Delete Button
my $orderDelButton = WebGUI::Form::button($session,{
value => "-",
extras => q{id="orderDelButton_formId"}
});
#Add Button
my $orderAddButton = WebGUI::Form::button($session,{
value => "+",
extras => q{ onclick="addRow(document.getElementById('order_1'),document.getElementById('orderBody'),'orderCount_id');" },
});
#Prop Count
my $propCount = WebGUI::Form::hidden($session, {
name => "propCount",
value => 1,
extras => q{id="propCount_id"},
});
#Order Count
my $orderCount = WebGUI::Form::hidden($session, {
name => "orderCount",
value => 1,
extras => q{id="orderCount_id"},
});
#Limit
my $limit = WebGUI::Form::integer($session,{
name => "limit",
value => $jsonDataHash->{limit},
});
my $classSelectLabel = $i18n->get("class select label");
my $startNodeLabel = $i18n->get("start node label");
my $anySelectLabel = sprintf($i18n->get("any select label"), $anySelect);
my $orderByLabel = $i18n->get("order by label");
my $limitLabel = $i18n->get("limit label");
my $limitSubText = $i18n->get("limit subtext");
#Choose a class
my $output = qq{
$propCount
$orderCount
<table>
<thead>
<tr><th>$classSelectLabel</th></tr>
</thead>
<tbody>
<tr><td>$classSelect</td></tr>
</tbody>
</table>
<table>
<thead>
<tr><th>$startNodeLabel</th></tr>
</thead>
<tbody>
<tr><td>$startNode</td></tr>
</tbody>
</table>
<table>
<thead>
<tr><th>$anySelectLabel</th><tr>
</thead>
</table>
<table>
<tbody id="whereBody">
<tr>
<td>$propSelect</td>
<td>$opSelect</td>
<td>$valText</td>
<td>$deleteButton</td>
<td>$addButton</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr><th colspan="4">$orderByLabel</th></tr>
</thead>
<tbody id="orderBody">
<tr>
<td>$orderSelect</td>
<td>$dirSelect</td>
<td>$orderDelButton</td>
<td>$orderAddButton</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr><th>$limitLabel</th></tr>
</thead>
<tbody>
<tr>
<td>$limit <span style="font-size:10px">($limitSubText)</span></td>
</tr>
</tbody>
</table>
};
return $output;
}
1;

View file

@ -68,6 +68,10 @@ Any extra name=value pairs needed to save the data successfully
If true, will enable the table for editing. This is only necessary when
displaying the table with getValueAsHtml().
=head4 dateFormat
A strftime string describing the proper date format
=cut
sub definition {
@ -81,6 +85,7 @@ sub definition {
ajaxSaveUrl => { defaultValue => undef, },
ajaxSaveFunc => { defaultValue => "view", },
ajaxSaveExtras => { defaultValue => undef, },
dateFormat => { defaultValue => '%y-%m-%d', },
};
return $class->SUPER::definition( $session, $definition );
@ -116,6 +121,8 @@ sub getDataTableHtml {
textbox => "textbox",
);
my $dateFormat = $self->get('dateFormat') || '%y-%m-%d';
my @columnsJson = ();
for my $column ( @{ $data->{columns} } ) {
@ -125,6 +132,7 @@ sub getDataTableHtml {
. qq["key" : "$column->{ key }", ]
. qq["abbr" : "$column->{ key }", ]
. qq["formatter" : "$column->{ formatter }", ]
. ( $column->{formatter} eq "Date" ? qq["dateOptions" : { "format" : "$dateFormat" },] : "" )
. qq["resizable" : 1, ]
. qq["sortable" : 1];
@ -155,6 +163,7 @@ sub getDataTableHtml {
"ajaxDataFunc" => $self->get('ajaxDataFunc'),
"ajaxSaveUrl" => $self->get('ajaxSaveUrl'),
"ajaxSaveFunc" => $self->get('ajaxSaveFunc'),
"dateFormat" => $dateFormat,
};
my $optionsJson = JSON->new->encode($options);

View file

@ -0,0 +1,34 @@
package WebGUI::Help::Asset_AssetReport;
use strict;
our $HELP = {
'asset report template' => {
title => 'help_asset_report_template',
body => 'help_asset_report_body',
isa => [
{ namespace => "Asset_Wobject",
tag => "wobject template variables",
},
{ namespace => "Asset_Template",
tag => "template variables"
},
{ namespace => "Asset",
tag => "asset template"
},
{ tag => 'pagination template variables',
namespace => 'WebGUI'
},
],
variables => [
{ 'name' => 'asset_loop',
'variables' => [
{ 'name' => 'asset_info' },
],
},
],
related => [],
},
};
1;

View file

@ -324,6 +324,11 @@ If usePaginator is not passed, then this variable will limit the number of asset
An array reference of asset states. The ids of assets in those states will be returned. If this option
is missing, only assets in the C<published> state will be returned.
=head4 sortOrder
Determines the order that assets are returned. By default, it is in Chronological order, by creationDate. If
you set sortOrder to Alphabetically, it will sort by title, and then lineage.
=cut
sub getMatchingAssets {
@ -384,9 +389,18 @@ sub getMatchingAssets {
push @clauses, 'keyword in ('.join(',', @placeholders).')';
}
my $sortOrder = $options->{sortOrder} || 'Chronologically';
my $orderBy = $sortOrder eq 'Alphabetically' ? ' order by upper(title), lineage' : ' order by creationDate desc, lineage';
# write the query
my $query = 'select distinct assetKeyword.assetId from assetKeyword left join asset using (assetId)
where '.join(' and ', @clauses).' order by creationDate desc, lineage';
my $query = q{
select distinct assetKeyword.assetId
from assetKeyword
left join asset using (assetId)
left join assetData using (assetId)
where } .
join(' and ', @clauses) . $orderBy;
# perform the search
if ($options->{usePaginator}) {

View file

@ -235,7 +235,11 @@ sub load {
croak $moduleError{$module};
}
# Check if we already have it
# Sanitize
if ( $module !~ m{^\w+(?:::\w+)*$} ) {
croak "Invalid module name: $module";
}
# Try to load the module
my $modulePath = $module . ".pm";
$modulePath =~ s{::|'}{/}g;

View file

@ -123,6 +123,28 @@ These methods are available from this class:
#-------------------------------------------------------------------
=head2 dispatch ( )
Extent the base method in Asset.pm to handle RSS feeds.
=cut
sub dispatch {
my ( $self, $fragment ) = @_;
if ($fragment eq '.rss') {
return $self->www_viewRss;
}
elsif ($fragment eq '.atom') {
return $self->www_viewAtom;
}
elsif ($fragment eq '.rdf') {
return $self->www_viewRdf;
}
return $self->next::method();
}
#-------------------------------------------------------------------
=head2 _httpBasicLogin ( )
Set header values and content to show the HTTP Basic Auth login box.

View file

@ -1314,9 +1314,8 @@ sub www_view {
my $style = $session->style;
my $yui = $url->extras('/yui/build');
$style->setScript("$yui/yahoo/yahoo-min.js");
$style->setScript("$yui/yahoo-dom-event/yahoo-dom-event.js");
$style->setScript("$yui/json/json-min.js");
$style->setScript("$yui/event/event-min.js");
$style->setScript("$yui/connection/connection-min.js");
$style->setScript($url->extras('underscore/underscore-min.js'));
$style->setScript($url->extras('shop/cart.js'), undef, 1);

View file

@ -229,7 +229,7 @@ sub paymentVariables {
return => $return->as_string,
cancel_return => $cancel->as_string,
shipping => $cart->calculateShipping,
handling_cart => $cart->calculateShipping, ##According to https://www.x.com/message/180018#180018
tax_cart => $cart->calculateTaxes,
discount_amount_cart => -($cart->calculateShopCreditDeduction),

View file

@ -238,20 +238,24 @@ sub correctCountry {
my $self = shift;
my $country = shift;
return $country eq q{United Kingdom} ? q{United Kingdom (Great Britain)}
: $country eq q{Bosnia and Herzegovina} ? q{Bosnia-Herzegovina}
: $country eq q{Christmas Island} ? q{Christmas Island (Australia)}
: $country eq q{Congo, the Democratic Republic of the} ? q{Congo, Democratic Republic of the}
: $country eq q{Cocos (Keeling) Islands} ? q{Cocos Island (Australia)}
: $country eq q{Congo} ? q{Congo, Republic of the}
: $country eq q{Christmas Island} ? q{Christmas Island (Australia)}
: $country eq q{Cote d'Ivoire} ? q{Ivory Coast (Cote dIvoire)}
: $country eq q{Georgia} ? q{Georgia, Republic of}
: $country eq q{Heard and Mc Donald Islands} ? q{Australia}
: $country eq q{Korea (South)} ? q{South Korea}
: $country eq q{Korea, Republic of} ? q{Democratic People's Republic of Korea}
: $country eq q{Korea, Republic of} ? q{Korea, Democratic Peoples Republic of (North Korea)}
: $country eq q{Lao People's Democratic Republic} ? q{Laos}
: $country eq q{Macedonia} ? q{Macedonia, Republic of}
: $country eq q{Moldova, Republic of} ? q{Moldova}
: $country eq q{Pitcairn} ? q{Pitcairn Island}
: $country eq q{Russian Federation} ? q{Russia}
: $country eq q{Saint Kitts and Nevis} ? q{Saint Christopher and Nevis}
: $country eq q{Slovakia} ? q{Slovak Republic}
: $country eq q{South Georgia and the South Sandwich Islands} ? q{South Georgia (Falkland Islands)}
: $country eq q{Tokelau} ? q{Tokelau (Union) Group (Western Samoa)}
: $country eq q{Trinidad} ? q{Trinidad and Tobago}
: $country eq q{Vatican City State (Holy See)} ? q{Vatican City}

View file

@ -316,7 +316,7 @@ sub addFileFromFilesystem {
return undef;
}
my $filename = (File::Spec->splitpath( $pathToFile ))[2];
if (isIn($self->getFileExtension($filename), qw(pl perl sh cgi php asp))) {
if (isIn($self->getFileExtension($filename), qw(pl perl sh cgi php asp pm))) {
$filename =~ s/\./\_/g;
$filename .= ".txt";
}

View file

@ -89,6 +89,45 @@ sub canView {
#----------------------------------------------------------------------------
=head2 updateDefaultStyle ( styleTemplateId [, asset ])
Update the default style to the given style template. If an asset is given,
also update all descendants of that asset.
=cut
sub updateDefaultStyle {
my ( $self, $styleTemplateId, $home ) = @_;
my $session = $self->session;
# WebGUI::Account modules cannot be introspected, so we hard-code the default set here
my @settingStyles = qw( userFunctionStyleId contribStyleTemplateId fmStyleTemplateId
friendsStyleTemplateId inboxStyleTemplateId profileStyleTemplateId
shopStyleTemplateId userAccountStyleTemplateId );
for my $setting ( @settingStyles ) {
$session->setting->set( $setting, $styleTemplateId );
}
# update default content styles
if ( $home ) {
my $assetIter = $home->getLineageIterator( [ "self", "descendants" ] );
while ( 1 ) {
my $asset;
eval { $asset = $assetIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $asset;
$asset->update( { styleTemplateId => $styleTemplateId } );
}
}
return;
}
#----------------------------------------------------------------------------
=head2 wrapStyle ( $output )
Wrap the output in the wizard style.
@ -255,18 +294,7 @@ sub www_chooseContentSave {
}
# update default site style
$session->setting->set( "userFunctionStyleId", $self->get('styleTemplateId') );
my $assetIter = $home->getLineageIterator( [ "self", "descendants" ] );
while ( 1 ) {
my $asset;
eval { $asset = $assetIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $asset;
$asset->update( { styleTemplateId => $self->get("styleTemplateId") } );
}
$self->updateDefaultStyle( $self->get('styleTemplateId'), $home );
# add new pages
if ( $form->get("aboutUs") ) {

View file

@ -362,22 +362,9 @@ sub www_defaultStyleSave {
my ( $self, @args ) = @_;
my $output = WebGUI::Wizard::HomePage::www_pickStyleSave( $self, @args );
my $session = $self->session;
# update default site style
$session->setting->set( "userFunctionStyleId", $self->get('styleTemplateId') );
my $home = WebGUI::Asset->getDefault( $session );
my $assetIter = $home->getLineageIterator( [ "self", "descendants" ] );
while ( 1 ) {
my $asset;
eval { $asset = $assetIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $asset;
if ( defined $asset ) {
$asset->update( { styleTemplateId => $self->get("styleTemplateId") } );
}
}
my $home = WebGUI::Asset->getDefault( $session );
WebGUI::Wizard::HomePage::updateDefaultStyle( $self, $self->get('styleTemplateId'), $home );
return $output;
}

View file

@ -0,0 +1,76 @@
package WebGUI::i18n::English::Asset_AssetReport;
use strict;
our $I18N = {
'assetName' => {
message => q{Asset Report},
lastUpdated => 0,
},
'templateId label' => {
message => q{Asset Report Template},
lastUpdated => 1226174617,
context => q{Label for asset edit screen},
},
'templateId description' => {
message => q{Select a template to display your asset report.},
lastUpdated => 1226174619,
context => q{Hover help for asset edit screen},
},
'paginateAfter label' => {
message => q{Assets Per Page},
lastUpdated => 1226174617,
context => q{Label for asset edit screen},
},
'paginateAfter description' => {
message => q{Choose the number of assets to display per page.},
lastUpdated => 1226174619,
context => q{Hover help for asset edit screen},
},
'help_asset_report_template' => {
message => q{Asset Report Template Help},
lastUpdate => 1226174619,
context => q{Title for Asset Report Template Help},
},
'help_asset_report_template' => {
message => q{Asset Report Template Help},
lastUpdate => 1226174619,
context => q{Title for Asset Report Template Help},
},
'help_asset_report_body' => {
message => q{<p>The following template variables are available for asset report templates.</p>},
lastUpdate => 1226174619,
context => q{Body for Asset Report Template Help},
},
'asset_loop' => {
message => q|A loop containing the assets returned by this report.|,
lastUpdated => 0,
context => q|Description of the asset_loop tmpl_loop for the template help.|
},
'asset_info' => {
message => q|General Asset information returned for the asset. See WebGUI Asset Template Help for more details.|,
lastUpdated => 0,
context => q|Description of the asset_loop tmpl_loop for the template help.|
},
'creation_date' => {
message => q{Creation Date},
lastUpdate => 1226174619,
context => q{Label for Creation Date inside template},
},
'created_by' => {
message => q{Created By},
lastUpdate => 1226174619,
context => q{Label for Created By inside template},
},
};
1;

View file

@ -0,0 +1,108 @@
package WebGUI::i18n::English::Form_AssetReportQuery;
use strict;
our $I18N = {
'any option' => {
message => q|any|,
lastUpdated => 1078852836,
context => q{Select list option in AssetReportQuery Form},
},
'all option' => {
message => q|all|,
lastUpdated => 1078852836,
context => q{Select list option in AssetReportQuery Form},
},
'ascending option' => {
message => q|Ascending|,
lastUpdated => 1078852836,
context => q{Select list option in AssetReportQuery Form},
},
'descending option' => {
message => q|Descending|,
lastUpdated => 1078852836,
context => q{Select list option in AssetReportQuery Form},
},
'choose one option' => {
message => q|Choose One|,
lastUpdated => 1078852836,
context => q{Select list option in AssetReportQuery Form},
},
'class select label' => {
message => q|Search for assets of type|,
lastUpdated => 1078852836,
context => q{Text label in AssetReportQuery Form},
},
'start node label' => {
message => q|That are descendants of the following asset|,
lastUpdated => 1078852836,
context => q{Text label in AssetReportQuery Form},
},
'any select label' => {
message => q|Matching %s of the following constraints|,
lastUpdated => 1078852836,
context => q{Text label in AssetReportQuery Form},
},
'order by label' => {
message => q|Order the results by|,
lastUpdated => 1078852836,
context => q{Text label in AssetReportQuery Form},
},
'limit label' => {
message => q|Limit the number of results returned to|,
lastUpdated => 1078852836,
context => q{Text label in AssetReportQuery Form},
},
'limit subtext' => {
message => q|Enter a zero if you do not wish to limit the number of results|,
lastUpdated => 1078852836,
context => q{Subtext for limit field in AssetReportQuery Form},
},
'creationDate (asset)' => {
message => q|creationDate (asset)|,
lastUpdated => 1078852836,
context => q{General item in asset select list},
},
'createdBy (asset)' => {
message => q|createdBy (asset)|,
lastUpdated => 1078852836,
context => q{General item in asset select list},
},
'stateChanged (asset)' => {
message => q|stateChanged (asset)|,
lastUpdated => 1078852836,
context => q{General item in asset select list},
},
'stateChangedBy (asset)' => {
message => q|stateChangedBy (asset)|,
lastUpdated => 1078852836,
context => q{General item in asset select list},
},
'isLockedBy (asset)' => {
message => q|isLockedBy (asset)|,
lastUpdated => 1078852836,
context => q{General item in asset select list},
},
'first_row_error_msg' => {
message => q|The first row may not be deleted. Please adjust your query appropriately|,
lastUpdated => 1078852836,
context => q{Error message in javascript},
},
};
1;

View file

@ -65,8 +65,8 @@ my $sth = $session->db->read($sql);
my $count = 1;
my %classTables; # Cache definition lookups
while ( my %row = $sth->hash ) {
eval { WebGUI::Asset->newPending( $session, $row{assetId} ) };
if ( $@ ) {
my $asset = eval { WebGUI::Asset->newPending( $session, $row{assetId} ) };
if ( $@ || ! $asset ) {
# Replace the progress bar with a message
printf "\r%-68s", "-- Corrupt: $row{assetId}";

125
sbin/fixWgaccess.pl Normal file
View file

@ -0,0 +1,125 @@
#!/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
#-------------------------------------------------------------------
$|++; # disable output buffering
our ($webguiRoot, $configFile, $help, $man);
BEGIN {
$webguiRoot = "..";
unshift (@INC, $webguiRoot."/lib");
}
use strict;
use Pod::Usage;
use Getopt::Long;
use WebGUI::Session;
# Get parameters here, including $help
GetOptions(
'configFile=s' => \$configFile,
'help' => \$help,
'man' => \$man,
);
pod2usage( verbose => 1 ) if $help;
pod2usage( verbose => 2 ) if $man;
pod2usage( msg => "Must specify a config file!" ) unless $configFile;
my $session = start( $webguiRoot, $configFile );
use WebGUI::Asset::File;
my $iter = WebGUI::Asset::File->getIsa($session);
ASSET: while (1) {
my $file = eval { $iter->() };
if (my $e = Exception::Class->caught()) {
$session->log->error($@);
next ASSET;
}
last ASSET unless $file;
$file->getStorageLocation->setPrivileges(
$file->get('ownerUserId'),
$file->get('groupIdView'),
$file->get('groupIdEdit'),
);
}
finish($session);
#----------------------------------------------------------------------------
sub start {
my $webguiRoot = shift;
my $configFile = shift;
my $session = WebGUI::Session->open($webguiRoot,$configFile);
$session->user({userId=>3});
return $session;
}
#----------------------------------------------------------------------------
sub finish {
my $session = shift;
$session->var->end;
$session->close;
}
__END__
=head1 NAME
fixWgaccess.pl -- Fix .wgaccess files
=head1 SYNOPSIS
fixWgaccess.pl --configFile config.conf ...
utility --help
=head1 DESCRIPTION
This script will fix all the .wgaccess files that control permissions inside
the /uploads folder.
This script currently only does File assets. Not all wgaccess files are
linked back to assets.
=head1 ARGUMENTS
=head1 OPTIONS
=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<--help>
Shows a short summary and usage
=item B<--man>
Shows this document
=back
=head1 AUTHOR
Copyright 2001-2009 Plain Black Corporation.
=cut
#vim:ft=perl

File diff suppressed because one or more lines are too long

View file

@ -21,10 +21,11 @@ use WebGUI::Test;
use WebGUI::Session;
use WebGUI::Storage;
use WebGUI::Asset::File;
use JSON;
use Test::More; # increment this value for each test you create
use Test::Deep;
plan tests => 10;
plan tests => 13;
#TODO: This script tests certain aspects of WebGUI::Storage and it should not
@ -47,7 +48,7 @@ cmp_bag($storage->getFiles, ['someScalarFile.txt'], 'Only 1 file in storage with
$session->user({userId=>3});
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->set({name=>"File Asset test"});
my $guard1 = cleanupGuard($versionTag);
my $guard1 = WebGUI::Test::addToCleanup($versionTag);
my $properties = {
# '1234567890123456789012'
id => 'FileAssetTest000000012',
@ -85,12 +86,47 @@ $versionTag->commit;
############################################
my $fileStorage = WebGUI::Storage->create($session);
my $guard2 = cleanupGuard($fileStorage);
$mocker->set_always('get', $fileStorage->getId);
WebGUI::Test->addToCleanup($fileStorage);
$mocker->set_always('get', $fileStorage->getId);
$mocker->set_always('getValue', $fileStorage->getId);
my $fileFormStorage = $asset->getStorageFromPost();
isa_ok($fileFormStorage, 'WebGUI::Storage', 'Asset::File::getStorageFromPost');
#----------------------------------------------------------------------------
# Test override of update to set permissions
$asset->update({ ownerUserId => '3', groupIdView => '3' });
my $privs = JSON->new->decode( $asset->getStorageLocation->getFileContentsAsScalar('.wgaccess') );
cmp_deeply(
$privs,
{
"assets" => [],
"groups" => superbagof( "3" ),
"users" => ["3"],
},
'update sets the correct permissions in wgaccess',
);
#----------------------------------------------------------------------------
# Add another new revision, changing the privs
my $newRev = $asset->addRevision( { ownerUserId => '3', groupIdView => '3' }, time + 5 );
WebGUI::Test::addToCleanup( WebGUI::VersionTag->getWorking( $session ) );
$privs = JSON->new->decode( $newRev->getStorageLocation->getFileContentsAsScalar('.wgaccess') );
cmp_deeply(
$privs,
{
"assets" => [],
"groups" => superbagof( "3" ),
"users" => ["3"],
},
'addRevision sets the correct permissions in wgaccess',
);
# Add a new revision, changing the privs
my $newRev = $asset->addRevision( { groupIdView => '7' }, time + 8 );
WebGUI::Test::addToCleanup( WebGUI::VersionTag->getWorking( $session ) );
is( $newRev->getStorageLocation->getFileContentsAsScalar('.wgaccess'), undef, "wgaccess doesn't exist" );
note( @{ $newRev->getStorageLocation->getFiles() } );
############################################
#
# www_view

View file

@ -52,8 +52,8 @@ $file->setFile( WebGUI::Test->getTestCollateralPath("International/lib/WebGUI/i1
my $storage = $file->getStorageLocation;
is_deeply(
$storage->getFiles, ['WebGUI.pm'],
"Storage location contains only the file we added",
$storage->getFiles, ['WebGUI_pm.txt'],
"Storage location contains only the file we added, name was changed to prevent uploading of code",
);
#vim:ft=perl

View file

@ -0,0 +1,127 @@
# vim:syntax=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
#------------------------------------------------------------------
# This tests the AssetReport asset
#
#
use FindBin;
use strict;
use lib "$FindBin::Bin/../../lib";
use Test::More;
use Test::Deep;
use JSON;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
my $node = WebGUI::Asset->getImportNode( $session );
#----------------------------------------------------------------------------
# Tests
plan tests => 3; # Increment this number for each test you create
#----------------------------------------------------------------------------
# Asset Report creation
use_ok( "WebGUI::Asset::Wobject::AssetReport" );
my $ar = $node->addChild( {
className => 'WebGUI::Asset::Wobject::AssetReport',
} );
isa_ok( $ar, 'WebGUI::Asset::Wobject::AssetReport' );
WebGUI::Test->addToCleanup($ar);
my $f = $node->addChild({
className => 'WebGUI::Asset::Wobject::Folder',
title => 'Asset Report Test',
});
WebGUI::Test->addToCleanup($f);
my $sn = $f->addChild({
className => 'WebGUI::Asset::Snippet',
title => 'Shawshank',
});
#----------------------------------------------------------------------------
# Value and variables
my $value = {
isNew => "false",
className => "WebGUI::Asset::Snippet",
startNode => $f->getId,
anySelect => "or",
where => {
1 => {
opSelect => "=",
propSelect => "assetData.title",
valText => "Shawshank"
},
},
whereCount => "2",
order => {
1 => {
dirSelect => "desc",
orderSelect => "assetData.title"
},
},
orderCount => "2",
limit => "0",
};
my $settings = JSON->new->encode( $value );
$ar->update( {
settings => $settings,
paginateAfter => 50,
} );
#----------------------------------------------------------------------------
# getTemplateVars
cmp_deeply(
$ar->getTemplateVars,
hash( {
%{ $ar->get },
'settings' => $settings,
'paginateAfter' => 50,
'templateId' => 'sJtcUCfn0CVbKdb4QM61Yw',
'pagination.firstPageUrl' => ignore(),
'pagination.isLastPage' => ignore(),
'pagination.nextPage' => ignore(),
'pagination.previousPageUrl' => ignore(),
'pagination.lastPageText' => ignore(),
'pagination.pageCount' => ignore(),
'pagination.firstPageText' => ignore(),
'pagination.previousPage' => ignore(),
'pagination.pageLoop' => ignore(),
'pagination.lastPage' => ignore(),
'pagination.lastPageUrl' => ignore(),
'pagination.pageNumber' => ignore(),
'pagination.pageList.upTo10' => ignore(),
'pagination.pageCount.isMultiple' => ignore(),
'pagination.pageList' => ignore(),
'pagination.previousPageText' => ignore(),
'pagination.nextPageUrl' => ignore(),
'pagination.pageLoop.upTo10' => ignore(),
'pagination.pageList.upTo20' => ignore(),
'pagination.pageLoop.upTo20' => ignore(),
'pagination.isFirstPage' => ignore(),
'pagination.nextPageText' => ignore(),
'pagination.firstPage' => ignore(),
'asset_loop' => [{ %{ $sn->get } }],
} ),
"getTemplateVars returns complete and correct data structure",
);
#vim:ft=perl

View file

@ -181,8 +181,6 @@ my $json = $matrix->www_getCompareFormData('score');
my $compareFormData = JSON->new->decode($json);
$expectedAssetId =~ s/-/_____/g;
cmp_deeply(
$compareFormData,
{ResultSet=>{

View file

@ -106,7 +106,6 @@ my $uploadsPath = Path::Class::Dir->new($session->config->get('uploadsPath'));
my $uploadsUrl = Path::Class::Dir->new($session->config->get('uploadsURL'));
my $graphRelative = $graphUrl->relative($uploadsUrl);
my $graphFile = $uploadsPath->file($graphRelative);
note $graphFile->stringify;
ok(-e $graphFile->stringify, 'graph exists');

View file

@ -31,7 +31,7 @@ my $session = WebGUI::Test->session;
#----------------------------------------------------------------------------
# Tests
plan tests => 18;
plan tests => 20;
#----------------------------------------------------------------------------
# put your tests here
@ -55,6 +55,7 @@ WebGUI::Test->addToCleanup($versionTag);
my $pastStory = $newFolder->addChild({ className => 'WebGUI::Asset::Story', title => "Yesterday is history", keywords => 'andy,norton'});
$creationDateSth->execute([$yesterday, $pastStory->getId]);
$pastStory->requestAutoCommit;
$pastStory = $pastStory->cloneFromDb;
my @staff = qw/norton hadley mert trout/;
my @inmates = qw/bogs red brooks andy heywood tommy jake skeet/;
@ -321,3 +322,61 @@ cmp_deeply(
],
'rssFeedItems'
);
################################################################
# Sort Order
################################################################
$pastStory->update( { title => "aaaay was history but isn't any more" } );
$pastStory->requestAutoCommit;
$pastStory = $pastStory->cloneFromDb;
$topic->update({ storiesPer => 4, storiesShort => 4, }); # storiesPer is used when _standAlone is true, storiesShort otherwise
$topic->{_standAlone} = 0;
$topic->update( { storySortOrder => 'Alphabetically' } );
$templateVars = $topic->viewTemplateVariables();
cmp_deeply(
$templateVars->{story_loop},
[
{
title => "aaaay was history but isn't any more",
url => ignore(),
creationDate => $yesterday,
},
{
title => 'andy',
url => ignore(),
creationDate => $now,
},
{
title => 'bogs',
url => ignore(),
creationDate => $now,
},
{
title => 'brooks',
url => ignore(),
creationDate => $now,
},
],
'viewTemplateVars has right number and contents in the story_loop in sort order Alphabetically mode'
);
################################################################
# Regression -- Empty StoryTopics shouldn't blow up
################################################################
my $emptyarchive = WebGUI::Asset->getDefault($session)->addChild({
className => 'WebGUI::Asset::Wobject::StoryTopic',
title => 'Why Do Good Things Happen To Bad People',
url => '/home/badstories',
keywords => 'aksjhgkja asgjhshs assajshhsg5',
});
WebGUI::Test->addToCleanup($emptyarchive); # blows up under the debugger...?
$versionTag->commit;
$emptyarchive->{_standAlone} = 1;
ok(eval { $emptyarchive->viewTemplateVariables() }, "viewTemplateVariables with _standAlone = 1 doesn't throw an error");

View file

@ -155,30 +155,30 @@ my $tag_set2 = WebGUI::VersionTag->getWorking($session);
$tag_set2->commit;
WebGUI::Test->addToCleanup($tag_set2);
cmp_bag(
cmp_deeply(
$wiki->getKeywordHierarchy(),
[
{
title => 'criminals', url => '/testwiki?func=byKeyword;keyword=criminals',
children => bag(
superhashof({ title => 'red', }),
children => set(
superhashof({ title => 'andy', }),
superhashof({ title => 'red', }),
),
descendants => 0,
},
{
title => 'inmates', url => '/testwiki?func=byKeyword;keyword=inmates',
children => bag(
superhashof({ title => 'heywood', }),
children => set(
superhashof({ title => 'brooks', }),
superhashof({ title => 'heywood', }),
),
descendants => 0,
},
{
title => 'staff', url => '/testwiki?func=byKeyword;keyword=staff',
children => bag(
superhashof({ title => 'norton', }),
children => set(
superhashof({ title => 'hadley', }),
superhashof({ title => 'norton', }),
),
descendants => 0,
},
@ -194,22 +194,22 @@ my $tag_set3 = WebGUI::VersionTag->getWorking($session);
$tag_set3->commit;
WebGUI::Test->addToCleanup($tag_set3);
cmp_bag(
cmp_deeply(
$wiki->getKeywordHierarchy(),
[
superhashof({
title => 'criminals',
children => bag(
children => set(
superhashof({
title => 'andy',
children => bag(
children => set(
superhashof({
title => 'inmates',
children => bag(
children => set(
superhashof({ title => 'heywood', }),
superhashof({
title => 'brooks',
children => bag(
children => set(
superhashof({ title => 'criminals', }),
),
}),
@ -226,7 +226,7 @@ cmp_bag(
}),
superhashof({
title => 'staff',
children => bag(
children => set(
superhashof({ title => 'norton', }),
superhashof({ title => 'hadley', }),
),

157
t/Asset/dispatch.t Normal file
View file

@ -0,0 +1,157 @@
# vim:syntax=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
#------------------------------------------------------------------
# Test the asset dispatch system
#
#
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::Session;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
BEGIN {
$INC{'WebGUI/Asset/TestDispatch.pm'} = __FILE__;
}
package WebGUI::Asset::TestDispatch;
use WebGUI::Asset;
use WebGUI::Exception;
our @ISA = ('WebGUI::Asset');
# Override dispatch to handle special /foo URL
sub dispatch {
my ( $self, $fragment ) = @_;
if ( $fragment eq '/foo' ) {
return "bar";
}
return $self->SUPER::dispatch( $fragment );
}
sub www_view {
return "www_view";
}
sub www_edit {
return "www_edit";
}
sub www_alsoView {
return;
}
sub www_brokenTemplate {
my $self = shift;
WebGUI::Error::ObjectNotFound::Template->throw(
error => qq{Template not found},
templateId => "This is a GUID",
assetId => $self->getId,
);
}
sub www_dies {
my $self = shift;
die "...aside from that bullet\n";
}
package main;
my $tag = WebGUI::VersionTag->getWorking( $session );
WebGUI::Test->addToCleanup( $tag );
#----------------------------------------------------------------------------
# Tests
plan tests => 18; # Increment this number for each test you create
#----------------------------------------------------------------------------
# Test dispatch
# Add a TestDispatch asset and test
my $td = WebGUI::Asset->getImportNode( $session )->addChild( {
url => 'testDispatch',
className => 'WebGUI::Asset::TestDispatch',
} );
is( $td->dispatch, "www_view", "dispatch with no fragment shows www_view" );
is( $td->dispatch( '/foo' ), 'bar', 'dispatch detects fragment and returns' );
ok( !$td->dispatch( '/unhandled' ), 'dispatch with unknown fragment returns false' );
# Test func=
$session->request->setup_body( {
func => 'edit',
} );
is( $td->dispatch, "www_edit", "dispatch handles ?func= query param" );
is( $td->dispatch( '/foo' ), "bar", "overridden dispatch trumps ?func= query param" );
# Test func= can only be run on the exact asset we requested
my $output = $td->dispatch( '/bar' );
is( $output, undef, "dispatch returned undef, meaning that it declined to handle the request for a func but the wrong URL" );
isnt( $output, "www_edit", "?func= dispatch cancelled because of unhandled fragment" );
# Test unhandled options
$session->request->setup_body( {
func => 'notAMethod',
} );
is( $td->dispatch, "www_view", "requests for non-existant methods return www_view method" );
# Test unhandled options
$session->request->setup_body( {
func => 'alsoView',
} );
is( $td->dispatch, "www_view", "if a query method returns undef, view is still returned" );
$session->request->setup_body( { } );
$output = $td->dispatch( '/not-foo' );
is( $output, undef, "dispatch returned undef, meaning that it declined to handle the request for the wrong URL" );
isnt( $output, "www_view", "?func= dispatch cancelled because of unhandled fragment" );
$td->cut();
$output = $td->dispatch();
is $output, undef, 'dispatch returns undef when trying to access an asset that is not published, and admin is not on';
$session->var->switchAdminOn;
$output = $td->dispatch();
is $output, 'www_view', 'when admin is on, the asset can be accessed';
$td->publish();
$session->var->switchAdminOff;
$output = $td->dispatch();
is $output, 'www_view', 'asset state restored for next tests';
# Test template exceptions
$session->request->setup_body( {
func => 'brokenTemplate',
} );
WebGUI::Test->interceptLogging(sub {
my $log_data = shift;
is( $td->dispatch, "www_view", "if a query method throws a Template exception, view is returned instead" );
is $log_data->{error}, 'Template not found templateId: This is a GUID assetId: '. $td->getId, '... and logged an error';
});
WebGUI::Test->interceptLogging(sub {
my $log_data = shift;
$session->request->setup_body( {
func => 'dies',
} );
is( $td->dispatch, "www_view", "if a query method dies, view is returned instead" );
is $log_data->{warn}, "Couldn't call method www_dies on asset for url: Root cause: ...aside from that bullet\n", '.. and logged a warn';
});
#vim:ft=perl

177
t/Content/Asset.t Normal file
View file

@ -0,0 +1,177 @@
# vim:syntax=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
#------------------------------------------------------------------
# Write a little about what this script tests.
#
#
use FindBin;
use strict;
use lib "$FindBin::Bin/../lib";
use Test::More;
use Test::Deep;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
use WebGUI::Content::Asset;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
BEGIN {
$INC{'WebGUI/Asset/TestDispatch.pm'} = __FILE__;
$INC{'WebGUI/Asset/TestDecline.pm'} = __FILE__;
}
package WebGUI::Asset::TestDispatch;
our @ISA = ('WebGUI::Asset');
# Override dispatch to handle special /foo URL
sub dispatch {
my ( $self, $fragment ) = @_;
if ( $fragment eq '/foo' ) {
return "bar";
}
return $self->SUPER::dispatch( $fragment );
}
sub www_edit {
my ( $self ) = @_;
return "www_edit " . $self->get('title');
}
sub www_view {
my ( $self ) = @_;
return "www_view " . $self->get('title');
}
package WebGUI::Asset::TestDecline;
our @ISA = ( 'WebGUI::Asset' );
# Override dispatch to decline everything
sub dispatch { return; }
sub www_edit { return "you'll never see me!" }
package main;
my $td
= WebGUI::Asset->getImportNode( $session )->addChild( {
title => "one",
className => 'WebGUI::Asset::TestDispatch',
url => 'testdispatch',
} );
WebGUI::Test->addToCleanup( WebGUI::VersionTag->getWorking( $session ) );
#----------------------------------------------------------------------------
# Tests
plan tests => 15; # Increment this number for each test you create
#----------------------------------------------------------------------------
# test getUrlPermutation( url ) method
cmp_deeply(
WebGUI::Content::Asset::getUrlPermutations( ),
[ ],
"Handles no URL gracefully",
);
cmp_deeply(
WebGUI::Content::Asset::getUrlPermutations( "one" ),
[ 'one' ],
"simple one element URL",
);
cmp_deeply(
WebGUI::Content::Asset::getUrlPermutations( "/one" ),
[ '/one', ],
"simple one element URL with leading slash",
);
cmp_deeply(
WebGUI::Content::Asset::getUrlPermutations( "one/two/three" ),
[ 'one/two/three', 'one/two', 'one', ],
"three element URL",
);
cmp_deeply(
WebGUI::Content::Asset::getUrlPermutations( "/one/two/three" ),
[ '/one/two/three', '/one/two', '/one', ],
"three element URL with leading slash",
);
cmp_deeply(
WebGUI::Content::Asset::getUrlPermutations( "/one/two/three.rss" ),
[ '/one/two/three.rss', '/one/two/three', '/one/two', '/one', ],
".ext is a seperate URL permutation",
);
#----------------------------------------------------------------------------
# test dispatch( session, url ) method
is ($session->asset, undef, 'session asset is not defined, yet');
is(
WebGUI::Content::Asset::dispatch( $session, "testdispatch" ),
"www_view one",
"Regular www_view",
);
is ($session->asset->getId, $td->getId, 'dispatch set the session asset');
is(
WebGUI::Content::Asset::dispatch( $session, "testdispatch/foo" ),
"bar",
"special /foo handler",
);
# Add an asset that clobbers the TestDispatch's /foo
my $clobberingTime
= WebGUI::Asset->getImportNode( $session )->addChild( {
title => "two",
className => 'WebGUI::Asset::TestDispatch',
url => $td->get('url') . '/foo',
} );
WebGUI::Test->addToCleanup($clobberingTime);
is(
WebGUI::Content::Asset::dispatch( $session, "testdispatch/foo" ),
"www_view two",
"dispatch to the asset with the longest URL",
);
is ($session->asset->getId, $clobberingTime->getId, 'dispatch reset the session asset');
$clobberingTime->purge;
# Add an asset that declines everything instead
my $declined
= WebGUI::Asset->getImportNode( $session )->addChild( {
title => "three",
className => 'WebGUI::Asset::TestDecline',
url => $td->get('url') . '/foo',
} );
is(
WebGUI::Content::Asset::dispatch( $session, "testdispatch/foo" ),
"bar",
"Dispatch passes to TestDispatch asset after declined",
);
# Test ?func= dispatch with declined asset
$session->request->setup_body({
func => "edit",
});
my $output = WebGUI::Content::Asset::dispatch( $session, "testdispatch/foo" );
isnt( $output, "you'll never see me!", "func=edit was declined" );
isnt( $output, "www_edit one", "func=edit was not for us" );
#vim:ft=perl

View file

@ -77,5 +77,5 @@ $xmlData = XMLin($output,
cmp_deeply(
\@actual_urls,
\@expected_urls,
'hidden pages hidden'
'hidden pages shown'
);

View file

@ -26,7 +26,7 @@ my $session = WebGUI::Test->session;
# put your tests here
plan tests => 28;
plan tests => 30;
my $timeZoneUser = addUser($session);
@ -91,6 +91,16 @@ ok($@, 'new croaks on an out of range time');
my $badday = eval { WebGUI::DateTime->new($session, '2001-08-16 99:199:99'); };
ok($@, 'new croaks on an illegal time');
#----------------------------------------------------------------------------
# Test webguiToStrftime conversion
is( $nowDt->webguiToStrftime('%y-%m-%d'), '%Y-%m-%d', 'webgui to strftime conversion' );
$timeZoneUser->update({ 'dateFormat' => '%y-%M-%D' });
$timeZoneUser->update({ 'timeFormat' => '%H:%n %p' });
is( $nowDt->webguiToStrftime, '%Y-%_varmonth_-%e %l:%M %P', 'default datetime string' );
sub addUser {
my $session = shift;
my $user = WebGUI::User->new($session, "new");

59
t/Form/AssetReportQuery.t Normal file
View file

@ -0,0 +1,59 @@
#-------------------------------------------------------------------
# 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 FindBin;
use strict;
use lib "$FindBin::Bin/../lib";
use WebGUI::Test;
use WebGUI::Form;
use WebGUI::Form::AssetReportQuery;
use WebGUI::Session;
use HTML::Form;
use WebGUI::Form_Checking;
#The goal of this test is to verify that Radio form elements work
use Test::More; # increment this value for each test you create
my $session = WebGUI::Test->session;
my $node = WebGUI::Asset->getImportNode( $session );
my $nodeId = $node->getId;
#----------------------------------------------------------------------------
# Tests
plan tests => 1; # Increment this number for each test you create
#----------------------------------------------------------------------------
# put your tests here
$session->request->setup_body({
className => "WebGUI::Asset",
propCount => 2,
orderCount => 2,
startNode => $nodeId,
startNode_display => "Import Node",
anySelect => "or",
propSelect_1 => "asset.createdBy",
opSelect_1 => "=",
valText_1 => "3",
orderSelect_1 => "assetData.title",
dirSelect_1 => "desc",
limit => "25",
});
my $arq = WebGUI::Form::AssetReportQuery->new($session);
my $expected = qq|{"anySelect":"or","className":"WebGUI::Asset","isNew":"false","limit":"25","order":{"1":{"dirSelect":"desc","orderSelect":"assetData.title"}},"orderCount":2,"startNode":"$nodeId","where":{"1":{"opSelect":"=","propSelect":"asset.createdBy","valText":"3"}},"whereCount":2}|;
is($arq->getValue, $expected, 'getValue');
#my $value = $session->form->process("settings","AssetReportQuery");

View file

@ -287,7 +287,6 @@ cmp_bag($gB->getGroupsIn(), [$gA->getId, 3], 'Group A is in Group B');
cmp_bag($gA->getGroupsFor(), [$gB->getId], 'Group B contains Group A');
cmp_bag($gA->getGroupsIn(), [3], 'Admin added to group A automatically');
diag $gA->getId;
$gA->addGroups([$gB->getId]);
cmp_bag($gA->getGroupsIn(), [3], 'Not allowed to create recursive group loops');

View file

@ -130,8 +130,6 @@ is(scalar @{ $inbox->getMessagesForUser($admin, '', '', '', 'sentBy='.$session->
is($inbox->getUnreadMessageCount($admin->userId), 4, 'getUnreadMessageCount');
my $messages = $inbox->getMessagesForUser($admin);
$messages->[0]->setRead($admin->userId);
note $messages->[0]->getStatus;
note $messages->[0]->isRead;
is($inbox->getUnreadMessageCount($admin->userId), 3, '... really tracks unread messages');
#vim:ft=perl

View file

@ -17,7 +17,7 @@ use WebGUI::Keyword;
use WebGUI::Asset;
# load your modules here
use Test::More tests => 15; # increment this value for each test you create
use Test::More tests => 16; # increment this value for each test you create
use Test::Deep;
use Data::Dumper;
@ -76,10 +76,28 @@ my $assetIds = $keyword->getMatchingAssets({ keyword => 'webgui', });
cmp_deeply(
$assetIds,
[$snippet->getId, $home->getId, ],
[ $snippet->getId, $home->getId, ],
'getMatchingAssets, by keyword, assetIds in order by creationDate, descending'
);
# sorted by title, alphabetically
my $aa_story = $home->addChild({ className => 'WebGUI::Asset::Snippet', title => "aaaa", keywords => 'webgui' });
WebGUI::Test->addToCleanup($aa_story);
$assetIds = $keyword->getMatchingAssets({ keyword => 'webgui', sortOrder => 'Alphabetically', });
cmp_deeply(
$assetIds,
[ $aa_story->getId, $snippet->getId, $home->getId, ], # 'aaa', 'Home', 'keyword snippet'
'getMatchingAssets, by keyword, assetIds in order by title'
);
$aa_story->trash();
$aa_story->purge();
# trashed assets
$snippet->trash();
cmp_deeply(

View file

@ -31,6 +31,7 @@ use Test::Deep::Shallow;
use Test::Deep::Blessed;
use Test::Deep::Isa;
use Test::Deep::Set;
use Test::Exception;
use WebGUI::Pluggable;
@ -41,7 +42,7 @@ use WebGUI::Pluggable;
#----------------------------------------------------------------------------
# Tests
plan tests => 12; # Increment this number for each test you create
plan tests => 19; # Increment this number for each test you create
#----------------------------------------------------------------------------
# put your tests here
@ -62,6 +63,15 @@ is($dumper->Dump, q|$VAR1 = {
};
|, "Can instanciate an object.");
dies_ok { WebGUI::Pluggable::load( '::HA::HA' ) } 'load dies on bad input';
like( $@, qr/^\QInvalid module name: ::HA::HA/, 'helpful error message' );
dies_ok { WebGUI::Pluggable::load( 'HA::HA::' ) } 'load dies on bad input';
dies_ok { WebGUI::Pluggable::load( 'HA::..::..::HA' ) } 'load dies on bad input';
dies_ok { WebGUI::Pluggable::load( '..::..::..::HA' ) } 'load dies on bad input';
dies_ok { WebGUI::Pluggable::load( 'uploads::ik::jo::ikjosdfwefsdfsefwef::myfile.txt\0.pm' ) } 'load dies on bad input';
dies_ok { WebGUI::Pluggable::load( 'HA::::HA' ) } 'load dies on bad input';
#----------------------------------------------------------------------------
# Test find and findAndLoad
{ # Block to localize @INC

View file

@ -354,8 +354,6 @@ cmp_deeply(
isa_ok( $driver->get(), 'HASH', 'get returns a hashref if called with no param');
note explain $driver->get();
is($driver->get('groupToUse'), 7, '... default group is 7');
$options = $driver->get();

View file

@ -140,7 +140,7 @@ cmp_deeply(
'create: requires a session variable',
);
my $now = WebGUI::DateTime->new($session, time);
my $now = time();
eval { $fence = WebGUI::Shop::Vendor->create($session, { userId => $fenceUser->userId, }); };
$e = Exception::Class->caught();
@ -152,9 +152,8 @@ is $fence->userId, $fenceUser->userId, 'object made with create has properties i
$fence->write;
ok($fence->get('dateCreated'), 'dateCreated is not null');
my $dateCreated = WebGUI::DateTime->new($session, $fence->get('dateCreated'));
my $deltaDC = $dateCreated - $now;
cmp_ok( $deltaDC->in_units('seconds'), '<=', 2, 'dateCreated is set properly');
my $deltaDC = $fence->dateCreated - $now;
cmp_ok( $deltaDC, '<=', 2, 'dateCreated is set properly');
#######################################################################
#

View file

@ -287,11 +287,11 @@ ok (!(-e $storage1->getPath("testfile-hash.file")), "rename file original file i
####################################################
$storage1->addFileFromFilesystem(
WebGUI::Test->getTestCollateralPath('International/lib/WebGUI/i18n/PigLatin/WebGUI.pm'),
WebGUI::Test->getTestCollateralPath('littleTextFile'),
);
ok(
grep(/WebGUI\.pm/, @{ $storage1->getFiles }),
grep(/littleTextFile/, @{ $storage1->getFiles }),
'addFileFromFilesystem: file added from test collateral area'
);
@ -312,7 +312,7 @@ cmp_bag($secondCopy->getFiles(), $storage1->getFiles(), 'copy: passing explicit
my $s3copy = WebGUI::Storage->create($session);
addToCleanup($s3copy);
my @filesToCopy = qw/WebGUI.pm testfile-hash-renamed.file/;
my @filesToCopy = qw/littleTextFile testfile-hash-renamed.file/;
$storage1->copy($s3copy, [@filesToCopy]);
cmp_bag($s3copy->getFiles(), [ @filesToCopy ], 'copy: passing explicit variable and files to copy');
{
@ -347,7 +347,7 @@ cmp_bag($s3copy->getFiles(), [ @filesToCopy ], 'copy: passing explicit variable
is(scalar @{ $storage1->getFiles }, 4, 'storage1 has 4 files');
is($storage1->deleteFile("testfile-hash-renamed.file"), 1, 'deleteFile: deleted 1 file');
is($storage1->deleteFile("testfile-hash-copied.file"), 1, 'deleteFile: deleted 1 file');
is($storage1->deleteFile("WebGUI.pm"), 1, 'deleteFile: deleted another file');
is($storage1->deleteFile("littleTextFile"), 1, 'deleteFile: deleted another file');
cmp_bag($storage1->getFiles, [$filename], 'deleteFile: storage1 has only 1 file');
##Test for out of object file deletion

View file

@ -57,7 +57,6 @@ my $nonRootLink = qr{
sub checkLinks {
my ($tag, $attrs) = @_;
if ($tag eq 'link' && $attrs->{href}) {
note sprintf '%s: %s', $tag, $attrs->{href};
if ($attrs->{href} !~ $nonRootLink) {
$validLinks = 0;
}

View file

@ -1,14 +0,0 @@
#-------------------------------------------------------------------
# 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 File::Spec::Functions qw( catdir rel2abs );
use File::Basename qw( dirname );
use Test::Class::Load rel2abs( catdir ( dirname( __FILE__ ), 'tests' ) );
Test::Class->runtests;

View file

@ -0,0 +1 @@
This is a little text file.

View file

@ -0,0 +1,363 @@
var classArray = [];
//-----------------------------------------------------------------------------------
function addRow(row,ttbody,countId,data) {
//Get the count
var count = getCount(countId);
//Set default data
if(data == null) data = {};
//Clone The Row
var tr = row.cloneNode(true);
//Get the row type
var rowType = getRowType(tr.id);
//Set the rowId
tr.id = rowType + '_' + count;
//Reset Row Props
var rowLen = tr.childNodes.length;
for (var i = 0; i < rowLen; i++) {
var td = tr.childNodes[i];
if(td.nodeType != 1) continue;
var colLen = td.childNodes.length;
for( var j = 0; j < colLen; j++) {
var node = td.childNodes[j];
if(node.nodeType != 1) continue;
var result = node.name.match(/([a-zA-Z]+)_(\d+)/);
if(result != null) {
node.name = result[1] + "_" + count;
node.id = result[1] + "_" + count + "_formId";
var nodeValue = data[result[1]];
var isSelect = node.type.indexOf("select") > -1
if(nodeValue) {
if(isSelect) {
selectValue(node,nodeValue);
}
else if(node.type != "button") {
node.value = nodeValue;
}
}
else {
if(isSelect) {
selectValue(node,"");
}
else if(node.type != "button") {
node.value = "";
}
}
if(result[1] == "deleteButton" || result[1] == "orderDelButton") {
node.onclick = new Function('deleteRow(document.getElementById("' + rowType + '_' + count + '"),document.getElementById("' + ttbody.id + '"));');
}
}
}
}
ttbody.appendChild(tr);
incrementCount(countId);
}
//-----------------------------------------------------------------------------------
function getPropCount() {
return getCount("propCount_id");
}
//-----------------------------------------------------------------------------------
function getOrderCount() {
return getCount("orderCount_id");
}
//-----------------------------------------------------------------------------------
function getCount(id) {
var count = document.getElementById(id);
return count.value;
}
//-----------------------------------------------------------------------------------
function getRowType(id) {
var parts = id.split("_");
return parts[0];
}
//-----------------------------------------------------------------------------------
function incrementCount(id) {
var count = document.getElementById(id);
var value = parseInt(count.value);
value++;
count.value = value;
return value;
}
//-----------------------------------------------------------------------------------
function incrementOrderCount() {
return incrementCount("orderCount_id");
}
//-----------------------------------------------------------------------------------
function incrementPropCount() {
return incrementCount("propCount_id");
}
//-----------------------------------------------------------------------------------
function deleteRow(row,ttbody) {
var rowId = row.id;
var rowType = getRowType(rowId);
var row1 = rowType + "_1";
if(rowId != row1) {
ttbody.removeChild(row);
return;
}
alert(first_row_error_msg);
return;
}
//-----------------------------------------------------------------------------------
function getClasses() {
if(classArray.length > 0) {
return classArray;
}
for (var key in classValues) {
classArray.push(key);
}
classArray.sort();
return classArray;
}
//-----------------------------------------------------------------------------------
function getClassValue() {
var className = document.getElementById("className_formId");
return className.value;
}
//-----------------------------------------------------------------------------------
function getFirstChild(node) {
var rowLen = node.childNodes.length;
for (var i = 0; i < rowLen; i++) {
if(node.childNodes[i].nodeType != 1) continue;
return node.childNodes[i];
}
return null;
}
//-----------------------------------------------------------------------------------
function loadClasses(selectBox) {
var classes = getClasses();
var value = "";
if(dataValues.isNew != "true") {
value = dataValues.className;
}
populateSelect(selectBox,classes,value);
return;
}
//-----------------------------------------------------------------------------------
function loadClassName (className) {
//Delete Where Rows
var propCount = getPropCount();
for(var i = 2; i < propCount; i++) {
var row = document.getElementById("row_" + i);
if(row != null) {
deleteRow(row,document.getElementById("whereBody"));
}
}
//Delete Order Rows
var orderCount = getOrderCount();
for(var i = 2; i < orderCount; i++) {
var row = document.getElementById("order_" + i);
if(row != null) {
deleteRow(row,document.getElementById("orderBody"));
}
}
//Load the new properties from the classes
var propSel = document.getElementById("propSelect_1_formId");
var orderSel = document.getElementById("orderSelect_1_formId");
emptySelect(propSel);
emptySelect(orderSel);
var classValue = getClassValue();
var propOpts = classValues[classValue];
populateSelect( propSel, propOpts, null, true );
populateSelect( orderSel, propOpts, null, true );
//Reset the counts
setCount("propCount_id",2);
setCount("orderCount_id",2);
return;
}
//-----------------------------------------------------------------------------------
function loadWhereRows(tbody) {
var propCount = getPropCount();
//Change the names and ids of the default row
var tr = getFirstChild(tbody);
tr.id = "row_" + propCount;
var propSelect = document.getElementById("propSelect_formId");
propSelect.name = "propSelect_" + propCount;
propSelect.id = "propSelect_" + propCount + "_formId";
var classValue = getClassValue();
var propOpts = classValues[classValue];
var opSelect = document.getElementById("opSelect_formId");
opSelect.name = "opSelect_" + propCount;
opSelect.id = "opSelect_" + propCount + "_formId";
var valText = document.getElementById("valText_formId");
valText.name = "valText_" + propCount;
valText.id = "valText_" + propCount + "_formId";
var deleteButton = document.getElementById("deleteButton_formId");
deleteButton.name = "deleteButton_" + propCount;
deleteButton.id = "deleteButton_" + propCount + "_formId";
deleteButton.onclick = new Function('deleteRow(document.getElementById("row_'+propCount+'"),document.getElementById("whereBody"));');
if(dataValues.isNew == "true") {
// Build the default row
populateSelect(propSelect,propOpts,null,true);
incrementPropCount();
}
else {
// Build existing rows
var whereData = dataValues.where;
//Handle case where user chooses no constraints.
var whereValue = null;
var selValue = null;
var valValue = null;
if(whereData[1] != null) {
whereValue = whereData[1].propSelect;
selValue = whereData[1].opSelect;
valValue = whereData[1].valText;
}
//Populate the data
populateSelect(propSelect,propOpts,whereValue,true);
selectValue(opSelect,selValue);
valText.value = valValue;
incrementPropCount();
for (var key in whereData) {
if(key > 1) {
addRow(tr,tbody,"propCount_id",whereData[key]);
}
}
}
}
//-----------------------------------------------------------------------------------
function selectValue (list, value) {
for ( var i = 0; i < list.options.length; i++ ) {
if(list.options[i].value == value) {
list.options[i].selected = true;
return;
}
}
}
//-----------------------------------------------------------------------------------
function loadOrder(tbody) {
var orderCount = getOrderCount();
//Change the names and ids of the default row
var tr = getFirstChild(tbody);
tr.id = "order_" + orderCount;
var orderSelect = document.getElementById("orderSelect_formId");
orderSelect.name = "orderSelect_" + orderCount;
orderSelect.id = "orderSelect_" + orderCount + "_formId";
// Build the default row
var classValue = getClassValue();
var orderOpts = classValues[classValue];
var dirSelect = document.getElementById("dirSelect_formId");
dirSelect.name = "dirSelect_" + orderCount;
dirSelect.id = "dirSelect_" + orderCount + "_formId";
var deleteButton = document.getElementById("orderDelButton_formId");
deleteButton.name = "orderDelButton_" + orderCount;
deleteButton.id = "orderDelButton_" + orderCount + "_formId";
deleteButton.onclick = new Function('deleteRow(document.getElementById("order_' + orderCount + '"),document.getElementById("orderBody"));');
if(dataValues.isNew == "true") {
populateSelect(orderSelect,propOpts,null,true);
incrementOrderCount();
}
else {
// Build existing rows
var orderData = dataValues.order;
//Handle case where user chooses no order.
var orderValue = null;
var dirValue = null;
if(orderData[1] != null) {
orderValue = orderData[1].orderSelect;
dirValue = orderData[1].dirSelect;
}
//Populate data
populateSelect(orderSelect,orderOpts,orderValue,true);
selectValue(dirSelect,dirValue);
incrementOrderCount();
for (var key in orderData) {
if(key > 1) {
addRow(tr,tbody,"orderCount_id",orderData[key]);
}
}
}
}
//-----------------------------------------------------------------------------------
function populateSelect( list, data, value, isHash ) {
if(isHash) {
for ( var key in data ) {
var opt = document.createElement("option");
opt.setAttribute("value",key);
if(key == value ) opt.setAttribute("selected",true);
opt.appendChild(document.createTextNode(data[key]));
list.appendChild(opt);
}
}
else {
for ( var i = 0; i < data.length; i++ ) {
var opt = document.createElement("option");
opt.setAttribute("value",data[i]);
if(data[i] == value ) opt.setAttribute("selected",true);
opt.appendChild(document.createTextNode(data[i]));
list.appendChild(opt);
}
}
//Fix IE Bug which causes dymamic repopulation to fail
var newList = list;
var col = list.parentNode;
col.removeChild(list);
col.appendChild(newList);
return;
}
//-----------------------------------------------------------------------------------
function emptySelect ( list ) {
//Remove all options from list except first one
while (list.options.length > 1) {
var elem = list.options[1];
list.removeChild(elem);
}
}
//-----------------------------------------------------------------------------------
function setCount(id,value) {
var count = document.getElementById(id);
count.value = value;
}
YAHOO.util.Event.onDOMReady( function () {
loadClasses(document.getElementById("className_formId"));
loadWhereRows(document.getElementById("whereBody"));
loadOrder(document.getElementById("orderBody"));
});

View file

@ -202,7 +202,10 @@ WebGUI.Form.DataTable
YAHOO.util.Dom.get( this.containerId + "-table" ).style.display = "none";
}
var dataTableOptions = { };
var dataTableOptions = {
dateOptions : { format : this.options.dateFormat }
};
if ( this.options.showEdit ) {
dataTableOptions.draggableColumns = true;
}
@ -629,6 +632,9 @@ WebGUI.Form.DataTable
sortable : ( col ? col.sortable : 1 ),
editor : ( format == "date" ? "date" : "textbox")
};
if ( format == "date" ) {
newCol["dateOptions"] = { format : this.options.dateFormat };
}
var newIndex = col ? col.getKeyIndex() : undefined;
this.dataTable.insertColumn( newCol, newIndex );