diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt
index 6a672ea99..25895da56 100644
--- a/docs/changelog/7.x.x.txt
+++ b/docs/changelog/7.x.x.txt
@@ -13,6 +13,7 @@
- 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.
7.9.10
- fixed #11721: spamStopWords not in WebGUI.conf.original
diff --git a/docs/upgrades/packages-7.9.11/pb_asset_report.wgpkg b/docs/upgrades/packages-7.9.11/pb_asset_report.wgpkg
new file mode 100644
index 000000000..a40bfb28d
Binary files /dev/null and b/docs/upgrades/packages-7.9.11/pb_asset_report.wgpkg differ
diff --git a/docs/upgrades/upgrade_7.9.10-7.9.11.pl b/docs/upgrades/upgrade_7.9.10-7.9.11.pl
index 420d8274c..8276f9a1c 100644
--- a/docs/upgrades/upgrade_7.9.10-7.9.11.pl
+++ b/docs/upgrades/upgrade_7.9.10-7.9.11.pl
@@ -32,6 +32,7 @@ my $session = start(); # this line required
# upgrade functions go here
alterStoryTopicTable($session);
+addAssetReport($session);
finish($session); # this line required
@@ -45,6 +46,30 @@ finish($session); # this line required
# 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;
+}
+
#----------------------------------------------------------------------------
# Describe what our function does
sub alterStoryTopicTable {
diff --git a/lib/WebGUI/Asset/Wobject/AssetReport.pm b/lib/WebGUI/Asset/Wobject/AssetReport.pm
new file mode 100644
index 000000000..4fa6f4c53
--- /dev/null
+++ b/lib/WebGUI/Asset/Wobject/AssetReport.pm
@@ -0,0 +1,297 @@
+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 Class::C3;
+use base qw/WebGUI::AssetAspect::Installable WebGUI::Asset::Wobject/;
+
+#-------------------------------------------------------------------
+
+=head2 definition ( session, definition )
+
+=cut
+
+sub definition {
+ my $class = shift;
+ my $session = shift;
+ my $definition = shift;
+ my $i18n = WebGUI::International->new( $session, 'Asset_AssetReport' );
+
+ tie my %properties, 'Tie::IxHash', (
+ settings => {
+ tab => 'properties',
+ fieldType => 'AssetReportQuery',
+ defaultValue => undef,
+ },
+ templateId => {
+ tab => "display",
+ fieldType => "template",
+ namespace => "AssetReport",
+ defaultValue => "sJtcUCfn0CVbKdb4QM61Yw",
+ label => $i18n->get("templateId label"),
+ hoverHelp => $i18n->get("templateId description"),
+ },
+ paginateAfter => {
+ tab => 'display',
+ fieldType => 'integer',
+ defaultValue => 25,
+ label => $i18n->get( 'paginateAfter label' ),
+ hoverHelp => $i18n->get( 'paginateAfter description' ),
+ },
+ );
+
+ push @{$definition}, {
+ assetName => $i18n->get('assetName'),
+ autoGenerateForms => 1,
+ tableName => 'AssetReport',
+ className => 'WebGUI::Asset::Wobject::AssetReport',
+ properties => \%properties,
+ };
+
+ return $class->SUPER::definition( $session, $definition );
+} ## end sub definition
+
+
+#----------------------------------------------------------------------------
+
+=head2 prepareView ( )
+
+Prepare the view. Add stuff to HEAD.
+
+=cut
+
+sub prepareView {
+ my $self = shift;
+ $self->SUPER::prepareView(@_);
+ my $session = $self->session;
+
+ # Prepare the template
+ my $template = WebGUI::Asset::Template->new( $session, $self->get("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;
+} ## end sub prepareView
+
+#----------------------------------------------------------------------------
+
+=head2 getTemplateVars ( )
+
+Get template variables common to all views of the Asset Report.
+
+=cut
+
+sub getTemplateVars {
+ my $self = shift;
+ my $session = $self->session;
+
+ my $var = $self->get;
+
+ #Build the lineage query
+ my $settings = JSON->new->decode($self->getValue("settings"));
+
+ #TO DO - ADD CACHE CONTROL
+
+ my $assetId = $settings->{startNode};
+ my $asset = WebGUI::Asset->newByDynamicClass($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 (keys %{$where}) {
+ my $clause = $where->{$key};
+ my $prop = $clause->{propSelect};
+ my $op = $clause->{opSelect};
+ my $value = $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 = keys %{$order};
+ if(scalar(@order)) {
+ $rules->{'orderByClause'} = undef;
+ foreach my $key (@order) {
+ my $orderBy = $order->{$key};
+ my $orderSelect = $orderBy->{orderSelect};
+ my $dirSelect = $orderBy->{dirSelect};
+
+ $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->get("paginateAfter"));
+ $p->setDataByQuery($sql);
+
+ #Build the data for all the assets on the page
+ $var->{'asset_loop'} = [];
+ my $data = $p->getPageData;
+ foreach my $row (@{$data}) {
+ my $returnAsset = WebGUI::Asset->new($session,$row->{assetId},$row->{className},$row->{revisionDate});
+ push(@{$var->{'asset_loop'}},$returnAsset->get);
+ }
+
+ #Append template variables
+ $p->appendTemplateVars($var);
+
+ return $var;
+}
+
+#----------------------------------------------------------------------------
+
+=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} );
+} ## end sub view
+
+#-------------------------------------------------------------------
+# Install Methods Below - Do Not Modify
+
+#-------------------------------------------------------------------
+sub install {
+ my $class = shift;
+ my $session = shift;
+ $class->next::method( $session );
+
+ ### Create a folder asset to store the default template
+ my $importNode = WebGUI::Asset->getImportNode($session);
+ my $folder = $importNode->addChild({
+ className => "WebGUI::Asset::Wobject::Folder",
+ title => "Asset Report",
+ menuTitle => "Asset Report",
+ url => "pb_asset_report",
+ groupIdView =>"3"
+ },"AssetReportFolder00001");
+
+ ### Add the template to the folder
+ $folder->addChild({
+ className => "WebGUI::Asset::Template",
+ namespace => "AssetReport",
+ title => "Asset Report Default Template",
+ menuTitle => "Asset Report Default Template",
+ ownerUserId => "3",
+ groupIdView => "7",
+ groupIdEdit => "4",
+ isHidden => 1,
+ isDefault => 1,
+ template => qq{
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+| Title |
+Creation Date |
+Created By |
+
+
+
+
+
+ |
+^D('%C %D, %y %h:%s %p',); |
+^User('username',); |
+
+
+
+
+
+
+
+
+ },
+ headBlock =>"",
+ }, "AssetReport00000000001");
+
+ ### Commit version tag
+ my $tag = WebGUI::VersionTag->new($session, WebGUI::VersionTag->getWorking($session)->getId);
+ if (defined $tag) {
+ $tag->set({comments=>"Template added/updated by Asset Install Process"});
+ $tag->requestCommit;
+ }
+}
+
+#-------------------------------------------------------------------
+sub uninstall {
+ my $class = shift;
+ my $session = shift;
+ $class->next::method( $session );
+
+ my $template = WebGUI::Asset->newByDynamicClass($session,"AssetReport00000000001");
+ $template->purge if($template);
+
+ my $folder = WebGUI::Asset->newByDynamicClass($session,"AssetReportFolder00001");
+ $folder->purge if($folder);
+}
+
+1;
diff --git a/lib/WebGUI/Form/AssetReportQuery.pm b/lib/WebGUI/Form/AssetReportQuery.pm
new file mode 100644
index 000000000..ae38ab61f
--- /dev/null
+++ b/lib/WebGUI/Form/AssetReportQuery.pm
@@ -0,0 +1,423 @@
+package WebGUI::Form::AssetReportQuery;
+
+use strict;
+use base 'WebGUI::Form::Control';
+use JSON;
+use WebGUI::International;
+use WebGUI::Utility;
+
+=head1 NAME
+
+WebGUI::Form::BooleanQuery -- Build a boolean query
+
+=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" => "creationDate (asset)",
+ "asset.createdBy" => "createdBy (asset)",
+ "asset.stateChanged" => "stateChanged (asset)",
+ "asset.stateChangedBy" => "stateChangedBy (asset)",
+ "asset.isLockedBy" => "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 $jsonStr = JSON->new->encode($json);
+ $style->setRawHeadTags(qq||);
+ my $jsonData = $self->get("value") || q|{ "isNew" : "true" }|;
+ $style->setRawHeadTags(qq||);
+ $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
+
+
+ | $classSelectLabel |
+
+
+ | $classSelect |
+
+
+
+
+ | $startNodeLabel |
+
+
+ | $startNode |
+
+
+
+
+
+
+ | $propSelect |
+ $opSelect |
+ $valText |
+ $deleteButton |
+ $addButton |
+
+
+
+
+
+ | $orderByLabel |
+
+
+
+ | $orderSelect |
+ $dirSelect |
+ $orderDelButton |
+ $orderAddButton |
+
+
+
+
+
+ | $limitLabel |
+
+
+
+ | $limit ($limitSubText) |
+
+
+
+ };
+
+ return $output;
+}
+
+1;
diff --git a/lib/WebGUI/i18n/English/Asset_AssetReport.pm b/lib/WebGUI/i18n/English/Asset_AssetReport.pm
new file mode 100644
index 000000000..50ff4a949
--- /dev/null
+++ b/lib/WebGUI/i18n/English/Asset_AssetReport.pm
@@ -0,0 +1,37 @@
+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},
+ },
+
+};
+
+1;
diff --git a/lib/WebGUI/i18n/English/Form_AssetReportQuery.pm b/lib/WebGUI/i18n/English/Form_AssetReportQuery.pm
new file mode 100644
index 000000000..979b29b88
--- /dev/null
+++ b/lib/WebGUI/i18n/English/Form_AssetReportQuery.pm
@@ -0,0 +1,73 @@
+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},
+ },
+
+};
+
+1;
diff --git a/t/Asset/Wobject/AssetReport.t b/t/Asset/Wobject/AssetReport.t
new file mode 100644
index 000000000..07480cc23
--- /dev/null
+++ b/t/Asset/Wobject/AssetReport.t
@@ -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
diff --git a/t/Form/AssetReportQuery.t b/t/Form/AssetReportQuery.t
new file mode 100644
index 000000000..b5b2523c7
--- /dev/null
+++ b/t/Form/AssetReportQuery.t
@@ -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");
diff --git a/www/extras/yui-webgui/build/form/assetReportQuery.js b/www/extras/yui-webgui/build/form/assetReportQuery.js
new file mode 100644
index 000000000..01179abdb
--- /dev/null
+++ b/www/extras/yui-webgui/build/form/assetReportQuery.js
@@ -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("The first row may not be deleted. Please adjust your query appropriately");
+ 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"));
+});
+