Merge commit 'v7.10.22' into WebGUI8

This commit is contained in:
Colin Kuskie 2011-10-31 20:13:01 -07:00
commit 431cd280a4
92 changed files with 3543 additions and 313 deletions

View file

@ -1,3 +1,13 @@
7.10.22
- rfe #12223: Add dateTime type to content profiling (metadata)
- rfe #12207: Thingy. Field_name info returned by www_editThingDataSaveViaAjax
- fixed #12206: Bad Subscription Groups in Duplicated Threads
- fixed #12208: replacements don't work
- fixed #12213: Unable to view cart when an asset is deleted.
- added: Better integration between User Profile fields, the Shop address book and the EMS.
- fixed #12218: Failed INSERT in Passive Profiling causes leak
- fixed #12173: CrystalX theme Thingy drop down problem
7.10.21
- added #9668 extension template variable to attachment loops for the following assets:
Article,Post,Event,File,Form::Attachments,Folder

View file

@ -1,7 +1,7 @@
This is a running list of template changes made during upgrades. If you have copied the default
templates, you will need to apply these changes manually to your copies.
7.8.0
8.0
* Account Macro template variables renamed:
account.url => account_url
@ -11,6 +11,10 @@ templates, you will need to apply these changes manually to your copies.
toggle.url => toggle_url
toggle.text => toggle_text
7.10.22
* Thingy CSS file - root/import/thingy-templates/thingy.css
Add CSS to make sure that overflows are visible, to handle style that hide overflow by default.
7.10.18
* Collaboration System Default Notification Template /default_forum_notification
Replace table with divs to make inline replying easier.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,198 @@
#!/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.10.22';
my $quiet; # this line required
my $session = start(); # this line required
# upgrade functions go here
addAuthorizePaymentDriver($session);
createAddressField($session);
addLinkedProfileAddress($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;
#}
#----------------------------------------------------------------------------
# Add the Authorize.net payment driver to each config file
sub addAuthorizePaymentDriver {
my $session = shift;
print "\tAdd the Authorize.net payment driver... " unless $quiet;
# and here's our code
$session->config->addToArray('paymentDrivers', 'WebGUI::Shop::PayDriver::CreditCard::AuthorizeNet');
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addLinkedProfileAddress {
my $session = shift;
print "\tAdding linked profile addresses for existing users... " unless $quiet;
my $users = $session->db->buildArrayRef( q{
select userId from users where userId not in ('1','3')
} );
foreach my $userId (@$users) {
#check to see if there is user profile information available
my $u = WebGUI::User->new($session,$userId);
#skip if user does not have any homeAddress fields filled in
next unless (
$u->profileField("homeAddress")
|| $u->profileField("homeCity")
|| $u->profileField("homeState")
|| $u->profileField("homeZip")
|| $u->profileField("homeCountry")
|| $u->profileField("homePhone")
);
#Get the address book for the user (one is created if it does not exist)
my $addressBook = WebGUI::Shop::AddressBook->newByUserId($session,$userId);
#Add the profile address for the user
$addressBook->addAddress({
label => "Profile Address",
firstName => $u->profileField("firstName"),
lastName => $u->profileField("lastName"),
address1 => $u->profileField("homeAddress"),
city => $u->profileField("homeCity"),
state => $u->profileField("homeState"),
country => $u->profileField("homeCountry"),
code => $u->profileField("homeZip"),
phoneNumber => $u->profileField("homePhone"),
email => $u->profileField("email"),
isProfile => 1,
});
}
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub createAddressField {
my $session = shift;
#skip if field exists
my $columns = $session->db->buildArrayRef("show columns from address where Field='isProfile'");
return if(scalar(@$columns));
print "\tAdding profile link to Address... " unless $quiet;
$session->db->write( q{
alter table address add isProfile tinyint default 0
} );
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

@ -0,0 +1,561 @@
#!/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 = "0.0.0"; # make this match what version you're going to
my $quiet; # this line required
my $session = start(); # this line required
# upgrade functions go here
i18nForAddonsTitle($session);
addForkTable($session);
installForkCleanup($session);
addVersioningToMetadata($session);
installNewDashboardTables($session);
addStockDataCacheColumn($session);
addWeatherDataCacheColumn($session);
addLastModifiedByMacro($session);
addAutoPlayToCarousel( $session );
addProcessorDropdownToSnippet( $session );
addRichEditToCarousel($session);
alterAssetIndexTable($session);
reindexAllThingys($session);
use WebGUI::Asset::MapPoint;
WebGUI::AssetAspect::Installable::upgrade("WebGUI::Asset::MapPoint",$session);
addRenderThingDataMacro($session);
addAssetPropertyMacro($session);
createThingyDBColumns($session);
addAssetManagerSortPreferences($session);
addTicketLimitToBadgeGroup( $session );
addFormFieldMacroToConfig();
addWaitForConfirmationWorkflow($session);
addCreateUsersEnabledSetting($session);
addAuthorizePaymentDriver($session);
createAddressField($session);
addLinkedProfileAddress($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;
#}
#----------------------------------------------------------------------------
# This internationalizes the link text of the addons link in the adminconsole
sub i18nForAddonsTitle {
my $session = shift;
print "\tInternationalize the text of the addons link in the adminconsole... " unless $quiet;
$session->config->set('adminConsole/addons',
{
icon => "addons.png",
uiLevel => 1,
group => "12",
url => "http://www.webgui.org/addons",
title => "^International(Addons title,WebGUI);"
}
);
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Creates a new table for tracking background processes
sub addForkTable {
my $session = shift;
my $db = $session->db;
my $sth = $db->dbh->table_info('', '', 'Fork', 'TABLE');
return if ($sth->fetch);
print "\tAdding Fork table..." unless $quiet;
my $sql = q{
CREATE TABLE Fork (
id CHAR(22),
userId CHAR(22),
groupId CHAR(22),
status LONGTEXT,
error TEXT,
startTime BIGINT(20),
endTime BIGINT(20),
finished BOOLEAN DEFAULT FALSE,
latch BOOLEAN DEFAULT FALSE,
PRIMARY KEY(id)
);
};
$db->write($sql);
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# install a workflow to clean up old background processes
sub installForkCleanup {
my $session = shift;
print "\tInstalling Fork Cleanup workflow..." unless $quiet;
my $class = 'WebGUI::Workflow::Activity::RemoveOldForks';
$session->config->addToArray('workflowActivities/None', $class);
my $wf = WebGUI::Workflow->new($session, 'pbworkflow000000000001');
use List::Util qw/first/;
my $a = first { ref $_ eq $class } @{ $wf->getActivities };
unless ($a) {
$a = $wf->addActivity($class);
$a->set(title => 'Remove Old Forks');
};
print "DONE!\n" unless $quiet;
}
sub addVersioningToMetadata {
my $session = shift;
print "\tAltering metadata tables for versioning..." unless $quiet;
my $db = $session->db;
$db->write(q{
alter table metaData_values
add column revisionDate bigint,
drop primary key,
add primary key (fieldId, assetId, revisionDate);
});
$db->write(q{
create table metaData_classes (
className char(255),
fieldId char(22)
);
});
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Describe what our function does
sub addLastModifiedByMacro {
my $session = shift;
print "\tAdd LastModifiedBy macro to the config file... " unless $quiet;
# and here's our code
$session->config->addToHash('macros', 'LastModifiedBy', 'LastModifiedBy');
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Describe what our function does
sub installNewDashboardTables {
my $session = shift;
print "\tInstall new Dashboard tables... " unless $quiet;
$session->db->write(<<EOSQL);
CREATE TABLE IF NOT EXISTS Dashboard_dashlets (
dashboardAssetId CHAR(22) BINARY,
dashletAssetId CHAR(22) BINARY,
isStatic BOOLEAN,
isRequired BOOLEAN,
PRIMARY KEY (dashboardAssetId, dashletAssetId)
) TYPE=MyISAM CHARSET=utf8;
EOSQL
$session->db->write(<<EOSQL);
CREATE TABLE IF NOT EXISTS Dashboard_userPrefs (
dashboardAssetId CHAR(22) BINARY,
dashletAssetId CHAR(22) BINARY,
userId CHAR(22) BINARY,
isMinimized BOOLEAN,
properties LONGTEXT,
PRIMARY KEY (dashboardAssetId, dashletAssetId, userId)
) TYPE=MyISAM CHARSET=utf8;
EOSQL
# and here's our code
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Describe what our function does
sub addStockDataCacheColumn {
my $session = shift;
print "\tAdd cache column for the StockData asset... " unless $quiet;
$session->db->write(<<EOSQL);
ALTER TABLE StockData ADD COLUMN cacheTimeout BIGINT
EOSQL
# and here's our code
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Describe what our function does
sub addWeatherDataCacheColumn {
my $session = shift;
print "\tAdd cache column for the WeatherData asset... " unless $quiet;
$session->db->write(<<EOSQL);
ALTER TABLE WeatherData ADD COLUMN cacheTimeout BIGINT
EOSQL
# and here's our code
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Add AutoPlay fields to the Carousel
sub addAutoPlayToCarousel {
my $session = shift;
print "\tAdding Auto Play to Carousel... " unless $quiet;
$session->db->write(
"ALTER TABLE Carousel ADD COLUMN autoPlay INT, ADD COLUMN autoPlayInterval INT"
);
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addProcessorDropdownToSnippet {
my $session = shift;
my $db = $session->db;
print "\tUpdating the Snippet table to add templateProcessor option..."
unless $quiet;
my $rows = $db->buildArrayRefOfHashRefs(q{
select assetId, revisionDate from snippet where processAsTemplate = 1
});
$db->write(q{
alter table snippet
drop column processAsTemplate,
add column templateParser char(255)
});
my $default = $session->config->get('defaultTemplateParser');
for my $row (@$rows) {
$db->write(q{
update snippet
set templateParser = ?
where assetId = ? and revisionDate = ?
}, [ $default, $row->{assetId}, $row->{revisionDate} ]);
}
print "Done!\n";
}
#----------------------------------------------------------------------------
# Describe what our function does
sub addRichEditToCarousel {
my $session = shift;
print "\tAdd RichEdit option to the Carousel... " unless $quiet;
# and here's our code
$session->db->write('ALTER TABLE Carousel ADD COLUMN richEditor CHAR(22) BINARY');
$session->db->write(q!update Carousel set richEditor='PBrichedit000000000001'!);
print "DONE!\n" unless $quiet;
}
sub addRenderThingDataMacro {
my $session = shift;
print "\tAdd the new RenderThingData macro to the site config... " unless $quiet;
$session->config->addToHash('macros', 'RenderThingData', 'RenderThingData');
print "DONE!\n" unless $quiet;
}
sub alterAssetIndexTable {
my $session = shift;
print "\tExtend the assetIndex table so we can search things other than assets... " unless $quiet;
$session->db->write(<<EOSQL);
alter table assetIndex
drop primary key,
add column subId char(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
add primary key (assetId, url)
EOSQL
print "DONE!\n" unless $quiet;
}
sub reindexAllThingys {
my $session = shift;
print "\tReindex all Thingys... " unless $quiet;
use WebGUI::Asset::Wobject::Thingy;
my $get_thingy = WebGUI::Asset::Wobject::Thingy->getIsa($session);
THINGY: while (1) {
my $thingy = eval { $get_thingy->() };
next THINGY if Exception::Class->caught();
last THINGY unless $thingy;
$thingy->indexContent;
}
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addAssetPropertyMacro {
my $session = shift;
my $c = $session->config;
my $hash = $c->get('macros');
unless (grep { $_ eq 'AssetProperty' } values %$hash) {
print "\tAdding AssetProperty macro... " unless $quiet;
$c->set('macros/AssetProperty' => 'AssetProperty');
print "DONE!\n" unless $quiet;
}
}
#----------------------------------------------------------------------------
# Creates new column in tables for Thingy_fields and Thingy_things
sub createThingyDBColumns {
my $session = shift;
print "\tAdding db. columns Thingy_fields.isUnique and Thingy_things.maxEntriesTotal.." unless $quiet;
# and here's our code
my %tfHash = $session->db->quickHash("show columns from Thingy_fields where Field='isUnique'");
my %ttHash = $session->db->quickHash("show columns from Thingy_things where Field='maxEntriesTotal'");
unless ( $tfHash{'Field'}) { $session->db->write("alter table Thingy_fields add isUnique int(1) default 0"); }
unless ( $ttHash{'Field'}) { $session->db->write("alter table Thingy_things add maxEntriesTotal int default null"); }
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addAssetManagerSortPreferences {
my $cn = 'assetManagerSortColumn';
my $on = 'assetManagerSortDirection';
use WebGUI::ProfileField;
unless (WebGUI::ProfileField->new($session, $cn)) {
print 'Adding Asset Manager Sort Column profile field...'
unless $quiet;
WebGUI::ProfileField->create($session, $cn => {
label =>
"WebGUI::International::get('$cn label', 'Account_Profile')",
protected => 1,
fieldType => 'selectBox',
dataDefault => 'lineage',
possibleValues => <<'VALUES',
{
lineage => WebGUI::International::get('rank', 'Asset'),
title => WebGUI::International::get(99, 'Asset'),
className => WebGUI::International::get('type', 'Asset'),
revisionDate => WebGUI::International::get('revision date', 'Asset'),
assetSize => WebGUI::International::get('size', 'Asset'),
lockedBy => WebGUI::International::get('locked', 'Asset'),
}
VALUES
}, 4);
print "Done!\n" unless $quiet;
}
unless (WebGUI::ProfileField->new($session, $on)) {
print 'Adding Asset Manager Sort Direction profile field...'
unless $quiet;
WebGUI::ProfileField->create($session, $on => {
label =>
"WebGUI::International::get('$on label', 'Account_Profile')",
protected => 1,
fieldType => 'selectBox',
dataDefault => 'asc',
possibleValues => <<'VALUES',
{
asc => WebGUI::International::get('ascending', 'Account_Profile'),
desc => WebGUI::International::get('descending', 'Account_Profile'),
}
VALUES
}, 4);
print "Done!\n" unless $quiet;
}
}
#----------------------------------------------------------------------------
# Add a ticket limit to badges in a badge group
sub addTicketLimitToBadgeGroup {
my $session = shift;
print "\tAdd ticket limit to badge groups... " unless $quiet;
# Make sure it hasn't been done already...
my $columns = $session->db->buildHashRef('describe EMSBadgeGroup');
if(! grep { /ticketsPerBadge/ } keys %{$columns}) {
$session->db->write(q{
ALTER TABLE EMSBadgeGroup ADD COLUMN `ticketsPerBadge` INTEGER
});
}
print "DONE!\n" unless $quiet;
}
sub addFormFieldMacroToConfig {
print "\tAdd FormField macro to config... " unless $quiet;
$session->config->addToHash( 'macros', FormField => 'FormField' );
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addWaitForConfirmationWorkflow {
my $session = shift;
my $c = $session->config;
my $exists = $c->get('workflowActivities/WebGUI::User');
my $class = 'WebGUI::Workflow::Activity::WaitForUserConfirmation';
unless (grep { $_ eq $class } @$exists) {
print "Adding WaitForUserConfirmation workflow..." unless $quiet;
$c->addToArray('workflowActivities/WebGUI::User' => $class);
print "Done!\n" unless $quiet;
}
}
#----------------------------------------------------------------------------
sub addCreateUsersEnabledSetting {
my $session = shift;
my $s = $session->setting;
my $name = 'enableUsersAfterAnonymousRegistration';
return if $s->has($name);
print "Adding $name setting..." unless $quiet;
$s->add($name => 1);
print "Done!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Add the Authorize.net payment driver to each config file
sub addAuthorizePaymentDriver {
my $session = shift;
print "\tAdd the Authorize.net payment driver... " unless $quiet;
# and here's our code
$session->config->addToArray('paymentDrivers', 'WebGUI::Shop::PayDriver::CreditCard::AuthorizeNet');
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addLinkedProfileAddress {
my $session = shift;
print "\tAdding linked profile addresses for existing users... " unless $quiet;
my $users = $session->db->buildArrayRef( q{
select userId from users where userId not in ('1','3')
} );
use WebGUI::User;
use WebGUI::Shop::AddressBook;
foreach my $userId (@$users) {
#check to see if there is user profile information available
my $u = WebGUI::User->new($session,$userId);
#skip if user does not have any homeAddress fields filled in
next unless (
$u->profileField("homeAddress")
|| $u->profileField("homeCity")
|| $u->profileField("homeState")
|| $u->profileField("homeZip")
|| $u->profileField("homeCountry")
|| $u->profileField("homePhone")
);
#Get the address book for the user (one is created if it does not exist)
my $addressBook = WebGUI::Shop::AddressBook->newByUserId($session,$userId);
#Add the profile address for the user
$addressBook->addAddress({
label => "Profile Address",
firstName => $u->profileField("firstName"),
lastName => $u->profileField("lastName"),
address1 => $u->profileField("homeAddress"),
city => $u->profileField("homeCity"),
state => $u->profileField("homeState"),
country => $u->profileField("homeCountry"),
code => $u->profileField("homeZip"),
phoneNumber => $u->profileField("homePhone"),
email => $u->profileField("email"),
isProfile => 1,
});
}
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub createAddressField {
my $session = shift;
#skip if field exists
my $columns = $session->db->buildArrayRef("show columns from address where Field='isProfile'");
return if(scalar(@$columns));
print "\tAdding profile link to Address... " unless $quiet;
$session->db->write( q{
alter table address add isProfile tinyint default 0
} );
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;
print "\tUpdating packages.\n" unless ($quiet);
addPackage( $session, 'packages-7.9.34-7.10.22/merged.wgpkg' );
}
#vim:ft=perl

View file

@ -218,6 +218,7 @@
"WebGUI::Shop::PayDriver::ITransact",
"WebGUI::Shop::PayDriver::PayPal::PayPalStd",
"WebGUI::Shop::PayDriver::PayPal::ExpressCheckout",
"WebGUI::Shop::PayDriver::CreditCard::AuthorizeNet",
"WebGUI::Shop::PayDriver::Ogone"
],

View file

@ -1,10 +1,8 @@
package WebGUI;
our $VERSION = '8.0.0';
our $STATUS = 'beta';
=head1 LEGAL
-------------------------------------------------------------------

View file

@ -431,16 +431,67 @@ sub www_editSave {
unless(scalar(@{$retHash->{errors}})) {
my $profile = $retHash->{profile};
my $privacy = {};
$session->user->update($profile);
my $address = {};
my $address_mappings = WebGUI::Shop::AddressBook->getProfileAddressMappings;
foreach my $fieldName (keys %{$profile}) {
#set the shop address fields
my $address_key = $address_mappings->{$fieldName};
$address->{$address_key} = $profile->{ $fieldName } if ($address_key);
#set the privacy settings
my $privacySetting = $session->form->get("privacy_".$fieldName);
next unless $privacySetting;
$privacy->{$fieldName} = $privacySetting;
}
$session->user->setProfileFieldPrivacySetting($privacy);
#Update or create and update the shop address
if ( keys %$address ) {
$address->{'isProfile' } = 1;
#Get the address book for the user (one is created if it does not exist)
my $addressBook = WebGUI::Shop::AddressBook->newByUserId($session,$self->uid);
my $profileAddress = eval { $addressBook->getProfileAddress() };
my $e;
if($e = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) {
#Get home address only mappings to avoid creating addresses with just firstName, lastName, email
my %home_address_map = %{$address_mappings};
foreach my $exclude ( qw{ firstName lastName email } ) {
delete $home_address_map{$exclude};
}
#Add the profile address for the user if there are homeAddress fields
if( grep { $address->{$_} } values %home_address_map ) {
$address->{label} = "Profile Address";
my $new_address = $addressBook->addAddress($address);
#Set this as the default address if one doesn't already exist
my $defaultAddress = eval{ $addressBook->getDefaultAddress };
if(WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) {
$addressBook->update( {
defaultAddressId => $new_address->getId
} );
}
}
}
elsif ($e = WebGUI::Error->caught) {
#Bad stuff happened - log an error but don't fail since this isn't a vital function
$session->log->error(
q{Could not update Shop Profile Address for user }
.$self->username.q{ : }.$e->error
);
}
else {
#Update the profile address for the user
$profileAddress->update($address);
}
}
}
#Store the category the error occurred in the object for reference
$self->store->{selected} = $retHash->{errorCategory};

View file

@ -257,15 +257,17 @@ sub duplicate {
my $self = shift;
my $session = $self->session;
my $copy = $self->SUPER::duplicate(@_);
my $oldGroupId = $self->get('subscriptionGroupId');
my $key = 'subscriptionGroupId';
my $oldGroupId = $self->get($key);
if ($oldGroupId) {
my $newGroup = WebGUI::Group->new($session, 'new');
my $oldGroup = WebGUI::Group->new($session, $oldGroupId);
if ($oldGroup) {
$copy->update({ $key => '' });
$copy->createSubscriptionGroup();
if (my $oldGroup = WebGUI::Group->new($session, $oldGroupId)) {
my $newGroup = WebGUI::Group->new($session, $copy->get($key));
$newGroup->addUsers($oldGroup->getUsers('withoutExpired'));
$newGroup->addGroups($oldGroup->getGroupsIn);
}
$copy->update({subscriptionGroupId => $newGroup->getId});
}
return $copy;
}

View file

@ -592,6 +592,22 @@ sub processStyle {
#-------------------------------------------------------------------
=head2 purge ( )
Extent the base class to clean out any items using this Sku in all Carts.
=cut
sub purge {
my $self = shift;
my $assetId = $self->getId;
my $success = $self->SUPER::purge;
return $success unless $success;
$self->session->db->write('delete from cartItem where assetId=?',[$assetId]);
}
#-------------------------------------------------------------------
=head2 setTaxConfiguration ($namespace, $configuration)
=head3 $namespace

View file

@ -83,6 +83,7 @@ property templateId => (
use JSON;
use WebGUI::International;
use WebGUI::Shop::Admin;
use WebGUI::Shop::AddressBook;
=head1 NAME
@ -204,6 +205,28 @@ sub getMaxAllowedInCart {
return 1;
}
#----------------------------------------------------------------------------
=head2 getPostPurchaseActions ( item )
Return a hash reference of "label" => "url" to do things with this item after
it is purchased. C<item> is the WebGUI::Shop::TransactionItem for this item
=cut
sub getPostPurchaseActions {
my ( $self, $item ) = @_;
my $session = $self->session;
my $opts = $self->SUPER::getPostPurchaseActions();
if($self->getParent->isRegistrationStaff) {
my $i18n = WebGUI::International->new( $session, "Asset_EventManagementSystem" );
my $badgeId = $item->get('options')->{badgeId};
$opts->{ $i18n->get('print') } = $self->getParent->getUrl( "func=printBadge;badgeId=$badgeId" );
}
return $opts;
}
#-------------------------------------------------------------------
=head2 getPrice
@ -404,11 +427,19 @@ sub view {
;
# instanciate address
my $address = WebGUI::Shop::AddressBook->newByUserId($self->session)->getAddress($form->get("addressId")) if ($form->get("addressId"));
my $address = undef;
my $address_book = WebGUI::Shop::AddressBook->newByUserId($self->session);
if ($form->get("addressId")) {
$address = $address_book->getAddress($form->get("addressId"));
}
else {
$address = eval{ $address_book->getDefaultAddress }
}
# build the form that the user needs to fill out with badge holder information
$vars{formHeader} = WebGUI::Form::formHeader($session, {action => $self->getUrl})
. WebGUI::Form::hidden($session, {name=>"func", value =>'addToCart'});
. WebGUI::Form::hidden($session, {name=>"func", value =>'addToCart'})
. WebGUI::Form::hidden($session, {name=>"addressId", value=>(defined $address ? $address->getId : "" )});;
$vars{formFooter} = WebGUI::Form::formFooter($session);
$vars{name} = WebGUI::Form::text($session, {
name => 'name',
@ -457,9 +488,21 @@ sub view {
if($self->getQuantityAvailable() > 0){
$vars{submitAddress} = WebGUI::Form::submit($session, {value => $i18n->get('add to cart'),});
}
$vars{resetButton} = q{<input type="button" value="}.$i18n->get('clear form'). q{" onclick="WebGUI.Form.clearForm(this.form)" />};
$vars{title} = $self->getTitle;
$vars{description} = $self->description;
$vars{search_url } = $self->getUrl("shop=address;method=ajaxSearch");
my $shopAdmin = WebGUI::Shop::Admin->new($session);
my $isStaff = $self->getParent->isRegistrationStaff;
my $canManageShop = $shopAdmin->canManage;
my $isCashier = $shopAdmin->isCashier;
if($isStaff && ($canManageShop || $isCashier)) {
$vars{canSearch} = 1;
}
# render the page;
return $self->processTemplate(\%vars, undef, $self->{_viewTemplate});
}
@ -495,13 +538,46 @@ sub www_addToCart {
if ($badgeInfo{name} eq "") {
$error = sprintf $i18n->get('is required'), $i18n->get('name','Shop');
}
# return them back to the previous screen if they messed up
if ($error) {
$self->{_errorMessage} = $error;
return $self->www_view($error);
}
#check to see if address has changed - if so, create a new address and set it to the default
my $address_id = $form->get("addressId");
if($address_id) {
my $address = undef;
my $address_book = WebGUI::Shop::AddressBook->newByUserId($self->session);
$address = $address_book->getAddress($address_id);
my $has_changes = 0;
my $new_address = {};
foreach my $field_name (qw/name address1 address2 address3 city state country code phoneNumber organization email/) {
my $form_field_name = $field_name;
$form_field_name = "zipcode" if ($field_name eq "code");
if($field_name eq "name") {
if($address->get('firstName')." ".$address->get('lastName') ne $badgeInfo{name}) {
$has_changes = 1;
}
($new_address->{firstName},$new_address->{lastName}) = split(" ",$badgeInfo{name});
next;
}
elsif($address->get($field_name) ne $badgeInfo{$form_field_name}) {
$has_changes = 1;
}
$new_address->{$field_name} = $badgeInfo{$form_field_name};
}
if($has_changes) {
my $address_book = WebGUI::Shop::AddressBook->newByUserId($self->session);
$new_address->{label} = $form->get("label")." New";
my $new_address = $address_book->addAddress($new_address);
$address_book->update({defaultAddressId => $new_address->getId });
}
}
# add it to the cart
$self->addToCart(\%badgeInfo);
return $self->getParent->www_buildBadge($self->getOptions->{badgeId});

View file

@ -2590,9 +2590,10 @@ sub www_printBadge {
my $self = shift;
my $session = $self->session;
return $session->privilege->insufficient unless ($self->isRegistrationStaff);
my $form = $session->form;
my $registrant = $self->getRegistrant($form->get('badgeId'));
my $badge = WebGUI::Asset::Sku::EMSBadge->newById($session, $registrant->{badgeAssetId});
my $form = $session->form;
my $badgeId = $form->get('badgeId');
my $registrant = $self->getRegistrant($badgeId);
my $badge = WebGUI::Asset::Sku::EMSBadge->newById($session, $registrant->{badgeAssetId});
$registrant->{badgeTitle} = $badge->getTitle;
# Add badge metadata
@ -2601,6 +2602,42 @@ sub www_printBadge {
$registrant->{ "badgeMeta_" . $key } = $meta->{ $key };
}
#Add tickets
my @tickets = $session->db->buildArray(
q{select ticketAssetId from EMSRegistrantTicket where badgeId=?},
[$badgeId]
);
$registrant->{ticket_loop} = [];
foreach my $ticketId (@tickets) {
my $ticket = WebGUI::Asset::Sku::EMSTicket->newById($session, $ticketId);
push (@{$registrant->{ticket_loop}}, $ticket->get);
}
#Add ribbons
my @ribbons = $session->db->buildArray(
q{select ribbonAssetId from EMSRegistrantRibbon where badgeId=?},
[$badgeId]
);
$registrant->{ribbon_loop} = [];
foreach my $ribbonId (@ribbons) {
my $ribbon = WebGUI::Asset::Sku::EMSRibbon->newById($session, $ribbonId);
push (@{$registrant->{ribbon_loop}}, $ribbon->get);
}
## Add tokens
my @tokens = $session->db->buildArray(
q{select tokenAssetId from EMSRegistrantToken where badgeId=?},
[$badgeId]
);
$registrant->{token_loop} = [];
foreach my $tokenId (@tokens) {
my $token = WebGUI::Asset::Sku::EMSToken->newById($session, $tokenId);
push (@{$registrant->{token_loop}}, $token->get);
}
return $self->processTemplate($registrant,$self->printBadgeTemplateId);
}

View file

@ -643,7 +643,7 @@ sub editThingDataSave {
}
if ($field->{status} eq "required" && ($fieldValue =~ /^\s$/x || $fieldValue eq "" || !(defined $fieldValue))) {
push (@errors,{
"error_message"=>$field->{label}." ".$i18n->get('is required error').".",
"error_message"=>$field->{label}." ".$i18n->get('is required error').".", "field_name"=>$fieldName,
});
}
if ($field->{status} eq "hidden") {
@ -659,7 +659,7 @@ sub editThingDataSave {
unless ( $self->isUniqueEntry($thingId,$fieldName,$fieldValue,$thingDataId)) {
push (@errors,{
"error_message"=>$field->{label}. $i18n->get('needs to be unique error'),
"error_message"=>$field->{label}. $i18n->get('needs to be unique error'),"field_name"=>$fieldName,
});
}
}

View file

@ -380,7 +380,7 @@ sub www_editMetaDataField {
label=>$i18n->get(486),
hoverHelp=>$i18n->get('Data Type description'),
value=>$fieldInfo->{fieldType} || "text",
types=> [ qw /text integer yesNo selectBox radioList checkList/ ]
types=> [ qw /text integer yesNo selectBox radioList checkList dateTime/ ]
);
my $default = ref WebGUI::Asset->assetName eq 'ARRAY'

View file

@ -20,6 +20,7 @@ use WebGUI::International;
use WebGUI::Asset::Template;
use WebGUI::User;
use WebGUI::Workflow::Instance;
use WebGUI::Shop::AddressBook;
use WebGUI::Inbox;
use WebGUI::Friends;
use WebGUI::Deprecate;
@ -910,9 +911,6 @@ sub www_createAccountSave {
my $userId = $u->userId;
$u->username($username);
$u->authMethod($self->authMethod);
$self->session->log->info( " override: " . $self->session->scratch->getLanguageOverride );
use Data::Dumper;
$self->session->log->info( Dumper $profile );
if (!$profile->{'language'} && $self->session->scratch->getLanguageOverride) {
$profile->{'language'} = $self->session->scratch->getLanguageOverride;
@ -921,6 +919,34 @@ sub www_createAccountSave {
$u->updateProfileFields($profile) if ($profile);
$self->update($properties);
my $address = {};
my $address_mappings = WebGUI::Shop::AddressBook->getProfileAddressMappings;
foreach my $fieldId (keys %$profile) {
#set the shop address fields
my $address_key = $address_mappings->{$fieldId};
$address->{$address_key} = $profile->{$fieldId} if ($address_key);
}
#Update or create and update the shop address
if ( keys %$address ) {
$address->{'isProfile' } = 1;
#Get home address only mappings to avoid creating addresses with just firstName, lastName, email
my %home_address_map = %{$address_mappings};
foreach my $exclude ( qw{ firstName lastName email } ) {
delete $home_address_map{$exclude};
}
#Add the profile address for the user if there are homeAddress fields
if( grep { $address->{$_} } values %home_address_map ) {
#Create the address book for the user
my $addressBook = WebGUI::Shop::AddressBook->newByUserId($self->session,$userId);
$address->{label} = "Profile Address";
my $new_address = $addressBook->addAddress($address);
#Set this as the default address if one doesn't already exist
$addressBook->update( { defaultAddressId => $new_address->getId } );
}
}
if ($self->getSetting("sendWelcomeMessage")){
my $var;
$var->{welcomeMessage} = $self->getSetting("welcomeMessage");

View file

@ -40,7 +40,25 @@ The following methods are specifically available from this class. Check the supe
=cut
#-------------------------------------------------------------------
=head2 definition ( session, [ additionalTerms ] )
Add another field so we can provide extras to the text area vs the selectBox
=cut
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift || [];
push(@{$definition}, {
textExtras=>{
defaultValue=>undef
},
});
return $class->SUPER::definition($session, $definition);
}
#-------------------------------------------------------------------
@ -127,7 +145,8 @@ sub toHtml {
.WebGUI::Form::Text->new($self->session,
size=>$self->session->setting->get("textBoxSize")-5,
name=>$self->get("name")."_new",
id=>$self->get('id')."_new"
id=>$self->get('id')."_new",
extras=>$self->get('textExtras'),
)->toHtml;
}

View file

@ -234,7 +234,7 @@ sub getValue {
=head2 getDefaultValue ( )
Returns the either the "value" ore "defaultValue" passed in to the object in that order, and doesn't take into account form processing.
Returns the either the "value" or "defaultValue" passed in to the object in that order, and doesn't take into account form processing.
=cut
@ -259,7 +259,7 @@ sub getDefaultValue {
=head2 getOriginalValue ( )
Returns the either the "value" ore "defaultValue" passed in to the object in that order, and doesn't take into account form processing.
Returns the either the "value" or "defaultValue" passed in to the object in that order, and doesn't take into account form processing.
=cut

View file

@ -109,7 +109,7 @@ sub getValue {
=head2 getDefaultValue ( )
Returns the either the "value" ore "defaultValue" passed in to the object in that order, and doesn't take into account form processing.
Returns the either the "value" or "defaultValue" passed in to the object in that order, and doesn't take into account form processing.
=cut
@ -124,7 +124,7 @@ sub getDefaultValue {
=head2 getOriginalValue ( )
Returns the either the "value" ore "defaultValue" passed in to the object in that order, and doesn't take into account form processing.
Returns the either the "value" or "defaultValue" passed in to the object in that order, and doesn't take into account form processing.
=cut

View file

@ -419,7 +419,11 @@ sub processReplacements {
}
foreach my $searchFor (keys %{$replacements}) {
my $replaceWith = $replacements->{$searchFor};
$content =~ s/\b\Q$searchFor\E\b/$replaceWith/gs;
my $pattern = qr/\Q$searchFor\E/;
if ($searchFor =~ /^\w+/) {
$pattern = qr/\b$pattern\b/;
}
$content =~ s/$pattern/$replaceWith/gs;
}
return $content;
}

View file

@ -790,7 +790,7 @@ sub www_editUser {
size=>15,
value=>\@groupsToDelete
);
return '<h1>' . $i18n->get(168) . '</h1>' . $f->toHtml;
return '<h1>' . $i18n->get(168) . '</h1>' . $error . $f->toHtml;
}
#-------------------------------------------------------------------
@ -818,7 +818,7 @@ sub www_editUserSave {
return $session->privilege->adminOnly() unless ($isAdmin || $isSecondary) && $session->form->validToken;
# Check to see if
# Check to see if
# 1) the userId associated with the posted username matches the posted userId (we're editing an account)
# or that the userId is new and the username selected is unique (creating new account)
# or that the username passed in isn't assigned a userId (changing a username)
@ -829,11 +829,11 @@ sub www_editUserSave {
my $postedUsername = $session->form->process("username");
$postedUsername = WebGUI::HTML::filter($postedUsername, "all");
if (($existingUserId eq $postedUserId || ($postedUserId eq "new" && !$existingUserId) || $existingUserId eq '')
if (($existingUserId eq $postedUserId || ($postedUserId eq "new" && !$existingUserId) || $existingUserId eq '')
&& $postedUsername ne '')
{
# Create a user object with the id passed in. If the Id is 'new', the new method will return a new user,
# otherwise return the existing users properties
# Create a user object with the id passed in. If the Id is 'new', the new method will return a new user,
# otherwise return the existing users properties
my $u = WebGUI::User->new($session,$postedUserId);
$actualUserId = $u->userId;
@ -851,10 +851,59 @@ sub www_editUserSave {
}
# Loop through all profile fields, and update them with new values.
foreach my $field (@{WebGUI::ProfileField->getFields($session)}) {
my $address = {};
my $address_mappings = WebGUI::Shop::AddressBook->getProfileAddressMappings;
foreach my $field (@{WebGUI::ProfileField->getFields($session)}) {
next if $field->getId =~ /contentPositions/;
$u->profileField($field->getId,$field->formProcess($u));
my $field_value = $field->formProcess($u);
$u->update({ $field->getId => $field_value} );
#set the shop address fields
my $address_key = $address_mappings->{$field->getId};
$address->{$address_key} = $field_value if ($address_key);
}
#Update or create and update the shop address
if ( keys %$address ) {
$address->{'isProfile' } = 1;
#Get the address book for the user (one is created if it does not exist)
my $addressBook = WebGUI::Shop::AddressBook->newByUserId($session, $actualUserId,);
my $profileAddress = eval { $addressBook->getProfileAddress() };
my $e;
if($e = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) {
#Get home address only mappings to avoid creating addresses with just firstName, lastName, email
my %home_address_map = %{$address_mappings};
delete $home_address_map{qw/firstName lastName email/};
#Add the profile address for the user if there are homeAddress fields
if( grep { $address->{$_} } values %home_address_map ) {
$address->{label} = "Profile Address";
my $new_address = $addressBook->addAddress($address);
#Set this as the default address if one doesn't already exist
my $defaultAddress = eval{ $addressBook->getDefaultAddress };
if(WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) {
$addressBook->update( {
defaultAddressId => $new_address->getId
} );
}
else {
$session->log->warn("The default address exists, and it should not.");
}
}
}
elsif ($e = WebGUI::Error->caught) {
#Bad stuff happened - log an error but don't fail since this isn't a vital function
$session->log->error(
q{Could not update Shop Profile Address for user }
.$u->username.q{ : }.$e->error
);
}
else {
#Update the profile address for the user
$profileAddress->update($address);
}
}
# Update group assignements
my @groups = $session->form->group("groupsToAdd");

View file

@ -88,6 +88,11 @@ property "addressBookId" => (
required => 1,
);
property "isProfile" => (
noFormPost => 1,
required => 0,
);
has [ qw/addressId addressBook/] => (
is => 'ro',
required => 1,
@ -196,6 +201,10 @@ An email address for this user.
The organization or company that this user is a part of.
=head4 isProfile
Whether or not this address is linked to the user profile. Defaults to 0
=cut
@ -357,5 +366,4 @@ sub write {
$book->session->db->setRow("address","addressId",$properties);
}
1;

View file

@ -26,6 +26,7 @@ require WebGUI::Asset::Template;
use WebGUI::Exception::Shop;
use WebGUI::Form;
use WebGUI::International;
use WebGUI::Shop::Admin;
use WebGUI::Shop::Address;
use Scalar::Util qw/blessed/;
@ -101,7 +102,7 @@ around BUILDARGS => sub {
}
my ($addressBookId) = $class->_init($session);
$properties->{addressBookId} = $addressBookId;
$properties->{userId} = $session->user->userId;
$properties->{userId} ||= $session->user->userId;
return $class->$orig($properties);
}
my $session = shift;
@ -369,6 +370,55 @@ sub getDefaultAddress {
#-------------------------------------------------------------------
=head2 getProfileAddress ()
Returns the profile address for this address book if there is one. Otherwise throws a WebGUI::Error::ObjectNotFound exception.
=cut
sub getProfileAddress {
my ($self) = @_;
my $id = $self->session->db->quickScalar(q{ select addressId from address where addressBookId=? and isProfile=1 },[$self->getId]);
if (!$id) {
WebGUI::Error::ObjectNotFound->throw(error=>"No profile address.");
}
my $address = eval { $self->getAddress($id) };
my $e;
if ($e = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) {
$e->rethrow;
}
elsif ($e = WebGUI::Error->caught) {
$e->rethrow;
}
else {
return $address;
}
}
#-------------------------------------------------------------------
=head2 getProfileAddressMappings ( )
Class or object method which returns the profile address field mappings
=cut
sub getProfileAddressMappings {
return {
homeAddress => 'address1',
homeCity => 'city',
homeState => 'state',
homeZip => 'code',
homeCountry => 'country',
homePhone => 'phoneNumber',
email => 'email',
firstName => 'firstName',
lastName => 'lastName'
}
}
#-------------------------------------------------------------------
=head2 getId ()
Returns the unique id for this addressBook.
@ -458,7 +508,9 @@ sub newByUserId {
}
else {
# nope create one for the user
return $class->new($session);
my $book = $class->new({session => $session, userId => $userId});
$book->write;
return $book
}
}
@ -481,19 +533,19 @@ sub processAddressForm {
$prefix ||= '';
my $form = $self->session->form;
my %addressData = (
label => $form->get($prefix . "label"),
firstName => $form->get($prefix . "firstName"),
lastName => $form->get($prefix . "lastName"),
address1 => $form->get($prefix . "address1"),
address2 => $form->get($prefix . "address2"),
address3 => $form->get($prefix . "address3"),
city => $form->get($prefix . "city"),
state => $form->get($prefix . "state"),
code => $form->get($prefix . "code", "zipcode"),
country => $form->get($prefix . "country", "country"),
phoneNumber => $form->get($prefix . "phoneNumber", "phone"),
email => $form->get($prefix . "email", "email"),
organization => $form->get($prefix . "organization"),
label => $form->get($prefix . "label") || '',
firstName => $form->get($prefix . "firstName") || '',
lastName => $form->get($prefix . "lastName") || '',
address1 => $form->get($prefix . "address1") || '',
address2 => $form->get($prefix . "address2") || '',
address3 => $form->get($prefix . "address3") || '',
city => $form->get($prefix . "city") || '',
state => $form->get($prefix . "state") || '',
code => $form->get($prefix . "code", "zipcode") || '',
country => $form->get($prefix . "country", "country") || '',
phoneNumber => $form->get($prefix . "phoneNumber", "phone") || '',
email => $form->get($prefix . "email", "email") || '',
organization => $form->get($prefix . "organization") || '',
);
##Label is optional in the form, but required for the UI and API.
@ -559,6 +611,80 @@ sub www_ajaxSave {
#-------------------------------------------------------------------
=head2 www_ajaxSearch ( )
Gets a JSON object with addresses returned based on the search
parameters from the form.
=cut
sub www_ajaxSearch {
my $self = shift;
my $session = $self->session;
my $form = $session->form;
my $name = $form->get('name');
my $fields = {
firstName => (split(" ",$name))[0] || "",
lastName => (split(" ",$name))[1] || "",
organization => $form->get('organization') || "",
address1 => $form->get('address1') || "",
address2 => $form->get('address2') || "",
address3 => $form->get('address3') || "",
city => $form->get('city') || "",
state => $form->get('state') || "",
code => $form->get('zipcode') || "",
country => $form->get('country') || "",
email => $form->get('email') || "",
phoneNumber => $form->get('phone') || "",
};
my $clause = [];
my $params = [];
foreach my $field (keys %$fields) {
my $field_value = $fields->{$field};
if($field_value) {
$field = $session->db->dbh->quote_identifier($field);
$field_value = $field_value."%";
push(@$clause,qq{$field like ?});
push(@$params,$field_value);
}
}
my $admin = WebGUI::Shop::Admin->new($session);
unless ($session->user->isAdmin || $admin->canManage || $admin->isCashier) {
push(@$clause,qq{users.userId=?});
push(@$params,$session->user->getId);
}
my $where = "";
$where = "where ".join(" and ",@$clause) if scalar(@$clause);
my $query = qq{
select
address.*,
users.username
from
address
join addressBook on address.addressBookId = addressBook.addressBookId
join users on addressBook.userId = users.userId
$where
limit 3
};
my $sth = $session->db->read($query,$params);
my $var = [];
while (my $hash = $sth->hashRef) {
push(@$var,$hash);
}
$session->http->setMimeType('text/plain');
return JSON->new->encode($var);
}
#-------------------------------------------------------------------
=head2 www_deleteAddress ( )
Deletes an address from the book.
@ -567,7 +693,10 @@ Deletes an address from the book.
sub www_deleteAddress {
my $self = shift;
$self->getAddress($self->session->form->get("addressId"))->delete;
my $address = $self->getAddress($self->session->form->get("addressId"));
if (defined $address && !$address->isProfile) {
$address->delete;
}
return $self->www_view;
}
@ -726,8 +855,20 @@ sub www_editAddressSave {
$self->addAddress(\%addressData);
}
else {
$self->getAddress($form->get('addressId'))->update(\%addressData);
my $addressId = $form->get('addressId');
my $address = $self->getAddress($addressId);
$address->update(\%addressData);
if($address->isProfile) {
my $u = WebGUI::User->new($self->session, $self->get("userId"));
my $address_mappings = $self->getProfileAddressMappings;
foreach my $field (keys %$address_mappings) {
my $addr_field = $address_mappings->{$field};
$u->profileField($field,$address->get($addr_field));
}
}
}
#profile fields updated in WebGUI::Shop::Address->update
return $self->www_view;
}
@ -758,12 +899,12 @@ sub www_view {
return $self->www_editAddress;
}
foreach my $address (@availableAddresses) {
push(@addresses, {
%{$address->get},
address => $address->getHtmlFormatted,
isDefault => ($self->get('defaultAddressId') eq $address->getId),
deleteButton =>
WebGUI::Form::formHeader( $session )
deleteButton => $address->get("isProfile") ? undef : WebGUI::Form::formHeader( $session )
. WebGUI::Form::hidden( $session, { name => 'shop', value => 'address' } )
. WebGUI::Form::hidden( $session, { name => 'method', value => 'deleteAddress' } )
. WebGUI::Form::hidden( $session, { name => 'addressId', value => $address->getId } )

View file

@ -766,8 +766,11 @@ sub requiresShipping {
my $self = shift;
# Look for recurring items in the cart
foreach my $item (@{ $self->getItems }) {
return 1 if $item->getSku->isShippingRequired;
ITEM: foreach my $item (@{ $self->getItems }) {
my $sku = $item->getSku;
next ITEM unless $sku;
return 1 if $sku->isShippingRequired;
}
# No recurring items in cart so return false
@ -1113,6 +1116,13 @@ sub www_view {
$self->update({shippingAddressId=>''});
}
#get the billing address
my $billingAddress = eval { $self->getBillingAddress };
if (my $e = WebGUI::Error->caught("WebGUI::Error::ObjectNotFound") && $self->get('billingAddressId')) {
# choose another address cuz we've got a problem
$self->update({billingAddressId=>''});
}
# generate template variables for the items in the cart
my @items = ();
tie my %addressOptions, 'Tie::IxHash';
@ -1274,9 +1284,11 @@ sub www_view {
$addressBook->appendAddressFormVars(\%var, 'shipping_', $shippingAddressData);
$addressBook->appendAddressFormVars(\%var, 'billing_', $billingAddressData);
my $has_billing_addr = $self->get('billingAddressId') ? 1 : 0;
$var{sameShippingAsBilling} = WebGUI::Form::yesNo($session, {
name => 'sameShippingAsBilling',
value => $self->billingAddressId && $self->billingAddressId eq $self->shippingAddressId,
value => (($has_billing_addr && $self->billingAddressId eq $self->shippingAddressId) || !$has_billing_addr),
});
}

View file

@ -0,0 +1,240 @@
package WebGUI::Shop::PayDriver::CreditCard;
use strict;
use Readonly;
=head1 NAME
WebGUI::Shop::PayDriver::CreditCard
=head2 DESCRIPTION
A base class for credit card payment drivers. They all need pretty much the
same information, the only difference is the servers you talk to. Leaves you
to handle recurring payments, processPayment, www_edit, and whatever else you
want to - but the user-facing code is pretty much taken care of.
=head2 METHODS
The following methods are available from this class.
=cut
use base qw/WebGUI::Shop::PayDriver/;
Readonly my $I18N => 'PayDriver_CreditCard';
#-------------------------------------------------------------------
sub _monthYear {
my $session = shift;
my $form = $session->form;
tie my %months, "Tie::IxHash";
tie my %years, "Tie::IxHash";
%months = map { sprintf( '%02d', $_ ) => sprintf( '%02d', $_ ) } 1 .. 12;
%years = map { $_ => $_ } 2004 .. 2099;
my $monthYear =
WebGUI::Form::selectBox( $session, {
name => 'expMonth',
options => \%months,
value => [ $form->process("expMonth") ]
})
. " / "
. WebGUI::Form::selectBox( $session, {
name => 'expYear',
options => \%years,
value => [ $form->process("expYear") ]
});
return $monthYear;
}
#-------------------------------------------------------------------
=head2 appendCredentialVars
Add template vars for www_getCredentials. Override this to add extra fields.
=cut
sub appendCredentialVars {
my ($self, $var) = @_;
my $session = $self->session;
my $u = $session->user;
my $form = $session->form;
my $i18n = WebGUI::International->new($session, $I18N);
$var->{formHeader} = WebGUI::Form::formHeader($session)
. $self->getDoFormTags('pay');
$var->{formFooter} = WebGUI::Form::formFooter();
my @fieldLoop;
# Credit card information
$var->{cardNumberField} = WebGUI::Form::text($session, {
name => 'cardNumber',
value => $self->session->form->process("cardNumber"),
});
$var->{monthYearField} = WebGUI::Form::readOnly($session, {
value => _monthYear( $session ),
});
$var->{cvv2Field} = WebGUI::Form::integer($session, {
name => 'cvv2',
value => $self->session->form->process("cvv2"),
}) if $self->get('useCVV2');
$var->{checkoutButton} = WebGUI::Form::submit($session, {
value => $i18n->get('checkout button', 'Shop'),
});
return;
}
#-------------------------------------------------------------------
sub definition {
my ($class, $session, $definition) = @_;
my $i18n = WebGUI::International->new($session, $I18N);
tie my %fields, 'Tie::IxHash', (
useCVV2 => {
fieldType => 'yesNo',
label => $i18n->get('use cvv2'),
hoverHelp => $i18n->get('use cvv2 help'),
},
credentialsTemplateId => {
fieldType => 'template',
label => $i18n->get('credentials template'),
hoverHelp => $i18n->get('credentials template help'),
namespace => 'Shop/Credentials',
defaultValue => 'itransact_credentials1',
},
);
push @{ $definition }, {
name => 'Credit Card Base Class',
properties => \%fields,
};
return $class->SUPER::definition($session, $definition);
}
#-------------------------------------------------------------------
=head2 processCredentials
Process the form where credentials (name, address, phone number and credit card information)
are entered.
=cut
sub processCredentials {
my $self = shift;
my $session = $self->session;
my $form = $session->form;
my $i18n = WebGUI::International->new($session, $I18N);
my @error;
# Check credit card data
push @error, $i18n->get( 'invalid card number' ) unless $form->integer('cardNumber');
push @error, $i18n->get( 'invalid cvv2' ) if ($self->get('useCVV2') && !$form->integer('cvv2'));
# Check if expDate and expYear have sane values
my ($currentYear, $currentMonth) = $self->session->datetime->localtime;
my $expires = $form->integer( 'expYear' ) . sprintf '%02d', $form->integer( 'expMonth' );
my $now = $currentYear . sprintf '%02d', $currentMonth;
push @error, $i18n->get('invalid expiration date') unless $expires =~ m{^\d{6}$};
push @error, $i18n->get('expired expiration date') unless $expires >= $now;
return \@error if scalar @error;
# Everything ok process the actual data
$self->{ _cardData } = {
acct => $form->integer( 'cardNumber' ),
expMonth => $form->integer( 'expMonth' ),
expYear => $form->integer( 'expYear' ),
cvv2 => $form->integer( 'cvv2' ),
};
return;
}
#-------------------------------------------------------------------
=head2 www_getCredentials ( $errors )
Build a templated form for asking the user for their credentials.
=head3 $errors
An array reference of errors to show the user.
=cut
sub www_getCredentials {
my $self = shift;
my $errors = shift;
my $session = $self->session;
my $form = $session->form;
my $i18n = WebGUI::International->new($session, $I18N);
my $var = {};
# Process form errors
$var->{errors} = [];
if ($errors) {
$var->{error_message} = $i18n->get('error occurred message');
foreach my $error (@{ $errors} ) {
push @{ $var->{errors} }, { error => $error };
}
}
$self->appendCredentialVars($var);
$self->appendCartVariables($var);
my $template = WebGUI::Asset::Template->new($session, $self->get("credentialsTemplateId"));
my $output;
if (defined $template) {
$template->prepare;
$output = $template->process($var);
}
else {
$output = $i18n->get('template gone');
}
return $session->style->userStyle($output);
}
#-------------------------------------------------------------------
=head2 www_pay
Makes sure that the user has all the requirements for checking out, including
getting credentials, it processes the transaction and then displays a thank
you screen.
=cut
sub www_pay {
my $self = shift;
my $session = $self->session;
# Check whether the user filled in the checkout form and process those.
my $credentialsErrors = $self->processCredentials;
# Go back to checkout form if credentials are not ok
return $self->www_getCredentials( $credentialsErrors ) if $credentialsErrors;
# Payment time!
my $transaction = $self->processTransaction( );
if ($transaction->get('isSuccessful')) {
return $transaction->thankYou();
}
# Payment has failed...
return $self->displayPaymentError($transaction);
}
1;

View file

@ -0,0 +1,267 @@
package WebGUI::Shop::PayDriver::CreditCard::AuthorizeNet;
use strict;
use base qw/WebGUI::Shop::PayDriver::CreditCard/;
use DateTime;
use Readonly;
use Business::OnlinePayment;
Readonly my $I18N => 'PayDriver_AuthorizeNet';
=head1 NAME
WebGUI::Shop::PayDriver::CreditCard::AuthorizeNet
=head1 DESCRIPTION
Payment driver that uses Business::OnlinePayment to process transactions
through Authorize.net
=head1 SYNOPSIS
# in webgui config file...
"paymentDrivers" : [
"WebGUI::Shop::PayDriver::Cash",
"WebGUI::Shop::PayDriver::CreditCard::AuthorizeNet",
...
],
=head1 METHODS
The following methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 appendCredentialVars ( var )
Overridden to add the card type field
=cut
sub appendCredentialVars {
my ( $self, $var ) = @_;
my $session = $self->session;
my $i18n = WebGUI::International->new( $session, $I18N );
$self->SUPER::appendCredentialVars($var);
$var->{cardTypeField} = WebGUI::Form::selectBox(
$session, {
name => 'cardType',
options => { map { $_ => $_ } ( 'Visa', 'MasterCard', 'American Express', 'Discover', ) },
}
);
return;
} ## end sub appendCredentialVars
#-------------------------------------------------------------------
=head2 cancelRecurringPayment ( transaction )
Cancels a recurring transaction. Returns an array containing ( isSuccess, gatewayStatus, gatewayError).
=head3 transaction
The instanciated recurring transaction object.
=cut
sub cancelRecurringPayment {
my ( $self, $transaction ) = @_;
my $session = $self->session;
my $tx = $self->gatewayObject;
$tx->content(
subscription => $transaction->get('transactionCode'),
login => $self->get('login'),
password => $self->get('transaction_key'),
action => 'Cancel Recurring Authorization',
);
$tx->submit;
return $self->gatewayResponse($tx);
}
#-------------------------------------------------------------------
sub definition {
my ( $class, $session, $definition ) = @_;
my $i18n = WebGUI::International->new( $session, $I18N );
tie my %fields, 'Tie::IxHash', (
login => {
fieldType => 'text',
label => $i18n->get('login'),
hoverHelp => $i18n->get('login help'),
},
transaction_key => {
fieldType => 'text',
label => $i18n->get('transaction key'),
hoverHelp => $i18n->get('transaction key help'),
},
testMode => {
fieldType => 'YesNo',
label => $i18n->get('test mode'),
hoverHelp => $i18n->get('test mode help'),
},
);
push @{$definition}, {
name => $i18n->get('name'),
properties => \%fields,
};
return $class->SUPER::definition( $session, $definition );
} ## end sub definition
#-------------------------------------------------------------------
=head2 gatewayObject ( params )
Returns a Business::OnlinePayment object, possibly with options set from the
paydriver properties. params can be a hashref of the options that would
normally be passed to tx->content, in which case these will be passed along.
=cut
sub gatewayObject {
my ( $self, $params ) = @_;
my $tx = Business::OnlinePayment->new('AuthorizeNet');
if ( $self->get('testMode') ) {
# Yes, we need to do both these things. The BOP interfaces tend to
# ony honor one or the other of them.
$tx->test_transaction(1);
$tx->server('test.authorize.net');
}
$tx->content(%$params) if $params;
return $tx;
}
#-------------------------------------------------------------------
=head2 gatewayResponse ( tx )
Returns the various responses required by the PayDriver interface from the
passed Business::OnlinePayment object.
=cut
sub gatewayResponse {
my ( $self, $tx ) = @_;
return ( $tx->is_success, $tx->order_number, $tx->result_code, $tx->error_message );
}
#-------------------------------------------------------------------
sub handlesRecurring {1}
#-------------------------------------------------------------------
=head2 paymentParams
Returns a hashref of the billing address and card information, translated into
a form that Business::OnlinePayment likes
=cut
sub paymentParams {
my $self = shift;
my $card = $self->{_cardData};
my $bill = $self->getCart->getBillingAddress->get();
my %params = (
type => $card->{type},
login => $self->get('login'),
transaction_key => $self->get('transaction_key'),
first_name => $bill->{firstName},
last_name => $bill->{lastName},
address => $bill->{address1},
city => $bill->{city},
state => $bill->{state},
zip => $bill->{code},
card_number => $card->{acct},
expiration => sprintf '%2d/%2d',
@{$card}{ 'expMonth', 'expYear' },
);
$params{cvv2} = $card->{cvv2} if $self->get('useCVV2');
return \%params;
} ## end sub paymentParams
#-------------------------------------------------------------------
sub processCredentials {
my $self = shift;
my $session = $self->session;
my $i18n = WebGUI::International->new( $session, $I18N );
my $error = $self->SUPER::processCredentials;
my $type = $session->form->process('cardType');
unless ($type) {
$error ||= [];
push @$error, $i18n->get('invalid cardType');
}
return $error if defined $error;
$self->{_cardData}->{type} = $type;
return;
} ## end sub processCredentials
#-------------------------------------------------------------------
sub processPayment {
my ( $self, $transaction ) = @_;
my $params = $self->paymentParams;
if ( $transaction->isRecurring ) {
my $items = $transaction->getItems;
if ( @$items > 1 ) {
WebGUI::Error::InvalidParam->throw(
error => 'This payment gateway can only handle one recurring item at a time' );
}
my $item = $items->[0];
my $sku = $item->getSku;
my %translateInterval = (
Weekly => '7 days',
BiWeekly => '14 days',
FourWeekly => '28 days',
Monthly => '1 month',
Quarterly => '3 months',
HalfYearly => '6 months',
Yearly => '12 months',
);
# BOP::AuthorizeNet::ARB has an API that's inconsistant with the AIM
# api -- it wants password instead of transaction_key. Go figure.
$params->{password} = delete $params->{transaction_key};
$params->{action} = 'Recurring Authorization';
$params->{interval} = $translateInterval{ $sku->getRecurInterval };
$params->{start} = DateTime->today->ymd;
$params->{periods} = '9999'; # magic value that means 'never stop'
$params->{description} = $item->get('configuredTitle');
} ## end if ( $transaction->isRecurring)
else {
$params->{action} = 'Normal Authorization';
}
$params->{amount} = $transaction->get('amount');
my $tx = $self->gatewayObject($params);
$tx->submit;
return $self->gatewayResponse($tx);
} ## end sub processPayment
1;

View file

@ -1475,8 +1475,8 @@ sub update {
delete $properties->{privacyFields};
# $self->{_user} contains all fields in `users` table
my @userFields = ();
my @userValues = ();
my @userFields = ();
my @userValues = ();
for my $key ( keys %{$self->{_user}} ) {
if ( exists $properties->{$key} ) {
# Delete the value because it's not a profile field
@ -1487,15 +1487,16 @@ sub update {
}
}
# No matter what we update properties
my $userFields = join ", ", @userFields;
my $userFields = join ", ", @userFields;
$db->write(
"UPDATE users SET $userFields WHERE userId=?",
[@userValues, $self->{_userId}]
);
# Everything else must be a profile field
my @profileFields = ();
my @profileValues = ();
my @profileFields = ();
my @profileValues = ();
for my $key ( keys %{$properties} ) {
if (!exists $self->{_profile}{$key} && !WebGUI::ProfileField->exists($session,$key)) {
$self->session->log->warn("No such profile field: $key");
@ -1506,7 +1507,7 @@ sub update {
$self->{_profile}->{$key} = $properties->{ $key };
}
if ( @profileFields ) {
my $profileFields = join ", ", @profileFields;
my $profileFields = join ", ", @profileFields;
$db->write(
"UPDATE userProfileData SET $profileFields WHERE userId=?",
[@profileValues, $self->{_userId}]

View file

@ -2307,6 +2307,12 @@ normal templates.|,
context => q{Error message when trying to add too many tickets to a badge},
},
'clear form' => {
message => q|Clear|,
lastUpdated => 0,
context => q|a button on the add badge to clear the form|,
},
};
1;

View file

@ -0,0 +1,50 @@
package WebGUI::i18n::English::PayDriver_AuthorizeNet;
use strict;
our $I18N = {
'cardType' => {
message => q{Card Type},
lastUpdated => 1101772177,
context => q{Form label in the checkout form of the AuthorizeNet module.},
},
'login' => {
message => q{API Login},
lastUpdated => 1247613128,
context => q{Form label in the configuration form of the AuthorizeNet module.},
},
'login help' => {
message => q{The API login id for your Authorize.net account},
lastUpdated => 1247613146,
context => q{Hover help for the login field of the AuthorizeNet module},
},
'name' => {
message => q{Credit Card (Authorize.net)},
lastUpdated => 0,
context => q{Name of the Authorize.net module},
},
'test mode' => {
message => q{Test Mode},
lastUpdated => 0,
context => q{Form label for test mode toggle in AuthroizeNet module},
},
'test mode help' => {
message => q{Whether calls using this gateway should be made in test mode},
lastUpdated => 0,
context => q{Hover help for test mode form field},
},
'transaction key' => {
message => q{Transaction Key},
lastUpdated => 1247613060,
context => q{Form label in the configuration form of the AuthorizeNet module.},
},
'transaction key help' => {
message => q{The Transaction Key for your Authorize.net account},
lastUpdated => 1247613119,
context => q{Hover help for the password field of the AuthorizeNet module},
},
};
1;
#vim:ft=perl

View file

@ -0,0 +1,161 @@
package WebGUI::i18n::English::PayDriver_CreditCard;
use strict;
our $I18N = {
'cardNumber' => {
message => q|Credit card number|,
lastUpdated => 1101772177,
context => q|Form label in the checkout form of the Credit Card module.|
},
'credentials template' => {
message => q|Credentials Template|,
lastUpdated => 0,
context => q|Form label in the configuration form of the Credit Card module.|
},
'credentials template help' => {
message => q|Pick a template to display the form where the user will enter in their billing information and credit card information.|,
lastUpdated => 0,
context => q|Hover help for the credentials template field in the configuration form of the Credit Card module.|
},
'cvv2' => {
message => q|Verification number (ie. CVV2)|,
lastUpdated => 1101772182,
context => q|Form label in the checkout form of the Credit Card module.|
},
'error occurred message' => {
message => q|The following errors occurred:|,
lastUpdated => 0,
context => q|The message that tell the user that there were some errors in their submitted credentials.|,
},
'expiration date' => {
message => q|Expiration date|,
lastUpdated => 1101772180,
context => q|Form label in the checkout form of the Credit Card module.|
},
'expired expiration date' => {
message => q|The expiration date on your card has already passed.|,
lastUpdated => 0,
context => q|An error indicating that an an expired card was used.|
},
'invalid firstName' => {
message => q|You have to enter a valid first name.|,
lastUpdated => 0,
context => q|An error indicating that an invalid first name has been entered.|
},
'invalid lastName' => {
message => q|You have to enter a valid last name.|,
lastUpdated => 0,
context => q|An error indicating that an invalid last name has been entered.|
},
'invalid address' => {
message => q|You have to enter a valid address.|,
lastUpdated => 0,
context => q|An error indicating that an invalid street has been entered.|
},
'invalid city' => {
message => q|You have to enter a valid city.|,
lastUpdated => 0,
context => q|An error indicating that an invalid city has been entered.|
},
'invalid zip' => {
message => q|You have to enter a valid zipcode.|,
lastUpdated => 0,
context => q|An error indicating that an invalid zipcode has been entered.|
},
'invalid email' => {
message => q|You have to enter a valid email address.|,
lastUpdated => 0,
context => q|An error indicating that an invalid email address has been entered.|
},
'invalid card number' => {
message => q|You have to enter a valid credit card number.|,
lastUpdated => 0,
context => q|An error indicating that an invalid credit card number has been entered.|
},
'invalid cvv2' => {
message => q|You have to enter a valid card security code (ie. cvv2).|,
lastUpdated => 0,
context => q|An error indicating that an invalid card security code has been entered.|
},
'invalid expiration date' => {
message => q|You have to enter a valid expiration date.|,
lastUpdated => 0,
context => q|An error indicating that an invalid expiration date has been entered.|
},
'template gone' => {
message => q|The template for entering in credentials has been deleted. Please notify the site administrator.|,
lastUpdated => 0,
context => q|Error message when the getCredentials template cannot be accessed.|
},
'use cvv2' => {
message => q|Use CVV2|,
lastUpdated => 0,
context => q|Form label in the configuration form of the Credit Card module.|
},
'use cvv2 help' => {
message => q|Set this option to yes if you want to use CVV2.|,
lastUpdated => 0,
context => q|Form label in the configuration form of the Credit Card module.|
},
'edit credentials template' => {
message => q|Edit Credentials Template|,
lastUpdated => 0,
context => q|Title of the help page.|
},
'edit credentials template help' => {
message => q|This template is used to display a form to the user where they can enter in contact and credit card billing information.|,
lastUpdated => 0,
context => q|Title of the help page.|
},
'errors help' => {
message => q{A template loop containing a list of errors from processing the form.},
lastUpdated => 0,
context => q{Template variable help.},
},
'error help' => {
message => q{One error from the errors loop. It will have minimal markup.},
lastUpdated => 0,
context => q{Template variable help.},
},
'addressField help' => {
message => q{A single text field for the user to enter in their street address.},
lastUpdated => 0,
context => q{Template variable help.},
},
'emailField help' => {
message => q{A single text field for the user to enter in their email address.},
lastUpdated => 1231192368,
context => q{Template variable help.},
},
'cardNumberField help' => {
message => q{A single text field for the user to enter in their credit card number.},
lastUpdated => 0,
context => q{Template variable help.},
},
'monthYearField help' => {
message => q{A combination form field for the user to enter in the month and year of the expiration date for the credit card.},
lastUpdated => 0,
context => q{Template variable help.},
},
'cvv2Field help' => {
message => q{A single text field for the user to enter in their credit card verification number. If the PayDriver is not configured to use CVV2, then this field will be empty.},
lastUpdated => 0,
context => q{Template variable help.},
},
'checkoutButton help' => {
message => q{A button with an internationalized label to submit the form and continue the checkout process.},
lastUpdated => 0,
context => q{Template variable help.},
},
'fields help' => {
message => q{A loop of all the available fields for convenience. Each
entry in the loop contains name (field name), label (an internationalized
label for the field), and field (the same as in stateField, cityField, etc).},
lastUpdated => 0,
},
};
1;

View file

@ -154,6 +154,8 @@ checkModule("MooseX::NonMoose", '0.07' );
checkModule("MooseX::Storage::Format::JSON","0.27" );
checkModule("namespace::autoclean", "0.09" );
checkModule("Business::PayPal::API", "0.62" );
checkModule("Business::OnlinePayment", "3.01" );
checkModule("Business::OnlinePayment::AuthorizeNet", "3.21" );
checkModule("Locales", "0.10" );
checkModule("Test::Harness", "3.17" );
checkModule("DateTime::Event::ICal", "0.10" );

File diff suppressed because one or more lines are too long

218
t/Account/Profile.t Normal file
View file

@ -0,0 +1,218 @@
# 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 operation of WebGUI::Account modules. You can use
# as a base to test your own modules.
use FindBin;
use strict;
use lib "$FindBin::Bin/../lib";
use Test::More;
use Test::Deep;
use Exception::Class;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
my $andy = WebGUI::User->new($session, "new");
WebGUI::Test->addToCleanup($andy);
$session->user({userId => $andy->getId});
#----------------------------------------------------------------------------
# Tests
plan tests => 17; # Increment this number for each test you create
#----------------------------------------------------------------------------
# Test the creation of WebGUI::Account::Profile
# Can we load it?
use_ok( "WebGUI::Account::Profile" );
SKIP: { # Not everyone has Test::Exception yet
eval { require Test::Exception; import Test::Exception };
# Skip 1 test if Test::Exception couldn't be loaded
skip 1, 'Test::Exception not found' if $@;
throws_ok( sub { WebGUI::Account::Profile->new }, 'WebGUI::Error::InvalidObject',
'new() throws exception without session object'
);
};
my $profile;
ok( $profile = WebGUI::Account::Profile->new( $session ),
"WebGUI::Account::Profile object created successfully"
);
# Test $profile->isa
isa_ok( $profile, "WebGUI::Account", 'Blessed into the right class' );
#----------------------------------------------------------------------------
# Test getUrl
is( $profile->getUrl, $session->url->page('op=account;module=;do='.$profile->method),
'getUrl adds op, module, and do since no method has been set'
);
is( $profile->getUrl( 'foo=bar' ), $session->url->page( 'op=account;foo=bar' ),
'getUrl adds op if passed other parameters'
);
is( $profile->getUrl( 'op=account' ), $session->url->page( 'op=account' ),
'getUrl doesnt add op=account if already exists'
);
#######################################################################
#
# www_editSave
#
#######################################################################
tie my %profile_info, "Tie::IxHash", (
firstName => "Andy",
lastName => "Dufresne",
homeAddress => "123 Shank Ave.",
homeCity => "Shawshank",
homeState => "PA",
homeZip => "11223",
homeCountry => "US",
homePhone => "111-111-1111",
email => 'andy@shawshank.com'
);
$session->request->setup_body( \%profile_info );
$profile->www_editSave;
#Reset andy to the session users since stuff has changed
$andy = $session->user;
#Test that the address was saved to the profile
cmp_bag(
[ map { $andy->profileField($_) } keys %profile_info ],
[ values %profile_info ],
'Profile fields were saved'
);
#Test that the addressBook was created
my $bookId = $session->db->quickScalar(
q{ select addressBookId from addressBook where userId=? },
[$andy->getId]
);
ok( ($bookId ne ""), "Address Book was created");
my $book = WebGUI::Shop::AddressBook->new($session,$bookId);
my @addresses = @{ $book->getAddresses() };
is(scalar(@addresses), 1 , "One address was created in the address book");
my $address = $addresses[0];
tie my %address_info, "Tie::IxHash", (
firstName => $address->get("firstName"),
lastName => $address->get("lastName"),
homeAddress => $address->get("address1"),
homeCity => $address->get("city"),
homeState => $address->get("state"),
homeZip => $address->get("code"),
homeCountry => $address->get("country"),
homePhone => $address->get("phoneNumber"),
email => $address->get("email")
);
#Test that the address was saved properly to shop
cmp_bag(
[ values %profile_info ],
[ values %address_info ],
'Shop address was has the right information'
);
#Test that the address is returned as the profile address
my $profileAddress = $book->getProfileAddress;
is($profileAddress->getId, $address->getId, "Profile linked properly to address");
#Test that the address is the default address
my $defaultAddress = $book->getDefaultAddress;
is(
$defaultAddress->getId,
$address->getId,
"Profile address properly set to default address when created"
);
#Test updates to existing addresses
%profile_info = (
firstName => "Andy",
lastName => "Dufresne",
homeAddress => "123 Seaside Ave.",
homeCity => "Zihuatanejo",
homeState => "Guerrero",
homeZip => "40880",
homeCountry => "MX",
homePhone => "222-222-2222",
email => 'andy@freeman.com'
);
$session->request->setup_body( \%profile_info );
$profile->www_editSave;
$andy = $session->user;
#Test that the address was saved to the profile
cmp_bag (
[ map { $andy->profileField($_) } keys %profile_info ],
[ values %profile_info ],
'Profile fields were updated'
);
#Test that there is still only one address book and one address
my @bookIds = $session->db->quickArray(
q{ select addressBookId from addressBook where userId=? },
[$andy->getId]
);
is( scalar(@bookIds), 1, "Only one address book exists after update" );
$bookId = $bookIds[0];
$book = WebGUI::Shop::AddressBook->new($session,$bookId);
@addresses = @{ $book->getAddresses() };
is( scalar(@addresses), 1 , "Only one address exists after update");
my $address = $addresses[0];
%address_info = (
firstName => $address->get("firstName"),
lastName => $address->get("lastName"),
homeAddress => $address->get("address1"),
homeCity => $address->get("city"),
homeState => $address->get("state"),
homeZip => $address->get("code"),
homeCountry => $address->get("country"),
homePhone => $address->get("phoneNumber"),
email => $address->get("email")
);
#Test that the address was saved properly to shop
cmp_bag(
[ values %profile_info ],
[ values %address_info ],
'Shop address was has the right information'
);
#vim:ft=perl

View file

@ -866,7 +866,7 @@ subtest 'canAdd tolerates being called as an object method', sub {
# Make a test user who's just in Turn Admin On
my $u = WebGUI::User->create($session);
WebGUI::Test->addToCleanup($u);
WebGUI::Test->addToCleanup($u, $snip);
$u->addToGroups(['12']);
$session->user({ user => $u });

View file

@ -0,0 +1,46 @@
# 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
#------------------------------------------------------------------
=head1 BUG DESCRIPTION
When Thread assets are copied, a new subscription group gets created for them,
but not by calling $thread->createSubscriptionGroup. Instead, a "blank" group
is created, and then the users from the old group are added to it -- which by
default has Admins subscribed in it. So, every time we copy a thread, our
admins start getting spammed with subscription updates.
=cut
use warnings;
use strict;
use Test::More tests => 2;
use Test::Exception;
use FindBin;
use lib "$FindBin::Bin/../../../lib";
use WebGUI::Test;
use WebGUI::Asset;
my $session = WebGUI::Test->session;
my $thread = WebGUI::Asset->getImportNode($session)->addChild(
{
className => 'WebGUI::Asset::Post::Thread',
}
);
WebGUI::Test->addToCleanup($thread);
$thread->createSubscriptionGroup();
my $admin = WebGUI::User->new($session, 3);
ok !$admin->isInGroup($thread->get('subscriptionGroupId'));
$thread = $thread->duplicate();
WebGUI::Test->addToCleanup($thread);
ok !$admin->isInGroup($thread->get('subscriptionGroupId'));

View file

@ -172,6 +172,7 @@ cmp_bag(
extension => 'tar',
}),
],
'extensions in the attachment_loop are correct'
) or diag Dumper($templateVars->{attachment_loop});
TODO: {

View file

@ -0,0 +1,166 @@
#-------------------------------------------------------------------
# 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";
##The goal of this test is to test www_editThingDataSaveViaAjax, particularly those things not tested in Thingy.t
use WebGUI::Test;
use WebGUI::Session;
use Test::More tests => 4; # increment this value for each test you create
use Test::Deep;
use JSON;
use WebGUI::Asset::Wobject::Thingy;
use Data::Dumper;
my $session = WebGUI::Test->session;
# Do our work in the import node
my $node = WebGUI::Asset->getImportNode($session);
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->set({name=>"Thingy Test"});
WebGUI::Test->addToCleanup($versionTag);
my $thingy = $node->addChild({className=>'WebGUI::Asset::Wobject::Thingy'});
# Test adding a new Thing
my $i18n = WebGUI::International->new($session, "Asset_Thingy");
my $groupIdEdit = $thingy->get("groupIdEdit");
my %thingProperties = (
thingId => "new",
label => $i18n->get('assetName'),
editScreenTitle => $i18n->get('edit screen title label'),
editInstructions => '',
groupIdAdd => $groupIdEdit,
groupIdEdit => $groupIdEdit,
saveButtonLabel => $i18n->get('default save button label'),
afterSave => 'searchThisThing',
editTemplateId => "ThingyTmpl000000000003",
groupIdView => $groupIdEdit,
viewTemplateId => "ThingyTmpl000000000002",
defaultView => 'searchThing',
searchScreenTitle => $i18n->get('search screen title label'),
searchDescription => '',
groupIdSearch => $groupIdEdit,
groupIdExport => $groupIdEdit,
groupIdImport => $groupIdEdit,
searchTemplateId => "ThingyTmpl000000000004",
thingsPerPage => 25,
);
my $thingId = $thingy->addThing(\%thingProperties,0);
# Test adding a field
my %fieldProperties = (
thingId => $thingId,
fieldId => "new",
label => "Optional",
dateCreated => time(),
fieldType => "text",
status => "editable",
display => 1,
);
my $field1Id = $thingy->addField(\%fieldProperties, 0);
$fieldProperties{status} = 'required';
$fieldProperties{label} = 'Required';
my $field2Id = $thingy->addField(\%fieldProperties, 0);
#################################################################
#
# www_editThingDataSaveViaAjax
#
#################################################################
$session->request->setup_body({
thingId => $thingId,
thingDataId => 'new',
"field_".$field1Id => 'test value',
"field_".$field2Id => 'required', # required
});
$session->user({userId => '3'});
$session->http->setStatus(200);
my $json = $thingy->www_editThingDataSaveViaAjax();
is $json, '{}', 'www_editThingDataSaveViaAjax: Empty JSON hash';
is $session->http->getStatus, 200, '... http status=200';
$session->request->setup_body({
thingId => $thingId,
thingDataId => 'new',
"field_".$field1Id => 'test value',
"field_".$field2Id => '',
});
my $json = from_json( $thingy->www_editThingDataSaveViaAjax());
cmp_bag ($json,
[
superhashof ({
field_name => "field_".$field2Id,
}),
],
'checking for field_name in error json'
) or diag Dumper($json);
$fieldProperties{status} = 'required';
$fieldProperties{label} = 'Required2';
my $field3Id = $thingy->addField(\%fieldProperties, 0);
$fieldProperties{status} = 'required';
$fieldProperties{label} = 'Required3';
my $field4Id = $thingy->addField(\%fieldProperties, 0);
$session->request->setup_body({
thingId => $thingId,
thingDataId => 'new',
"field_".$field1Id => 'test value',
"field_".$field2Id => '',
"field_".$field3Id => '',
"field_".$field4Id => '',
});
$json = from_json( $thingy->www_editThingDataSaveViaAjax());
cmp_bag ($json,
[
superhashof ({
field_name => "field_".$field2Id,
}),
superhashof ({
field_name => "field_".$field3Id,
}),
superhashof ({
field_name => "field_".$field4Id,
}),
],
'checking for field_name in error json (3 required fields)'
) or diag Dumper($json);

121
t/Auth.t
View file

@ -15,6 +15,9 @@
use strict;
use Test::More;
use Test::Deep;
use Exception::Class;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Auth;
use WebGUI::Session;
@ -30,7 +33,7 @@ my ($request, $oldRequest, $output);
#----------------------------------------------------------------------------
# Tests
plan tests => 4; # Increment this number for each test you create
plan tests => 11; # Increment this number for each test you create
#----------------------------------------------------------------------------
# Test createAccountSave and returnUrl together
@ -59,9 +62,21 @@ WebGUI::Test->addToCleanup(sub {
"SELECT userId FROM users WHERE username=?",
[ $username ]
);
my $addressBookId = $session->db->quickScalar(
"select addressBookId from addressBook where userId=?",
[ $userId ]
);
if($addressBookId) {
$session->db->write(
"delete from address where addressBookId=?",
[$addressBookId]
);
}
my @tableList
= qw{authentication users userProfileData groupings inbox userLoginLog};
= qw{authentication users userProfileData groupings inbox userLoginLog addressBook};
for my $table ( @tableList ) {
$session->db->write(
@ -80,6 +95,8 @@ is(
is $createAccountSession->user->profileField('language'), $language, 'languageOverride is taken in to account in createAccountSave';
$createAccountSession->scratch->delete('language'); ##Remove language override
#----------------------------------------------------------------------------
# Test login and returnUrl together
# Set up request
@ -102,6 +119,104 @@ is $output, undef, 'login returns undef when showMessageOnLogin is false';
# Session Cleanup
$session->{_request} = $oldRequest;
#----------------------------------------------------------------------------
# Test createAccountSave
$username = $session->id->generate;
push @cleanupUsernames, $username;
#Test updates to existing addresses
tie my %profile_info, "Tie::IxHash", (
firstName => "Andy",
lastName => "Dufresne",
homeAddress => "123 Shank Ave.",
homeCity => "Shawshank",
homeState => "PA",
homeZip => "11223",
homeCountry => "US",
homePhone => "111-111-1111",
email => 'andy@shawshank.com'
);
$auth->createAccountSave( $username, { }, "PASSWORD", \%profile_info );
#Reset andy to the session users since stuff has changed
my $andy = $session->user;
#Test that the address was saved to the profile
cmp_bag(
[ map { $andy->profileField($_) } keys %profile_info ],
[ values %profile_info ],
'Profile fields were saved'
);
#Test that the addressBook was created
my $bookId = $session->db->quickScalar(
q{ select addressBookId from addressBook where userId=? },
[$andy->getId]
);
ok( ($bookId ne ""), "Address Book was created");
my $book = WebGUI::Shop::AddressBook->new($session,$bookId);
my @addresses = @{ $book->getAddresses() };
is(scalar(@addresses), 1 , "One address was created in the address book");
my $address = $addresses[0];
tie my %address_info, "Tie::IxHash", (
firstName => $address->get("firstName"),
lastName => $address->get("lastName"),
homeAddress => $address->get("address1"),
homeCity => $address->get("city"),
homeState => $address->get("state"),
homeZip => $address->get("code"),
homeCountry => $address->get("country"),
homePhone => $address->get("phoneNumber"),
email => $address->get("email")
);
#Test that the address was saved properly to shop
cmp_bag(
[ values %profile_info ],
[ values %address_info ],
'Shop address was has the right information'
);
#Test that the address is returned as the profile address
my $profileAddress = $book->getProfileAddress;
is($profileAddress->getId, $address->getId, "Profile linked properly to address");
#Test that the address is the default address
my $defaultAddress = $book->getDefaultAddress;
is(
$defaultAddress->getId,
$address->getId,
"Profile address properly set to default address when created"
);
$username = $session->id->generate;
push @cleanupUsernames, $username;
#Test updates to existing addresses
%profile_info = (
firstName => "Andy",
lastName => "Dufresne",
email => 'andy@shawshank.com'
);
$auth->createAccountSave( $username, { }, "PASSWORD", \%profile_info );
#Test that the addressBook was not created
my $bookCount = $session->db->quickScalar(
q{ select count(addressBookId) from addressBook where userId=? },
[$session->user->getId]
);
is( $bookCount, 0, "Address Book was not created for user without address fields");
sub installPigLatin {
use File::Copy;
mkdir File::Spec->catdir(WebGUI::Test->lib, 'WebGUI', 'i18n', 'PigLatin');

View file

@ -63,7 +63,7 @@ my @filterSets = (
},
{
inputText => q!<p>Paragraph</p>^H();!,
output => q!Paragraph &#94;H();!,
output => q|Paragraph &#94;H();|,
type => 'all',
comment => 'all filters macros and HTML',
},
@ -81,12 +81,12 @@ my @filterSets = (
},
{
inputText => q!&nbsp;!,
output => q!&#x26;nbsp;!,
output => q|&#x26;nbsp;|,
type => 'xml',
comment => 'xml, &nbsp;',
},
{
inputText => q!> < "!,
inputText => q|> < "|,
output => q!&#x3E; &#x3C; &#x22;!,
type => 'xml',
comment => 'xml, other characters',
@ -127,7 +127,7 @@ my @htmlTextSets = (
my $numTests = scalar @filterSets
+ scalar @macroParamSets
+ scalar @htmlTextSets
+ 3
+ 6
;
plan tests => $numTests;
@ -147,6 +147,31 @@ foreach my $testSet (@htmlTextSets) {
is($text, $testSet->{output}, $testSet->{comment});
}
my @replacement_ids = ();
push @replacement_ids, $session->db->setRow("replacements","replacementId",{
replacementId=>'new',
searchFor=>':)',
replaceWith=>'smiley.gif',
});
push @replacement_ids, $session->db->setRow("replacements","replacementId",{
replacementId=>'new',
searchFor=>'[]',
replaceWith=>'square brackets',
});
push @replacement_ids, $session->db->setRow("replacements","replacementId",{
replacementId=>'new',
searchFor=>'[IMAG]',
replaceWith=>'IMAGE',
});
WebGUI::Test->addToCleanup(sub {
foreach my $id (@replacement_ids) {
$session->db->write('delete from replacements where replacementId=?',[$id]);
}
});
is(WebGUI::HTML::processReplacements($session, 'grass'), 'grass', 'processReplacements: grass is not replaced');
is(WebGUI::HTML::processReplacements($session, 'shitake'), 'shitake', '... shitake is not replaced');
is(WebGUI::HTML::processReplacements($session, 'This is shit.'), 'This is crap.', '... shit is replaced');
is(WebGUI::HTML::processReplacements($session, ':)'), 'smiley.gif', '... unbalanced paren is replaced');
is(WebGUI::HTML::processReplacements($session, '[]'), 'square brackets', '... square brackets are replaced');
is(WebGUI::HTML::processReplacements($session, '[IMAG]'), 'IMAGE', '... image sequence processed');

View file

@ -10,28 +10,24 @@
#------------------------------------------------------------------
# Test the User operation
#
#
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;
use WebGUI::Test::Mechanize;
use WebGUI::User;
use WebGUI::Operation::User;
use Test::More;
use Test::Deep;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
$session->user({ userId => 3 });
#----------------------------------------------------------------------------
# Tests
plan tests => 17; # Increment this number for each test you create
#----------------------------------------------------------------------------
# Create a new user
my $mech = WebGUI::Test::Mechanize->new( config => WebGUI::Test->file );
@ -40,7 +36,7 @@ $mech->session->user({userId => 3});
$mech->get_ok( '?op=editUser;uid=new' );
my %fields = (
username => 'AndyDufresne',
username => 'AndrewDufresne',
email => 'andy@shawshank.doj.gov',
alias => 'Randall Stevens',
status => 'Active',
@ -55,12 +51,12 @@ $mech->submit_form_ok({
"Add a new user",
);
ok( my $user = WebGUI::User->newByUsername( $session, 'AndyDufresne' ), "user exists" );
ok( my $user = WebGUI::User->newByUsername( $session, 'AndrewDufresne' ), "user exists" );
WebGUI::Test->addToCleanup( $user );
is( $user->get('email'), $fields{email} );
is( $user->get('alias'), $fields{alias} );
is( $user->status, $fields{status} );
ok( $user->isInGroup( 12 ) );
is( $user->get('email'), $fields{email}, 'checking email' );
is( $user->get('alias'), $fields{alias}, '... alias' );
is( $user->status, $fields{status}, '... status' );
ok( $user->isInGroup( 12 ), '... added to group 12' );
my $auth = WebGUI::Auth::WebGUI->new( $session, $user );
is( $auth->get('identifier'), $auth->hashPassword('zihuatanejo'), "password was set correctly" );
@ -83,11 +79,166 @@ $mech->submit_form_ok({
);
ok( my $user = WebGUI::User->newByUsername( $mech->session, 'EllisRedding' ), "user exists" );
is( $user->get('email'), $fields{email} );
is( $user->get('alias'), $fields{alias} );
is( $user->status, $fields{status} );
ok( not $user->isInGroup( 12 ) );
is( $user->get('email'), $fields{email}, '... checking email' );
is( $user->get('alias'), $fields{alias}, '... checking alias' );
is( $user->status, $fields{status}, '... checking status' );
ok( not ($user->isInGroup( 12 )), '.. checking group deletion' );
$auth = WebGUI::Auth::WebGUI->new( $session, $user );
is( $auth->get('identifier'), $auth->hashPassword('rehabilitated'), "password was set correctly" );
#vim:ft=perl
#######################################################################
#
# Address testing in the profile
#
#######################################################################
my $andy = WebGUI::User->new($session, "new");
WebGUI::Test->addToCleanup($andy);
$andy->username("andydufresne");
$mech->get_ok( '?op=editUser;uid=' . $andy->getId );
my %profile_info = (
firstName => "Andy",
lastName => "Dufresne",
homeAddress => "123 Shank Ave.",
homeCity => "Shawshank",
homeState => "PA",
homeZip => "11223",
homeCountry => "US",
homePhone => "111-111-1111",
email => 'andy@shawshank.com'
);
$mech->submit_form_ok({
fields => {
%profile_info,
},
},
"Edit an existing user for address testing",
);
$andy = WebGUI::User->new($session,$andy->getId);
#Test that the address was saved to the profile
cmp_bag(
[ map { $andy->get($_) } keys %profile_info ],
[ values %profile_info ],
'Profile fields were saved'
);
#Test that the addressBook was created
my $bookId = $session->db->quickScalar(
q{ select addressBookId from addressBook where userId=? },
[$andy->getId]
);
ok( ($bookId ne ""), "Address Book was created");
my $book = WebGUI::Shop::AddressBook->new($session,$bookId);
my @addresses = @{ $book->getAddresses() };
is(scalar(@addresses), 1 , "One address was created in the address book");
my $address = $addresses[0];
ok ($address->get('isProfile'), '... and it is a profile address');
tie my %address_info, "Tie::IxHash", (
firstName => $address->get("firstName"),
lastName => $address->get("lastName"),
homeAddress => $address->get("address1"),
homeCity => $address->get("city"),
homeState => $address->get("state"),
homeZip => $address->get("code"),
homeCountry => $address->get("country"),
homePhone => $address->get("phoneNumber"),
email => $address->get("email")
);
#Test that the address was saved properly to shop
cmp_bag(
[ values %profile_info ],
[ values %address_info ],
'Shop address has the right information'
);
#Test that the address is returned as the profile address
my $profileAddress = $book->getProfileAddress;
is($profileAddress->getId, $address->getId, "Profile linked properly to address");
#Test that the address is the default address
my $defaultAddress = $book->getDefaultAddress;
is(
$defaultAddress->getId,
$address->getId,
"Profile address properly set to default address when created"
);
#Test updates to existing addresses
%profile_info = (
firstName => "Andy",
lastName => "Dufresne",
homeAddress => "123 Seaside Ave.",
homeCity => "Zihuatanejo",
homeState => "Guerrero",
homeZip => "40880",
homeCountry => "MX",
homePhone => "222-222-2222",
email => 'andy@freeman.com'
);
$mech->get_ok( '?op=editUser;uid=' . $andy->getId );
$mech->submit_form_ok({
fields => {
%profile_info,
},
},
"Update existing address info",
);
$andy = WebGUI::User->new($session,$andy->getId);
#Test that the address was saved to the profile
cmp_bag (
[ map { $andy->get($_) } keys %profile_info ],
[ values %profile_info ],
'Profile fields were updated'
);
#Test that there is still only one address book and one address
my @bookIds = $session->db->quickArray(
q{ select addressBookId from addressBook where userId=? },
[$andy->getId]
);
is( scalar(@bookIds), 1, "Only one address book exists after update" );
$bookId = $bookIds[0];
$book = WebGUI::Shop::AddressBook->new($session,$bookId);
@addresses = @{ $book->getAddresses() };
is( scalar(@addresses), 1 , "Only one address exists after update");
my $address = $addresses[0];
%address_info = (
firstName => $address->get("firstName"),
lastName => $address->get("lastName"),
homeAddress => $address->get("address1"),
homeCity => $address->get("city"),
homeState => $address->get("state"),
homeZip => $address->get("code"),
homeCountry => $address->get("country"),
homePhone => $address->get("phoneNumber"),
email => $address->get("email")
);
#Test that the address was saved properly to shop
cmp_bag(
[ values %profile_info ],
[ values %address_info ],
'Shop address has the right information'
);
done_testing;

View file

@ -26,11 +26,6 @@ use WebGUI::Shop::AddressBook;
# Init
my $session = WebGUI::Test->session;
#----------------------------------------------------------------------------
# Tests
plan tests => 20;
#----------------------------------------------------------------------------
# put your tests here
@ -128,6 +123,7 @@ cmp_deeply(
addressId => ignore(), #checked elsewhere
addressBookId => $book->getId,
addressBook => $book,
isProfile => 0,
},
'get the whole thing and check a new, blank object'
);
@ -192,3 +188,5 @@ cmp_deeply(
$address->delete;
my $check = $session->db->quickScalar('select count(*) from address where addressId=?',[$address->getId]);
is( $check, 0, 'delete worked');
done_testing;

View file

@ -22,15 +22,16 @@ use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
use WebGUI::Text;
use WebGUI::Shop::AddressBook;
use JSON;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
#----------------------------------------------------------------------------
# Tests
plan tests => 23;
#Create a temporary admin user
my $tempAdmin = WebGUI::User->create($session);
$tempAdmin->addToGroups(['3']);
WebGUI::Test->addToCleanup($tempAdmin);
$session->user({ userId => $tempAdmin->getId} );
#----------------------------------------------------------------------------
# put your tests here
@ -84,7 +85,7 @@ cmp_deeply(
'... correct error message',
);
$session->user({userId => 3});
$session->user({userId => $tempAdmin->getId});
$book = WebGUI::Shop::AddressBook->new($session);
isa_ok($book, 'WebGUI::Shop::AddressBook', 'new returns the right kind of object');
@ -94,10 +95,10 @@ is($session->getId, $book->session->getId, 'session method returns OUR session o
ok($session->id->valid($book->getId), 'new makes a valid GUID style addressBookId');
is($book->get('userId'), 3, 'new uses $session->user to get the userid for this book');
is($book->userId, 3, '... testing direct accessor');
is($book->get('userId'), $tempAdmin->getId, 'create uses $session->user to get the userid for this book');
is($book->userId, $tempAdmin->getId, '... testing direct accessor');
my $bookCount = $session->db->quickScalar('select count(*) from addressBook');
my $bookCount = $session->db->quickScalar('select count(*) from addressBook where addressBookId=?',[$book->getId]);
is($bookCount, 1, 'only 1 address book was created');
my $alreadyHaveBook = WebGUI::Shop::AddressBook->new($session);
@ -163,25 +164,188 @@ cmp_deeply(
'update updates the db, too'
);
#######################################################################
#
# getProfileAddress
#
#######################################################################
eval { $book->getProfileAddress };
$e = Exception::Class->caught();
isa_ok($e, 'WebGUI::Error::ObjectNotFound', 'getProfileAddress takes exception to a profile address not being set');
cmp_deeply(
$e,
methods(
error => 'No profile address.',
),
'... correct error message',
);
$address1->update({ isProfile => 1 });
my $profile_address = eval{ $book->getProfileAddress() };
is($profile_address->getId,$address1->getId,"getProfileAddress returns addresses tied to profiles");
#######################################################################
#
# www_editAddressSave
#
#######################################################################
#Clear the book address cache
$book->uncache;
my $address_info = {
label => 'Profile Label',
addressId => $address1->getId,
firstName => 'Andy',
lastName => 'Dufresne',
address1 => '123 Shank Ave',
address2 => 'Cell Block E',
address3 => 'Cell 12',
city => 'Shawshank',
state => 'PA',
code => '11223',
country => 'US',
phoneNumber => '111-111-1111',
email => 'andy@shawshank.com',
organization => 'Shawshank'
};
$session->request->setup_body({
%$address_info,
callback => q|{'url':''}|
});
$book->www_editAddressSave;
$address1 = $book->getAddress($address1->getId);
cmp_bag(
[ map { $address1->get($_) } keys %$address_info ],
[ values %$address_info ],
'Address fields were saved'
);
my $u = WebGUI::User->new($session,$book->get("userId"));
cmp_bag(
[ map { $u->profileField($_) } keys %{ $book->getProfileAddressMappings } ],
[ map { $address1->get($_) } values %{ $book->getProfileAddressMappings } ],
'Profile address was updated and matches address fields'
);
#Test that updates to non profile address does not update the profile
$book->uncache;
$address_info = {
label => 'Non Profile Label',
addressId => $address2->getId,
firstName => 'Ellis',
lastName => 'Redding',
address1 => '123 Shank Ave',
address2 => 'Cell Block E',
address3 => 'Cell 15',
city => 'Shawshank',
state => 'PA',
code => '11223',
country => 'US',
phoneNumber => '111-111-1111',
email => 'red@shawshank.com',
organization => 'Shawshank'
};
$session->request->setup_body({
%$address_info,
callback => q|{'url':''}|
});
$book->www_editAddressSave;
$address1 = $book->getAddress($address1->getId);
$address2 = $book->getAddress($address2->getId);
cmp_bag(
[ map { $address2->get($_) } keys %$address_info ],
[ values %$address_info ],
'Non Profile Address fields were saved'
);
cmp_bag(
[ map { $u->profileField($_) } keys %{ $book->getProfileAddressMappings } ],
[ map { $address1->get($_) } values %{ $book->getProfileAddressMappings } ],
'Profile address was not updated when non profile fields were saved'
);
#######################################################################
#
# www_deleteAddress
#
#######################################################################
#clear the cache
$book->uncache;
$session->request->setup_body({
'addressId' => $address2->getId,
'callback' => q|{'url':''}|
});
$book->www_deleteAddress;
@addresses = @{ $book->getAddresses() };
cmp_bag(
[ map { $_->getId } @addresses ],
[$address1->getId],
'Address was deleted properly'
);
#clear the cache
$book->uncache;
$session->request->setup_body({
'addressId' => $address1->getId,
'callback' => q|{'url':''}|
});
$book->www_deleteAddress;
@addresses = @{ $book->getAddresses() };
cmp_bag(
[ map { $_->getId } @addresses ],
[$address1->getId],
'Profile Address was not deleted'
);
#######################################################################
#
# delete
#
#######################################################################
#clear the cache
$book->uncache;
my $addressBookId = $alreadyHaveBook->getId;
my $firstCount = $session->db->quickScalar('select count(*) from addressBook where addressBookId=?',[$addressBookId]);
$alreadyHaveBook->delete();
$bookCount = $session->db->quickScalar('select count(*) from addressBook');
my $addrCount = $session->db->quickScalar('select count(*) from address');
my $afterCount = $session->db->quickScalar('select count(*) from addressBook where addressBookId=?',[$addressBookId]);
my $addrCount = $session->db->quickScalar('select count(*) from address where addressBookId=?',[$addressBookId]);
is($bookCount, 1, 'delete: one book deleted');
ok(($firstCount == 1 && $afterCount == 0), 'delete: one book deleted');
$addressBookId = $bookClone->getId;
$bookClone->delete();
$bookCount = $session->db->quickScalar('select count(*) from addressBook');
$addrCount = $session->db->quickScalar('select count(*) from address');
$bookCount = $session->db->quickScalar('select count(*) from addressBook where addressBookId=?',[$addressBookId]);
$addrCount = $session->db->quickScalar('select count(*) from address where addressBookId=?',[$addressBookId]);
is($bookCount, 0, '... book deleted');
is($addrCount, 0, '... also deletes addresses in the book');
undef $book;
#######################################################################
#
@ -189,7 +353,6 @@ undef $book;
#
#######################################################################
my $otherSession = WebGUI::Test->newSession;
my $mergeUser = WebGUI::User->create($otherSession);
WebGUI::Test->addToCleanup($mergeUser);
@ -208,3 +371,227 @@ cmp_bag(
[ $goodAddress->getId, ],
'newByUserId works'
);
#######################################################################
#
# www_ajaxSearch
#
#######################################################################
#Create some data to search for
my $andySession = WebGUI::Test->newSession;
my $andy = WebGUI::User->create($andySession);
WebGUI::Test->addToCleanup($andy);
$andySession->user({ userId => $andy->getId });
my $andyBook = WebGUI::Shop::AddressBook->create($andySession);
WebGUI::Test->addToCleanup($andyBook);
my $andyAddr1 = $andyBook->addAddress({
label => 'Andy1',
firstName => 'Andy',
lastName => 'Dufresne',
address1 => '123 Shank Ave',
address2 => 'Cell Block E',
address3 => 'Cell 12',
city => 'Shawshank',
state => 'PA',
code => '11223',
country => 'US',
phoneNumber => '111-111-1111',
email => 'andy@shawshank.com',
organization => 'Shawshank'
});
my $andyAddr2 = $andyBook->addAddress({
label => 'Andy2',
firstName => 'Andy',
lastName => 'Dufresne',
address1 => '123 Seaside Ave',
address2 => '',
address3 => '',
city => 'Zihuatanejo',
state => '',
code => '40880',
country => 'MX',
phoneNumber => '222-222-2222',
email => 'andy@freeman.com',
organization => 'Unaffiliated'
});
my $redSession = WebGUI::Test->newSession;
my $red = WebGUI::User->create($redSession);
WebGUI::Test->addToCleanup($red);
$redSession->user({userId => $red->getId});
my $redBook = WebGUI::Shop::AddressBook->create($redSession);
WebGUI::Test->addToCleanup($redBook);
my $redAddr = $redBook->addAddress({
label => 'Red1',
firstName => 'Ellis',
lastName => 'Redding',
address1 => '123 Shank Ave',
address2 => 'Cell Block E',
address3 => 'Cell 15',
city => 'Shawshank',
state => 'PA',
code => '11223',
country => 'US',
phoneNumber => '111-111-1111',
email => 'red@shawshank.com',
organization => 'Shawshank'
});
my $brooksSession = WebGUI::Test->newSession;
my $brooks = WebGUI::User->create($brooksSession);
WebGUI::Test->addToCleanup($brooks);
$brooksSession->user({userId => $brooks->getId});
my $brooksBook = WebGUI::Shop::AddressBook->create($brooksSession);
WebGUI::Test->addToCleanup($brooksBook);
my $brooksAddr = $brooksBook->addAddress({
label => 'Brooks1',
firstName => 'Brooks',
lastName => 'Hatlen',
address1 => '123 Shank Ave',
address2 => 'Cell Block E',
address3 => 'Cell 22',
city => 'Shawshank',
state => 'PA',
code => '11223',
country => 'US',
phoneNumber => '111-111-1111',
email => 'brooks@shawshank.com',
organization => 'Shawshank'
});
#Test search as admin
$session->request->setup_body({
'name' => 'Andy Du'
});
my $results = JSON->new->decode($book->www_ajaxSearch);
cmp_bag(
$results,
[
{ %{$andyAddr1->get}, username => $andy->username },
{ %{$andyAddr2->get}, username => $andy->username },
],
'Ajax Address Search matches name correctly for admins'
);
#Test search for multiple fields
$session->request->setup_body({
'name' => 'Andy Du',
'organization' => 'Shaw',
'address1' => '123',
'address2' => 'Cell',
'address3' => 'Cell',
'city' => 'Shaw',
'state' => 'P',
'zipcode' => '11',
'country' => 'U',
'email' => 'andy',
'phone' => '111',
});
$results = JSON->new->decode($book->www_ajaxSearch);
cmp_bag(
$results,
[{ %{$andyAddr1->get}, username => $andy->username }],
'Ajax Address Search matches multiple fields correctly'
);
#Test limiting
$session->request->setup_body({
'name' => 'Andy Du',
'organization' => 'Shaw',
'address1' => '123',
'address2' => 'Cell',
'address3' => 'Cell',
'city' => 'Shaw',
'state' => 'Q', #This should cause no results to come back
'zipcode' => '11',
'country' => 'U',
'email' => 'andy',
'phone' => '111',
});
$results = JSON->new->decode($book->www_ajaxSearch);
cmp_bag(
$results,
[],
'Ajax Address Search limits results correctly'
);
#Test searching across users
#Test as admin
$session->request->setup_body({
'organization' => 'Shawshank'
});
$results = JSON->new->decode($book->www_ajaxSearch);
cmp_bag(
$results,
[
{ %{$andyAddr1->get}, username => $andy->username },
{ %{$redAddr->get}, username => $red->username },
{ %{$brooksAddr->get}, username => $brooks->username },
],
'Ajax Address Search returns cross user results for admins'
);
#Test as shop admin
$andy->addToGroups([ $andySession->setting->get('groupIdAdminCommerce') ]);
$andySession->request->setup_body({
'organization' => 'Shawshank'
});
$results = JSON->new->decode($andyBook->www_ajaxSearch);
cmp_bag(
$results,
[
{ %{$andyAddr1->get}, username => $andy->username },
{ %{$redAddr->get}, username => $red->username },
{ %{$brooksAddr->get}, username => $brooks->username },
],
'Ajax Address Search returns cross user results for shop admins'
);
#Test search as shop cashier
$red->addToGroups([ $redSession->setting->get('groupIdCashier') ]);
$redSession->request->setup_body({
'organization' => 'Shawshank'
});
$results = JSON->new->decode($redBook->www_ajaxSearch);
cmp_bag(
$results,
[
{ %{$andyAddr1->get}, username => $andy->username },
{ %{$redAddr->get}, username => $red->username },
{ %{$brooksAddr->get}, username => $brooks->username },
],
'Ajax Address Search returns cross user results for shop cashiers'
);
#Test search as non privileged
$brooksSession->request->setup_body({
'organization' => 'Shawshank'
});
$results = JSON->new->decode($brooksBook->www_ajaxSearch);
cmp_bag(
$results,
[{ %{$brooksAddr->get}, username => $brooks->username }],
'Ajax Address Search returns only current user results for non privileged users'
);
undef $book;
done_testing;

View file

@ -16,6 +16,7 @@
use strict;
use Test::More;
use Test::Deep;
use Test::Exception;
use Scalar::Util qw/refaddr/;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
@ -30,11 +31,6 @@ use JSON 'from_json';
my $session = WebGUI::Test->session;
my $i18n = WebGUI::International->new($session, "Shop");
#----------------------------------------------------------------------------
# Tests
plan tests => 35; # Increment this number for each test you create
#----------------------------------------------------------------------------
# put your tests here
@ -219,3 +215,11 @@ is($cart->delete, undef, "Can destroy cart.");
$product->purge;
my $requiresShipping_ok = lives_ok { $cart->requiresShipping; } 'requiresShipping does not die if the asset in the cart has been deleted';
SKIP: {
skip 1, 'requiresShipping died, so skipping' unless $requiresShipping_ok;
ok !$cart->requiresShipping, 'Shipping no longer required on a cart with missing assets';
}
done_testing;

View file

@ -129,6 +129,7 @@ my $defaultPayDrivers = {
'WebGUI::Shop::PayDriver::Ogone' => 'Ogone',
'WebGUI::Shop::PayDriver::PayPal::PayPalStd' => 'PayPal',
'WebGUI::Shop::PayDriver::PayPal::ExpressCheckout' => 'PayPal Express Checkout',
'WebGUI::Shop::PayDriver::CreditCard::AuthorizeNet' => 'Credit Card (Authorize.net)',
};
cmp_deeply( $drivers, $defaultPayDrivers, 'getDrivers returns the default PayDrivers');

View file

@ -0,0 +1,118 @@
// Initialize namespace
if (typeof WebGUI == "undefined") {
var WebGUI = {};
}
if (typeof WebGUI.Asset == "undefined") {
WebGUI.Asset = {};
}
if(typeof WebGUI.Asset.Sku == "undefined") {
WebGUI.Asset.Sku = {};
}
if(typeof WebGUI.Asset.Sku.EMSBadge == "undefined") {
WebGUI.Asset.Sku.EMSBadge = {};
}
var timeout = null;
var searchResults = [];
WebGUI.Asset.Sku.EMSBadge = {
delayLookup : function( ) {
if(timeout != null) {
clearTimeout(timeout);
}
timeout = setTimeout(WebGUI.Asset.Sku.EMSBadge.lookupAddress,300);
},
initForm : function( ) {
var addressCol = document.getElementById("emsbadge_container");
var divs = addressCol.getElementsByTagName('div');
for( var i = 0; i < divs.length; i++ ) {
WebGUI.Asset.Sku.EMSBadge.setHoverStates( divs[i] );
YAHOO.util.Event.addListener( divs[i], "click", WebGUI.Asset.Sku.EMSBadge.setAddress );
}
var formTbl = document.getElementById("emsbadge_form_tbl");
var inputs = formTbl.getElementsByTagName('input');
for( var i = 0; i < inputs.length; i++ ) {
var inputEl = inputs[i];
YAHOO.util.Event.addListener(inputEl, "keydown", WebGUI.Asset.Sku.EMSBadge.delayLookup);
}
},
lookupAddress : function( ) {
timeout = null;
var url = searchUrl + ";" + WebGUI.Form.buildQueryString("emsbadge_form",{ name: ['func'] });
YAHOO.util.Connect.asyncRequest('GET', url, {
success: function(o) {
searchResults = YAHOO.lang.JSON.parse(o.responseText);
for( var i = 1; i <= 3; i++ ) {
document.getElementById('emsbadge_address_' + i).style.display='none';
}
for( var i = 0; i < searchResults.length; i++ ) {
if(i > 3) break;
var addressEl = document.getElementById('emsbadge_address_' + (i+1));
var address = searchResults[i];
var addressStr = "<span style='color:blue'>" + address.username + "</span>"
+ "<br />";
addressStr += address.firstName + " " + address.lastName
+ "<br />"
+ address.address1
+ "<br />";
if(address.state) {
addressStr += address.city + ", " + address.state + " " + address.code;
}
else {
addressStr += address.city + ", " + address.country;
}
if(address.email) {
addressStr += "<br />" + address.email;
}
addressEl.innerHTML = addressStr;
addressEl.style.display = '';
}
},
failure: function(o) {}
});
},
setAddress : function ( e ) {
var el = YAHOO.util.Event.getTarget(e);
if(el.tagName == "SPAN") {
el = el.parentNode;
}
var divClicked = el.id;
var parts = divClicked.split("_");
var index = parseInt(parts[2]);
var result = searchResults[(index -1)];
if( result == null ) return;
document.getElementById('name_formId').value = result.firstName + " " + result.lastName;
document.getElementById('organization_formId').value = result.organization;
document.getElementById('address1_formId').value = result.address1;
document.getElementById('address2_formId').value = result.address2;
document.getElementById('address3_formId').value = result.address3;
document.getElementById('city_formId').value = result.city;
document.getElementById('state_formId').value = result.state;
document.getElementById('zipcode_formId').value = result.code;
document.getElementById('country_formId').value = result.country;
document.getElementById('phone_formId').value = result.phoneNumber;
document.getElementById('email_formId').value = result.email;
},
setHoverStates : function( el ) {
el.setAttribute("oldclass", el.className);
el.onmouseover = function() { this.className = this.getAttribute("oldclass") + "_on"; };
el.onmouseout = function() { this.className = this.getAttribute("oldclass"); };
}
}
YAHOO.util.Event.onDOMReady( function () {
WebGUI.Asset.Sku.EMSBadge.initForm();
});

View file

@ -96,6 +96,65 @@ WebGUI.Form.buildQueryString = function ( formId, excludes ) {
return sFormData;
};
/***********************************************************************************
* @description This method clears all the values of the form. This is different than reset which will restore default values
* @method clearForm
* @public
* @static
* @param {string || object} id or object of the form element to clear values for.
* @param {object} object containing array of form elements to exclude. { id:[], name:[], classNames:[], type:[] }
*/
WebGUI.Form.clearForm = function ( oElement, excludes ) {
var _isInArray = function ( value, array) {
if(!array || !value) return 0;
if(typeof array != 'object') return 0;
for(var i = 0; i < array.length; i++) {
if(array[i] == value) return 1;
}
return 0;
};
if(typeof oElement != 'object') oElement = document.getElementById(oElement);
for (i = 0; i < oElement.length; i++) {
var oType = oElement[i].type.toLowerCase();
var oClass = oElement[i].className;
var oName = oElement[i].name;
var oId = oElement[i].id;
if(_isInArray(oClass,excludes.classNames)) continue;
if(_isInArray(oId,excludes.id)) continue;
if(_isInArray(oName,excludes.name)) continue;
if(_isInArray(oType,excludes.type)) continue;
switch (oType) {
case "text":
case "password":
case "textarea":
case "hidden":
oElement[i].value = "";
break;
case "radio":
case "checkbox":
if (oElement[i].checked) {
oElement[i].checked = false;
}
break;
case "select-one":
case "select-multi":
oElement[i].selectedIndex = -1;
break;
default:
break;
}
}
return;
};
/***********************************************************************************
* @description This method gets the proper value of the form element passed in
* @method getFormValue

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Before After
Before After