Merge commit 'b8845e25fa' into WebGUI8. Up to 7.10.0

This commit is contained in:
Colin Kuskie 2010-09-22 07:58:06 -07:00
commit 0180b11064
45 changed files with 480 additions and 46 deletions

View file

@ -1,4 +1,17 @@
7.10.0
- fixed #11812: Checking www_ajaxSave's response in the cart js, urlencoding post parameters
- added: Link in the Admin Console to the Addons section on webgui.org
- added: Labels in the Shopping Cart addresses are optional.
- added: template variable downgrading so that using we can safely pass
template variables TT would understand to HTML::Template templates -- see
WebGUI::Asset::Template::Parser->downgrade for details.
- fixed #11813: Payment confirmation screen dollar amount
- fixed #11832: Admin Session Interface broken
- fixed: Attachment label in the Template is missing
- fixed #11810: Attachment list broken in template
- fixed #11814: upgrade script removes cache too aggresively (Ernesto Hernández-Novich)
- fixed #11827: CS rich edit bug
- fixed #11825: Questionable attachmentsJson in AssetReport template
7.9.13
- fixed #11783: Instances deleted during realtime run
@ -1076,6 +1089,7 @@
- fixed #10158: Matrix 2.0 - Screenshots rendering poorly
- administer.js now has a much improved handling of the slider algorithm, plus some refactored code. Users will not notice anything.
- Survey slider answer updates, now update all the answers for max,min,step settings since only the first answers values are used anyways.
7.7.3
- fixed #10094: double explanation in thread help
- rfe #9612: Carousel Wobject (was Widget Wobject) (SDH Consulting Group)

View file

@ -21,6 +21,19 @@ save you many hours of grief.
Account Macro template
Admin Toggle Macro template
7.10.0
--------------------------------------------------------------------
* Due to a bug in the 7.8.24-7.9.11 upgrade, the ordering of template
attachments has been lost. The bug has been fixed in 7.9.14 for sites
that have not been upgraded yet. Unfortunately, due to the nature of
the bug, the correct ordering cannot be automatically restored.
Another bug, in the new attachments javascript, will change all attachments
to type CSS when the template is saved. Since there are 2 types of Javascript
attachments, there's no way of recovering the original type. If you are using
template attachments and have upgraded to 7.9.13 directly, you will need to
check each template and update the types.
7.9.8
--------------------------------------------------------------------
* Starting in WebGUI 7.9.4, the Net::Twitter module is required.

View file

@ -419,6 +419,13 @@
"url" : "^PageUrl(\"\",op=switchOffAdmin);",
"title" : "^International(12,WebGUI);"
},
"addons" : {
"icon" : "addons.png",
"uiLevel" : 1,
"group" : "12",
"url" : "http://www.webgui.org/addons",
"title" : "Addons"
},
"contentFilters" : {
"icon" : "contentFilters.gif",
"uiLevel" : 3,

View file

@ -61,7 +61,6 @@ sub appendCommonVars {
eval { WebGUI::Shop::Vendor->newByUserId($session, $session->user->userId); };
$var->{ 'userIsVendor' } = ! Exception::Class->caught();
$session->log->warn($@);
}
#-------------------------------------------------------------------

View file

@ -1635,8 +1635,12 @@ sub www_edit {
});
$var{'userDefined'.$x.'.form.htmlarea'}
= WebGUI::Form::HTMLArea($session, {
name => "userDefined".$x,
value => $userDefinedValue,
name => "userDefined".$x,
value => $userDefinedValue,
richEditId => ($self->isa("WebGUI::Asset::Post::Thread")
? $self->getThread->getParent->get("richEditor")
: $self->getThread->getParent->get("replyRichEditor")
),
});
$var{'userDefined'.$x.'.form.float'}
= WebGUI::Form::Float($session, {

View file

@ -294,7 +294,7 @@ override getEditForm => sub {
$tabform->getTab('properties')->addField( "jsonTable",
name => 'attachmentsJson',
value => $self->get('attachmentsJson'),
label => $i18n->get("attachments display label"),
label => $i18n->get("attachment display label"),
fields => [
{
type => "text",

View file

@ -54,6 +54,7 @@ sub process {
my $self = shift;
my $template = shift;
my $vars = $self->addSessionVars(shift);
$self->downgrade($vars);
my $t;
eval {
$t = HTML::Template->new(

View file

@ -81,6 +81,7 @@ sub process {
my $class = shift;
my $template = shift;
my $vars = $class->addSessionVars(shift);
$class->downgrade($vars);
my $t;
eval {
$t = HTML::Template::Expr->new(scalarref=>\$template,

View file

@ -16,6 +16,7 @@ package WebGUI::Asset::Template::Parser;
use strict;
use WebGUI::International;
use Scalar::Util qw(blessed);
#-------------------------------------------------------------------
@ -63,6 +64,49 @@ sub addSessionVars {
#-------------------------------------------------------------------
=head2 downgrade ( vars )
Removes or converts things HTML::Template-like engines can't handle. Coderefs
are removed, blessed objects are removed, and hashes are recursively flattened
by appending keys separated by dots (e.g. { foo => { bar => 'baz' } } becomes
{ 'foo.bar' => 'baz' }. Also, array elements that aren't hashes are converted
to hashes via { value => $bareValue }.
=cut
sub downgrade {
my ($self, $vars) = @_;
for my $k (keys %$vars) {
my $v = $vars->{$k};
if (blessed($v) || ref $v eq 'CODE') {
delete $vars->{$k};
}
elsif (ref $v eq 'ARRAY') {
for my $i (0..$#$v) {
if (ref $v->[$i] eq 'HASH') {
$self->downgrade($v->[$i]);
}
else {
my %hash = ( value => $v->[$i] );
$self->downgrade(\%hash);
$v->[$i] = \%hash;
}
}
}
elsif (ref $v eq 'HASH') {
delete $vars->{$k};
my %flatter;
for my $subkey (keys %$v) {
$flatter{"$k.$subkey"} = $v->{$subkey};
}
$self->downgrade(\%flatter);
@{$vars}{keys %flatter} = values %flatter;
}
}
}
#-------------------------------------------------------------------
=head2 new ( session )
Constructor.

View file

@ -133,8 +133,8 @@ sub generateFeed {
my $cache = $session->cache;
my $sort = $self->sortItems;
my %opt = (use_ixhash => 1) if $sort eq 'feed';
my $feed = XML::FeedPP::Atom->new(%opt);
my @opt = (use_ixhash => 1) if $sort eq 'feed';
my $feed = XML::FeedPP::Atom->new(@opt);
# build one feed out of many
my $newlyCached = 0;
@ -163,7 +163,7 @@ sub generateFeed {
}, $self->cacheTimeout );
eval {
my $singleFeed = XML::FeedPP->new($value, utf8_flag => 1, -type => 'string', xml_deref => 1, %opt);
my $singleFeed = XML::FeedPP->new($value, utf8_flag => 1, -type => 'string', xml_deref => 1, @opt);
$feed->merge_channel($singleFeed);
$feed->merge_item($singleFeed);
};

View file

@ -86,7 +86,7 @@ sub www_viewActiveSessions {
and users.userId<>1 order by users.username,userSession.lastPageView desc");
my $pn = $p->getPageNumber;
foreach my $data (@{ $p->getPageData() }) {
$output = '<tr class="tableData"><td>'.$data->{username}.' ('.$data->{userId}.')</td>';
$output .= '<tr class="tableData"><td>'.$data->{username}.' ('.$data->{userId}.')</td>';
$output .= '<td>'.$data->{sessionId}.'</td>';
$output .= '<td>'.$session->datetime->epochToHuman($data->{expires}).'</td>';
$output .= '<td>'.$session->datetime->epochToHuman($data->{lastPageView}).'</td>';

View file

@ -404,7 +404,7 @@ sub missingFields {
$addressData = $address;
}
my @missingFields = ();
FIELD: foreach my $field (qw/label firstName lastName address1 city state code country phoneNumber/) {
FIELD: foreach my $field (qw/firstName lastName address1 city state code country phoneNumber/) {
push @missingFields, $field if $addressData->{$field} eq '';
}
return @missingFields;
@ -495,11 +495,10 @@ sub processAddressForm {
email => $form->get($prefix . "email", "email"),
organization => $form->get($prefix . "organization"),
);
#my $label = $field eq 'address1' ? 'address'
# : $field eq 'phoneNumber' ? 'phone number'
# : $field
# ;
##Label is optional in the form, but required for the UI and API.
##Use the first address line in its place if it's missing
$addressData{label} = $addressData{address1} if ! $addressData{label};
return %addressData;
}

View file

@ -425,7 +425,6 @@ sub getI18nError {
my $i18n = WebGUI::International->new($self->session, 'Shop');
return $error eq 'no billing address' ? $i18n->get('no billing address')
: $error eq 'no shipping address' ? $i18n->get('no shipping address')
: $error eq 'billing label' ? $i18n->get('billing label')
: $error eq 'billing firstName' ? $i18n->get('billing firstName')
: $error eq 'billing lastName' ? $i18n->get('billing lastName')
: $error eq 'billing address1' ? $i18n->get('billing address1')
@ -434,7 +433,6 @@ sub getI18nError {
: $error eq 'billing state' ? $i18n->get('billing state')
: $error eq 'billing country' ? $i18n->get('billing country')
: $error eq 'billing phoneNumber' ? $i18n->get('billing phoneNumber')
: $error eq 'shipping label' ? $i18n->get('shipping label')
: $error eq 'shipping firstName' ? $i18n->get('shipping firstName')
: $error eq 'shipping lastName' ? $i18n->get('shipping lastName')
: $error eq 'shipping address1' ? $i18n->get('shipping address1')

View file

@ -94,7 +94,7 @@ sub appendCartVariables {
$var ||= {};
my $cart = $self->getCart;
$var->{shippableItemsInCart} = $cart->requiresShipping;
$var->{subtotal} = $cart->calculateSubtotal;
$var->{subtotal} = $cart->formatCurrency($cart->calculateSubtotal);
$var->{shipping} = $cart->calculateShipping;
$var->{taxes} = $cart->calculateTaxes;
my $totalPrice = $var->{subtotal} + $var->{shipping} + $var->{taxes};

182
sbin/classLoadTest.pl Normal file
View file

@ -0,0 +1,182 @@
#!/usr/bin/env perl
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2009 Plain Black Corporation.
#-------------------------------------------------------------------
# Please read the legal notices (docs/legal.txt) and the license
# (docs/license.txt) that came with this distribution before using
# this software.
#-------------------------------------------------------------------
# http://www.plainblack.com info@plainblack.com
#-------------------------------------------------------------------
use strict;
use File::Basename ();
use File::Spec;
my $webguiRoot;
BEGIN {
$webguiRoot = File::Spec->rel2abs(File::Spec->catdir(File::Basename::dirname(__FILE__), File::Spec->updir));
unshift @INC, File::Spec->catdir($webguiRoot, 'lib');
}
$|++; # disable output buffering
our ($configFile, $help, $man, $class);
use Pod::Usage;
use Getopt::Long;
use WebGUI::Session;
# Get parameters here, including $help
GetOptions(
'configFile=s' => \$configFile,
'help' => \$help,
'man' => \$man,
'class=s' => \$class,
);
pod2usage( verbose => 1 ) if $help;
pod2usage( verbose => 2 ) if $man;
pod2usage( msg => "Must specify a config file!" ) unless $configFile;
foreach my $libDir ( readLines( "preload.custom" ) ) {
if ( !-d $libDir ) {
warn "WARNING: Not adding lib directory '$libDir' from preload.custom: Directory does not exist.\n";
next;
}
unshift @INC, $libDir;
}
my $session = start( $webguiRoot, $configFile );
open(my $null, ">:utf8","/dev/null");
$session->output->setHandle($null);
printf "%22s\t\%18s\t%12s\t%s\n", 'Asset ID', 'Instanciate Time', 'Render Time','URL';
my $count = 0;
my $sth = $session->db->read("select assetId from asset where className=? and state='published'",[$class]);
while (my ($id) = $sth->array) {
$count++;
print $id;
# check instanciation time
my $t = [Time::HiRes::gettimeofday];
my $asset = eval { WebGUI::Asset->new($session, $id, $class)};
if (!defined $asset || $@) {
my $url = $session->db->quickScalar("select url from assetData where assetId=? order by revisionDate desc",[$id]);
print "\tbad asset: $@ \t url: $url \n";
next;
}
my $instanciation = Time::HiRes::tv_interval($t);
# set the default asset for those things that need it
$session->asset($asset);
# check render time
$t = [Time::HiRes::gettimeofday];
eval {my $junk = $asset->www_view};
my $rendering = Time::HiRes::tv_interval($t);
if ($@) {
$rendering = $@;
}
# get the url
my $url = $asset->getValue("url");
# output the results
printf "\t%18.4f\t%12.4f\t%s\n", $instanciation, $rendering ,$url;
}
close($null);
print "Total assets: $count\n";
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;
}
#-------------------------------------------------
sub readLines {
my $file = shift;
my @lines;
if (open(my $fh, '<', $file)) {
while (my $line = <$fh>) {
$line =~ s/#.*//;
$line =~ s/^\s+//;
$line =~ s/\s+$//;
next if !$line;
push @lines, $line;
}
close $fh;
}
return @lines;
}
__END__
=head1 NAME
classLoadTest.pl -- Test a single class performance
=head1 SYNOPSIS
classLoadTest.pl --configFile config.conf --class=<>
classLoadTest.pl --help
=head1 DESCRIPTION
This script will test the time it takes to instanciate and view all the
assets of a particular class from the given site.
=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<--class>
The full class name of the asset to test. Something like WebGUI::Asset::Wobject::Layout
or WebGUI::Asset::Wobject::Navigation.
=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

@ -8,8 +8,10 @@
# http://www.plainblack.com info@plainblack.com
#-------------------------------------------------------------------
use FindBin;
use strict;
use File::Spec;
use lib "$FindBin::Bin/../../../lib";
# The goal of this test is to test the creation of
# and expose any bugs of SyndicatedContent Wobjects.

View file

@ -31,7 +31,6 @@ SKIP: {
$today->set_time_zone('UTC');
my $yesterday = $today->clone;
$yesterday->subtract( days => 1 );
$yesterday->set_formatter($formatter);
my $out1 = WebGUI::Macro::ConvertUTCToTZ::process($session);
like( $out1, qr/\d{2}\/\d{2}\/\d{2}\/\d{2}\/\d{2}/, 'No parameters passed, check pattern');

View file

@ -19,7 +19,7 @@
# test 75% or 3 out of four items
use strict;
use lib '/data/WebGUI/t/lib';
use lib "$FindBin::Bin/../lib";
use WebGUI::Test;
use WebGUI::Session;

View file

@ -16,6 +16,7 @@
use strict;
use Test::More;
use Test::Deep;
use Data::Dumper;
use JSON;
use HTML::Form;
@ -30,7 +31,7 @@ my $session = WebGUI::Test->session;
#----------------------------------------------------------------------------
# Tests
plan tests => 54;
plan tests => 55;
#----------------------------------------------------------------------------
# figure out if the test can actually run
@ -451,6 +452,63 @@ TODO: {
ok(0, 'Test other users and groups');
}
#######################################################################
#
# appendCartVariables
#
#######################################################################
my $versionTag = WebGUI::VersionTag->getWorking($session);
my $node = WebGUI::Asset->getImportNode($session);
my $widget = $node->addChild({
className => 'WebGUI::Asset::Sku::Product',
title => 'Test product for cart template variables in the Product',
isShippingRequired => 1,
});
my $blue_widget = $widget->setCollateral('variantsJSON', 'variantId', 'new',
{
shortdesc => 'Blue widget', price => 5.00,
varSku => 'blue-widget', weight => 1.0,
quantity => 9999,
}
);
$versionTag->commit;
my $cart = WebGUI::Shop::Cart->newBySession($session);
WebGUI::Test->addToCleanup($versionTag, $cart);
my $addressBook = $cart->getAddressBook;
my $workAddress = $addressBook->addAddress({
label => 'work',
organization => 'Plain Black Corporation',
address1 => '1360 Regent St. #145',
city => 'Madison', state => 'WI', code => '53715',
country => 'United States',
});
$cart->update({
billingAddressId => $workAddress->getId,
shippingAddressId => $workAddress->getId,
});
$widget->addToCart($widget->getCollateral('variantsJSON', 'variantId', $blue_widget));
my $cart_variables = {};
$driver->appendCartVariables($cart_variables);
diag Dumper($cart_variables);
cmp_deeply(
$cart_variables,
{
taxes => ignore(),
shippableItemsInCart => 1,
totalPrice => '5.00',
inShopCreditDeduction => ignore(),
inShopCreditAvailable => ignore(),
subtotal => '5.00',
shipping => ignore(),
},
'appendCartVariables: checking shippableItemsInCart and totalPrice & subtotal formatting'
);
#######################################################################
#
# delete

108
t/Template/downgrade.t Normal file
View file

@ -0,0 +1,108 @@
use FindBin;
use strict;
use warnings;
use lib "$FindBin::Bin/../../lib";
use lib "$FindBin::Bin/../lib";
use Data::Dumper;
use Test::More;
use WebGUI::Test;
use WebGUI::Asset;
use WebGUI::Asset::Template::Parser;
my $funky_instance = bless {}, 'WebGUI::Asset::Template::Parser';
sub down_ok {
my ( $down, $expected, $msg ) = @_;
$funky_instance->downgrade($down);
is_deeply( $down, $expected, $msg )
or diag Dumper($down);
}
down_ok { foo => 'bar' }, { foo => 'bar' }, 'nonthreatening';
down_ok {
code => sub { }
},
{},
'code';
down_ok { obj => $funky_instance }, {}, 'object';
down_ok { hash => { foo => 'foo', bar => 'bar' } },
{ 'hash.foo' => 'foo', 'hash.bar' => 'bar' },
'simple hash flattening';
down_ok { array => [ 1, 2, 3 ] },
{ array => [ { value => 1 }, { value => 2 }, { value => 3 }, ] }, 'simple array flattening';
down_ok {
regular => 'simple',
hash => {
quite => 'deeply',
with => {
another => 'hashref',
and_even => [
'an', sub { }, { obj => $funky_instance },
'array',
[ 'nested', 'further', { son => '!!!' } ],
[ { oh => { wow => 'man' } } ]
],
blessme => $funky_instance,
}
}
}, {
regular => 'simple',
'hash.quite' => 'deeply',
'hash.with.another' => 'hashref',
'hash.with.and_even' => [
{ value => 'an' },
{}, {},
{ value => 'array' },
{ value => [ { value => 'nested' }, { value => 'further' }, { son => '!!!' }, ], },
{ value => [ { 'oh.wow' => 'man' } ] }
],
},
'twisted deep complex strucuture';
my $session = WebGUI::Test->session;
sub processed_ok {
my ( $parser, $template, $msg ) = @_;
my $temp = WebGUI::Asset->getTempspace($session);
my $tmpl = $temp->addChild( {
className => 'WebGUI::Asset::Template',
parser => $parser,
template => $template,
}
);
addToCleanup($tmpl);
is( $tmpl->process( {
his => { yes => 'yes', stop => 'stop' },
my => { yes => 'no', stop => 'go' }
}
),
<<'END_EXPECTED', $msg );
You say yes, I say no.
You say stop, and I say go.
END_EXPECTED
} ## end sub processed_ok
processed_ok( 'WebGUI::Asset::Template::HTMLTemplate', <<'END_HT', 'HTML::Template' );
You say <tmpl_var his.yes>, I say <tmpl_var my.yes>.
You say <tmpl_var his.stop>, and I say <tmpl_var my.stop>.
END_HT
my $gotExpr = use_ok('WebGUI::Asset::Template::HTMLTemplateExpr');
SKIP: {
skip 'No HTML::Template::Expr module', 1 unless $gotExpr;
WebGUI::Test->originalConfig('templateParsers');
$session->config->addToArray('templateParsers', 'WebGUI::Asset::Template::HTMLTemplateExpr');
processed_ok( 'WebGUI::Asset::Template::HTMLTemplateExpr', <<'END_HTE', 'HTML::Template::Expr' );
You say <tmpl_var his_yes>, I say <tmpl_var my_yes>.
You say <tmpl_var his_stop>, and I say <tmpl_var my_stop>.
END_HTE
}
done_testing;
#vim:ft=perl

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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -38,9 +38,18 @@
var Cart = {
attachAddressBlurHandlers: function (name) {
var fields = _.values(this.elements[name]),
var els = this.elements[name],
label = els.label,
addr = els.address1,
fields = _.values(els),
handler = this.createAddressBlurHandler(name);
this.event.on(fields, 'focusout', handler);
this.event.on(addr, 'focusout', function () {
if (!label.value) {
label.value = addr.value;
label.blur();
}
});
},
attachAddressSelectHandler: function (name) {
@ -300,6 +309,16 @@
var id = o.responseText,
d = self.elements.dropdowns;
if (!id.match(/^[A-Za-z0-9_-]{22}$/)) {
alert('Error: bad response trying to save address.');
return;
}
if (!id.match(/^[A-Za-z0-9_-]{22}$/)) {
alert('Error: bad response trying to save address.');
return;
}
function updateOne(dropdown) {
var opt = _.detect(dropdown.options, function (o) {
return o.text === label;
@ -401,7 +420,7 @@
var url = this.baseUrl,
cb = { success: success },
query = _(params).map(function (v, k) {
return [k, v].join('=');
return [k, escape(v)].join('=');
}).join('&');
if (method === 'GET') {

View file

@ -143,7 +143,7 @@ WebGUI.Form.JsonTable.prototype.init
// Fill in values based on field type
var cells = newRow.getElementsByTagName( "td" );
for ( var i = 0; i < this.columns.length - 1; i++ ) { // Last cell is for buttons
for ( var i = 0; i < this.columns.length; i++ ) { // Last cell is for buttons
var cell = cells[i];
var column = this.columns[i];
var field = cell.childNodes[0];