Merge commit '4969f31e1f' into WebGUI8

This commit is contained in:
Colin Kuskie 2010-06-26 14:37:31 -07:00
commit e5b82bc861
61 changed files with 2199 additions and 521 deletions

View file

@ -1,4 +1,29 @@
7.9.5
- Asset->www_copy now has a progress bar
- fixed #11556: New cart doesn't work with other forms on the same page
- fixed #11557: Shop credit deduction calculated incorrectly
- fixed #11561: PayDriver_Cash - password help
- fixed #11541: running workflows screen
- fixed #11544: VersionTag Workflows with missing Version Tags run forever
- fixed #11555: Wiki subcategories entry field is not labeled
- fixed: UserList asset has SQL injection bug
- fixed #11558: wiki results for visitors
- fixed #11533: Saving entered data at registration
- fixed #11564: Shop: Cart does not require a state field in the address
- fixed #11562: Missing perl modules in gotcha
- fixed #11565: Can't clear cache on plainblack.com
- fixed #11540: Pending version tags are not completed on approval under certain conditions
- fixed #11566: Group API: group membership cannot be checked without consideration of expiration dates.
- fixed #11567: EMS: Build badge page, ticket tab, pagination
- added: a new inbox setting which supresses friend rejection notices
- fixed #11552: Visitors (and others) can bypass group-by-IP restrictions
- fixed #11572: visitors can enter editProfile
- fixed #11563: Syndicated Content - descriptionFirstParagraph cuts off
- fixed #11538: User invite mail: whitespace in message lost
- fixed #11549: Shortcut Asset cannot override Page Layout
- added #11502: Gallery: Allow specification of location when uploading ZIP archives
- added #11517: Gallery: Sorting of files uploaded in zip archives
- fixed #11559: Unsubscribe Link in Emails
7.9.4
- We're shipping underscore.js now for its suite of extremely handy utility

File diff suppressed because one or more lines are too long

View file

@ -17,6 +17,14 @@ save you many hours of grief.
- Moose
- CHI
7.9.5
--------------------------------------------------------------------
* Starting in WebGUI 7.9.4, the CHI and Cache::FastMmap modules are required.
* Starting in WebGUI 7.9.5, you cannot enter in a URL that is a has more than 2 dashes,
"-", in a row. They will be collapsed down into 1 dash.
7.9.4
--------------------------------------------------------------------
* Shop and Cart changes

View file

@ -22,6 +22,7 @@ use Getopt::Long;
use WebGUI::Session;
use WebGUI::Storage;
use WebGUI::Asset;
use WebGUI::Workflow::Instance;
my $toVersion = '7.9.5';
@ -31,10 +32,14 @@ my $quiet; # this line required
my $session = start(); # this line required
# upgrade functions go here
modifySortItems( $session );
fixRequestForApprovalScratch($session);
addRejectNoticeSetting($session);
updateGroupGroupingsTable($session);
installNewCSUnsubscribeTemplate($session);
finish($session); # this line required
#----------------------------------------------------------------------------
# Describe what our function does
#sub exampleFunction {
@ -44,6 +49,85 @@ finish($session); # this line required
# print "DONE!\n" unless $quiet;
#}
#----------------------------------------------------------------------------
# Adds setting which allows users to set whether or not to send reject notices
sub addRejectNoticeSetting {
my $session = shift;
print "\tAdding reject notice setting... " unless $quiet;
$session->setting->add('sendRejectNotice',1);
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub installNewCSUnsubscribeTemplate {
my $session = shift;
print "\tAdding new unsubscribe template to the CS... " unless $quiet;
$session->db->write(q|ALTER TABLE Collaboration ADD COLUMN unsubscribeTemplateId CHAR(22) NOT NULL|);
$session->db->write(q|UPDATE Collaboration set unsubscribeTemplateId='default_CS_unsubscribe'|);
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Add keys and indicies to groupGroupings to help speed up group queries
sub updateGroupGroupingsTable {
my $session = shift;
print "\tAdding primary key and indicies to groupGroupings table... " unless $quiet;
my $sth = $session->db->read('show create table groupGroupings');
my ($field,$stmt) = $sth->array;
$sth->finish;
unless ($stmt =~ m/PRIMARY KEY/i) {
$session->db->write("alter table groupGroupings add primary key (groupId,inGroup)");
}
unless ($stmt =~ m/KEY `inGroup`/i) {
$session->db->write("alter table groupGroupings add index inGroup (inGroup)");
}
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Describe what our function does
sub fixRequestForApprovalScratch {
my $session = shift;
print "\tCorrect RequestApprovalForVersionTag workflow instance data with leading commas... " unless $quiet;
# and here's our code
my $instances = WebGUI::Workflow::Instance->getAllInstances($session);
INSTANCE: foreach my $instance (@{ $instances }) {
my $messageId = $instance->getScratch('messageId');
next INSTANCE unless $messageId;
$messageId =~ s/^,//;
$instance->setScratch('messageId', $messageId);
}
print "DONE!\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Changes sortItems to a SelectBox
sub modifySortItems {
my $session = shift;
print "\tUpdating SyndicatedContent...\n" unless $quiet;
require WebGUI::Form::SelectBox;
print "\t\tModifying table...\n" unless $quiet;
my $type = WebGUI::Form::SelectBox->getDatabaseFieldType;
$session->db->write("ALTER TABLE SyndicatedContent MODIFY sortItems $type");
print "\t\tConverting old values..." unless $quiet;
$session->db->write(q{
UPDATE SyndicatedContent
SET sortItems = 'none'
WHERE sortItems <> '1'
});
$session->db->write(q{
UPDATE SyndicatedContent
SET sortItems = 'pubDate_des'
WHERE sortItems = '1'
});
# and here's our code
print "DONE!\n" unless $quiet;
}
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------

View file

@ -294,7 +294,8 @@ sub getJsonStatus {
my %output;
if ($sitename) { #must have entry for each queue
%output = %queues;
foreach my $instance ($self->getInstances) {
INSTANCE: foreach my $instance ($self->getInstances) {
next INSTANCE unless $instance->{sitename} eq $sitename;
my $queue = ucfirst($instance->{status});
push @{$output{$queue}}, [$instance->{workingPriority}, $instance->{instanceId}, $instance];
}

View file

@ -238,6 +238,12 @@ sub editSettingsForm {
hoverHelp => $i18n->get('send inbox notifications only help'),
defaultValue => $setting->get('sendInboxNotificationsOnly'),
);
$f->yesNo(
name => 'sendRejectNotice',
label => $i18n->get('send reject notice'),
hoverHelp => $i18n->get('send reject notice help'),
defaultValue => $setting->get('sendRejectNotice'),
);
$f->text(
name => 'inboxNotificationsSubject',
label => $i18n->get('inbox notifications subject'),
@ -306,6 +312,7 @@ sub editSettingsFormSave {
$setting->set("inboxNotificationsSubject", $form->process("inboxNotificationsSubject", "text"));
$setting->set("inboxNotificationTemplateId", $form->process("inboxNotificationTemplateId","template"));
$setting->set("inboxSmsNotificationTemplateId", $form->process("inboxSmsNotificationTemplateId","template"));
$setting->set("sendRejectNotice", $form->process("sendRejectNotice","yesNo"));
}
@ -605,7 +612,7 @@ sub www_approveDenyInvitations {
next unless ($invite->{inviterId}); #Not sure how this could ever happen, but check for it
next unless ($session->user->userId eq $invite->{friendId}); #Protect against malicious stuff
if($deny) {
$friends->rejectAddRequest($inviteId);
$friends->rejectAddRequest($inviteId,$session->setting->get("sendRejectNotice"));
}
elsif($approve) {
$friends->approveAddRequest($inviteId);
@ -954,7 +961,7 @@ sub www_inviteUserSave {
);
## No sneaky attack paths...
$var->{'message'} = WebGUI::HTML::html2text( WebGUI::HTML::filter($message) );
$var->{'message'} = WebGUI::HTML::format(WebGUI::HTML::filter($message));
my $emailBody = $self->processTemplate( $var, $self->getInviteUserMessageTemplateId );

View file

@ -996,18 +996,22 @@ sub unstick {
#-------------------------------------------------------------------
=head2 unsubscribe ( )
=head2 unsubscribe ( [$user] )
Negates the subscribe method.
Unsubscribes a user from this thread.
=head3 $user
An optional user object to unsubscribe. If the object isn't passed, then it uses the session user.
=cut
sub unsubscribe {
my $self = shift;
my $self = shift;
my $user = shift || $self->session->user;
my $group = WebGUI::Group->new($self->session,$self->subscriptionGroupId);
return
if !$group;
$group->deleteUsers([$self->session->user->userId]);
return if !$group;
$group->deleteUsers([$user->userId]);
}
@ -1355,16 +1359,60 @@ sub www_unstick {
#-------------------------------------------------------------------
=head2 www_unsubscribe ( )
=head2 www_unsubscribe ( [$message] )
The web method to unsubscribe from a thread.
=head3 $message
An error message to display to the user.
=cut
sub www_unsubscribe {
my $self = shift;
$self->unsubscribe if $self->canSubscribe;
return $self->www_view;
my $self = shift;
my $message = shift;
if($self->canSubscribe){
$self->unsubscribe;
return $self->www_view;
}
else {
my $session = $self->session;
my $i18n = WebGUI::International->new($session, 'Asset_Collaboration');
my $var = $self->get();
$var->{title} = $self->getTitle;
$var->{url} = $self->getUrl;
$var->{formHeader} = WebGUI::Form::formHeader($session)
. WebGUI::Form::hidden($session, { name => 'func', value => 'unsubscribeConfirm', }, ),
$var->{formFooter} = WebGUI::Form::formFooter($session),
$var->{formSubmit} = WebGUI::Form::submit($session, { value => $i18n->get('unsubscribe'), }),
$var->{formEmail} = WebGUI::Form::email($session, { name => 'userEmail', value => $session->form->process('userEmail'), }),
$var->{formMessage} = $message;
return $self->getParent->processStyle($self->processTemplate($var, $self->getParent->get("unsubscribeTemplateId")));
}
}
#-------------------------------------------------------------------
=head2 www_unsubscribeConfirm ( )
Process the unsubscribe form.
=cut
sub www_unsubscribeConfirm {
my $self = shift;
my $session = $self->session;
return $self->www_view unless $session->form->validToken;
my $email = $session->form->process('userEmail', 'email');
return $self->www_view unless $email;
my $user = WebGUI::User->newByEmail($session, $email);
my $i18n = WebGUI::International->new($session, 'Asset_Collaboration');
if (! $user) {
return $self->www_unsubscribe($i18n->get('no user email error message'));
}
$self->unsubscribe($user);
return $self->www_unsubscribe($i18n->get('You have been unsubscribed'));
}
#-------------------------------------------------------------------

View file

@ -904,9 +904,13 @@ sub view {
}
}
if ($self->get("shortcutToAssetId") eq $self->get("parentId")) {
$content = $i18n->get("Displaying this shortcut would cause a feedback loop");
} else {
if ($self->get("shortcutToAssetId") eq $self->get("parentId")) {
$content = $i18n->get("Displaying this shortcut would cause a feedback loop");
}
elsif (! $shortcut->canView) {
$content = '';
}
else {
# Make sure the www_view method won't be skipped b/c the asset is cached.
$shortcut->purgeCache();
@ -1214,10 +1218,12 @@ Render the shortcut in standalone mode.
=cut
sub www_view {
my $self = shift;
my $check = $self->checkView;
my $self = shift;
my $session = $self->session;
my $check = $self->checkView;
return $check if defined $check;
my $shortcut = $self->getShortcut;
return $session->privilege->noAccess() unless $shortcut->canView;
$self->prepareView;
# Make sure the www_view method won't be skipped b/c the asset is cached.

View file

@ -452,6 +452,14 @@ property postReceivedTemplateId => (
hoverHelp => [ 'post received template hoverHelp', 'Asset_Collaboration' ],
default => 'default_post_received1',
);
property unsubscribeTemplateId => (
fieldType => 'template',
namespace => 'Collaboration/Unsubscribe',
tab => 'display',
label => [ 'unsubscribe template', 'Asset_Collaboration' ],
hoverHelp => [ 'unsubscribe template hoverHelp', 'Asset_Collaboration' ],
default => 'default_CS_unsubscribe',
);
with 'WebGUI::Role::Asset::RssFeed';
@ -1557,18 +1565,22 @@ sub subscribe {
#-------------------------------------------------------------------
=head2 unsubscribe ( )
=head2 unsubscribe ( [$user] )
Unsubscribes a user from this collaboration system
=head3 $user
An optional user object to unsubscribe. If the object isn't passed, then it uses the session user.
=cut
sub unsubscribe {
my $self = shift;
my $self = shift;
my $user = shift || $self->session->user;
my $group = WebGUI::Group->new($self->session,$self->subscriptionGroupId);
return
unless $group;
$group->deleteUsers([$self->session->user->userId],[$self->subscriptionGroupId]);
return unless $group;
$group->deleteUsers([$user->userId]);
}
@ -1706,24 +1718,64 @@ sub www_unarchiveAll {
#-------------------------------------------------------------------
=head2 www_unsubscribe ( )
=head2 www_unsubscribe ( [$message] )
The web method to unsubscribe from a collaboration.
=head3 $message
An error message to display to the user.
=cut
sub www_unsubscribe {
my $self = shift;
my $self = shift;
my $message = shift;
if($self->canSubscribe){
$self->unsubscribe;
return $self->www_view;
}else{
return $self->session->privilege->noAccess;
}
else {
my $session = $self->session;
my $i18n = WebGUI::International->new($session, 'Asset_Collaboration');
my $var = $self->get();
$var->{title} = $self->getTitle;
$var->{url} = $self->getUrl;
$var->{formHeader} = WebGUI::Form::formHeader($session)
. WebGUI::Form::hidden($session, { name => 'func', value => 'unsubscribeConfirm', }, ),
$var->{formFooter} = WebGUI::Form::formFooter($session),
$var->{formSubmit} = WebGUI::Form::submit($session, { value => $i18n->get('unsubscribe'), }),
$var->{formEmail} = WebGUI::Form::email($session, { name => 'userEmail', value => $session->form->process('userEmail'), }),
$var->{formMessage} = $message;
return $self->processStyle($self->processTemplate($var, $self->get("unsubscribeTemplateId")));
}
}
#-------------------------------------------------------------------
=head2 www_unsubscribeConfirm ( )
Process the unsubscribe form.
=cut
sub www_unsubscribeConfirm {
my $self = shift;
my $session = $self->session;
return $self->www_view unless $session->form->validToken;
my $email = $session->form->process('userEmail', 'email');
return $self->www_view unless $email;
my $user = WebGUI::User->newByEmail($session, $email);
my $i18n = WebGUI::International->new($session, 'Asset_Collaboration');
if (! $user) {
return $self->www_unsubscribe($i18n->get('no user email error message'));
}
$self->unsubscribe($user);
return $self->www_unsubscribe($i18n->get('You have been unsubscribed'));
}
#-------------------------------------------------------------------
=head2 www_view
Extend the base method to handle the visitor cache timeout.

View file

@ -1896,7 +1896,7 @@ className='WebGUI::Asset::Sku::EMSTicket' and state='published' and revisionDate
# gotta get to the page we're working with
$counter++;
next unless ($counter >= ($startIndex * $numberOfResults));
next unless ($counter >= $startIndex+1);
# publish the data for this ticket
my $description = $ticket->description;

View file

@ -43,16 +43,22 @@ for my $i ( 1 .. 5 ) {
with 'WebGUI::Role::Asset::AlwaysHidden';
with 'WebGUI::Role::Asset::RssFeed';
use strict;
use Carp qw( croak );
use File::Find;
use File::Spec;
use File::Temp qw{ tempdir };
use JSON qw();
use Image::ExifTool qw( :Public );
use JSON;
use Tie::IxHash;
use WebGUI::International;
use WebGUI::HTML;
use WebGUI::ProgressBar;
use WebGUI::Storage;
# Do not move this instruction!
use Archive::Any;
=head1 NAME
@ -88,6 +94,12 @@ The name of the file archive to import.
A base set of properties to add to each file in the archive.
=head3 sortBy
Order in which files should be added to the gallery album. Legal values are
'name', 'date' and 'fileOrder'. If missing or invalid, files will be added as
ordered in the archive (default; corresponding to 'fileOrder').
=head3 $outputSub
A callback to use for outputting data, most likely to a progress bar. It expects the
@ -100,6 +112,7 @@ sub addArchive {
my $self = shift;
my $filename = shift;
my $properties = shift;
my $sortBy = shift;
my $outputSub = shift || sub {};
my $gallery = $self->getParent;
my $session = $self->session;
@ -119,6 +132,33 @@ sub addArchive {
find( {
wanted => $wanted,
}, $tempdirName );
# Sort files by date
if ($sortBy eq 'date') {
# Hash for storing last modified timestamps
my %mtimes;
my $exifTool = Image::ExifTool->new;
# Make ExifTool return epoch timestamps
$exifTool->Options('DateFormat', '%s');
# Iterate through all files
foreach my $file (@files) {
# Extract exif data from image
$exifTool->ExtractInfo( $file );
# Get last modified timestamp from exif data
$mtimes{$file} = $exifTool->GetValue('ModifyDate');
# Use last modified date of file as fallback
$mtimes{$file} = (stat($file))[9] unless $mtimes{$file};
}
# Sort files based on last modified timestamps
@files = sort { $mtimes{$a} <=> $mtimes{$b} } @files;
}
# Sort files by name
elsif ($sortBy eq 'name') {
@files = sort @files;
}
for my $filePath (@files) {
my ($volume, $directory, $filename) = File::Spec->splitpath( $filePath );
@ -955,12 +995,29 @@ sub www_addArchive {
name => "keywords",
value => ( $form->get("keywords") ),
});
$var->{ form_location }
= WebGUI::Form::Text( $session, {
name => "location",
value => ( $form->get("location") ),
});
$var->{ form_friendsOnly }
= WebGUI::Form::yesNo( $session, {
name => "friendsOnly",
value => ( $form->get("friendsOnly") ),
});
$var->{ form_sortBy }
= WebGUI::Form::RadioList( $session, {
name => "sortBy",
value => [ "name" ],
options => {
name => $i18n->get("addArchive sortBy name", 'Asset_GalleryAlbum'),
date => $i18n->get("addArchive sortBy date", 'Asset_GalleryAlbum'),
fileOrder => $i18n->get("addArchive sortBy fileOrder", 'Asset_GalleryAlbum'),
},
});
return $self->processStyle(
$self->processTemplate($var, $self->getParent->templateIdAddArchive)
@ -978,26 +1035,39 @@ Process the form for adding an archive.
sub www_addArchiveSave {
my $self = shift;
# Return error message if the user viewing does not have permission to add files
return $self->session->privilege->insufficient unless $self->canAddFile;
my $session = $self->session;
my $form = $self->session->form;
my $i18n = WebGUI::International->new( $session, 'Asset_GalleryAlbum' );
my $pb = WebGUI::ProgressBar->new($session);
# Retrieve properties and sort order from form variables
my $properties = {
keywords => $form->get("keywords"),
location => $form->get("location"),
friendsOnly => $form->get("friendsOnly"),
};
my $sortBy = $form->get("sortBy");
# Create progress bar to keep the connection alive
$pb->start($i18n->get('Uploading archive'), $session->url->extras('adminConsole/assets.gif'));
# Retrieve storage containing the uploaded archive
my $storageId = $form->get("archive", "File");
my $storage = WebGUI::Storage->get( $session, $storageId );
if (!$storage) {
return $pb->finish($self->getUrl('func=addArchive;error='.$i18n->get('addArchive error too big')));
}
my $filename = $storage->getPath( $storage->getFiles->[0] );
eval { $self->addArchive( $filename, $properties, sub{ $pb->update(sprintf $i18n->get(shift), @_); }); };
# Get the full path to the archive
my $filename = $storage->getPath( $storage->getFiles->[0] );
# Try to add files in archive as photos
eval { $self->addArchive( $filename, $properties, $sortBy, sub{ $pb->update(sprintf $i18n->get(shift), @_); }); };
# Delete storage containing archive
$storage->delete;
if ( my $error = $@ ) {
return $pb->finish($self->getUrl('func=addArchive;error='.sprintf $i18n->get('addArchive error generic'), $error ));

View file

@ -71,11 +71,23 @@ property hasTerms => (
);
property sortItems => (
tab => 'properties',
fieldType => 'yesNo',
default => 1,
fieldType => 'selectBox',
default => 'none',
label => ['sortItemsLabel', 'Asset_SyndicatedContent'],
hoverHelp => ['sortItemsLabel description', 'Asset_SyndicatedContent'],
options => \&_sortItems_options,
);
sub _sortItems_options {
my $session = shift->session;
my $i18n = WebGUI::International->new($session,'Asset_SyndicatedContent');
tie my %o, 'Tie::IxHash', (
none => $i18n->get('no order'),
feed => $i18n->get('feed order'),
pubDate_asc => $i18n->get('publication date ascending'),
pubDate_des => $i18n->get('publication date descending'),
);
return \%o;
}
has '+uiLevel' => (
default => 6,
);
@ -114,11 +126,15 @@ Combines all feeds into a single XML::FeedPP object.
=cut
sub generateFeed {
my $self = shift;
my $limit = shift || $self->maxHeadlines;
my $self = shift;
my $limit = shift || $self->maxHeadlines;
my $session = $self->session;
my ( $log, $cache ) = $session->quick(qw( log cache ));
my $feed = XML::FeedPP::Atom->new();
my $log = $session->log;
my $cache = $session->cache;
my $sort = $self->sortItems;
my %opt = (use_ixhash => 1) if $sort eq 'feed';
my $feed = XML::FeedPP::Atom->new(%opt);
# build one feed out of many
my $newlyCached = 0;
@ -151,7 +167,7 @@ sub generateFeed {
# care of any encoding specified in the XML prolog
utf8::downgrade($value, 1);
eval {
my $singleFeed = XML::FeedPP->new($value, utf8_flag => 1, -type => 'string');
my $singleFeed = XML::FeedPP->new($value, utf8_flag => 1, -type => 'string', %opt);
$feed->merge_channel($singleFeed);
$feed->merge_item($singleFeed);
};
@ -183,9 +199,14 @@ sub generateFeed {
}
# sort them by date and remove any duplicate from the OR based term matching above
if ($self->sortItems) {
if ($sort =~ /^pubDate/) {
$feed->sort_item();
}
if ($sort =~ /_asc$/) {
my @items = $feed->get_item;
$feed->clear_item;
$feed->add_item($_) for (reverse @items);
}
# limit the feed to the maximum number of headlines (or the feed generator limit).
$feed->limit_item($limit);
@ -270,10 +291,19 @@ sub getTemplateVariables {
$item{descriptionFirst25words} =~ s/(((\S+)\s+){25}).*/$1/s;
$item{descriptionFirst10words} = $item{descriptionFirst25words};
$item{descriptionFirst10words} =~ s/(((\S+)\s+){10}).*/$1/s;
$item{descriptionFirst2paragraphs} = $item{description};
$item{descriptionFirst2paragraphs} =~ s/^((.*?\n){2}).*/$1/s;
$item{descriptionFirstParagraph} = $item{descriptionFirst2paragraphs};
$item{descriptionFirstParagraph} =~ s/^(.*?\n).*/$1/s;
if ($description =~ /<p>/) {
my $html = $description;
$html =~ tr/\n/ /s;
my @paragraphs = map { "<p>".$_."</p>" } WebGUI::HTML::splitTag($html,3);
$item{descriptionFirstParagraph} = $paragraphs[0];
$item{descriptionFirst2paragraphs} = join '', @paragraphs[0..1];
}
else {
$item{descriptionFirst2paragraphs} = $item{description};
$item{descriptionFirst2paragraphs} =~ s/^((.*?\n){2}).*/$1/s;
$item{descriptionFirstParagraph} = $item{descriptionFirst2paragraphs};
$item{descriptionFirstParagraph} =~ s/^(.*?\n).*/$1/s;
}
$item{descriptionFirst4sentences} = $item{description};
$item{descriptionFirst4sentences} =~ s/^((.*?\.){4}).*/$1/s;
$item{descriptionFirst3sentences} = $item{descriptionFirst4sentences};

View file

@ -502,6 +502,7 @@ sub view {
if(isIn($sortBy,@sortByUserProperties)){
$sortBy = 'users.'.$sortBy;
}
$sortBy = join '.', map { $self->session->db->quoteIdentifier($_) } split /\./, $sortBy;
$sql .= " order by ".$sortBy." ".$sortOrder;
($defaultPublicProfile) = $self->session->db->quickArray("SELECT dataDefault FROM userProfileField WHERE fieldName='publicProfile'");

View file

@ -972,19 +972,13 @@ sub www_search {
wikiHomeUrl=>$self->getUrl,
addPageUrl=>$self->getUrl("func=add;class=WebGUI::Asset::WikiPage;title=".$queryString),
};
if (defined $queryString) {
$self->session->scratch->set('wikiSearchQueryString', $queryString);
}
else {
$queryString = $self->session->scratch->get('wikiSearchQueryString');
}
$self->appendSearchBoxVars($var, $queryString);
if (length $queryString) {
my $search = WebGUI::Search->new($self->session);
$search->search({ keywords => $queryString,
lineage => [$self->lineage],
classes => ['WebGUI::Asset::WikiPage'] });
my $rs = $search->getPaginatorResultSet($self->getUrl("func=search"));
my $rs = $search->getPaginatorResultSet($self->getUrl("func=search;query=".$queryString));
$rs->appendTemplateVars($var);
my @results = ();
foreach my $row (@{$rs->getPageData}) {

View file

@ -232,36 +232,98 @@ sub paste {
=head2 www_copy ( )
Duplicates self, cuts duplicate, returns self->getContainer->www_view if canEdit. Otherwise returns an AdminConsole rendered as insufficient privilege.
Duplicates self, cuts duplicate, returns self->getContainer->www_view if
canEdit. Otherwise returns an AdminConsole rendered as insufficient privilege.
If with children/descendants is selected, a progress bar will be rendered.
=cut
sub www_copy {
my $self = shift;
return $self->session->privilege->insufficient
unless $self->canEdit;
my $self = shift;
my $session = $self->session;
return $session->privilege->insufficient unless $self->canEdit;
# with: 'children' || 'descendants' || ''
my $with = $self->session->form->get('with') || '';
my $newAsset;
if ($with) {
my $childrenOnly = $with eq 'children';
$newAsset = $self->duplicateBranch($childrenOnly);
my $with = $session->form->get('with');
if ($with eq 'children') {
$self->_wwwCopyChildren;
}
elsif ($with eq 'descendants') {
$self->_wwwCopyDescendants;
}
else {
$newAsset = $self->duplicate({skipAutoCommitWorkflows => 1});
$self->_wwwCopySingle;
}
my $i18n = WebGUI::International->new($self->session, 'Asset');
$newAsset->update({ title=>sprintf("%s (%s)",$self->getTitle,$i18n->get('copy'))});
}
#-------------------------------------------------------------------
sub _wwwCopyChildren { shift->_wwwCopyProgress(1) }
#-------------------------------------------------------------------
sub _wwwCopyDescendants { shift->_wwwCopyProgress(0) }
#-------------------------------------------------------------------
sub _wwwCopyFinish {
my ($self, $newAsset) = @_;
my $session = $self->session;
my $i18n = WebGUI::International->new($session, 'Asset');
my $title = sprintf("%s (%s)", $self->getTitle, $i18n->get('copy'));
$newAsset->update({ title => $title });
$newAsset->cut;
if (WebGUI::VersionTag->autoCommitWorkingIfEnabled($self->session, {
allowComments => 1,
returnUrl => $self->getUrl,
}) eq 'redirect') {
return undef;
};
return $self->session->asset($self->getContainer)->www_view;
my $result = WebGUI::VersionTag->autoCommitWorkingIfEnabled(
$session, {
allowComments => 1,
returnUrl => $self->getUrl,
}
);
my $redirect = $result eq 'redirect';
$session->asset($self->getContainer) unless $redirect;
return $redirect;
}
#-------------------------------------------------------------------
sub _wwwCopyProgress {
my ($self, $childrenOnly) = @_;
my $session = $self->session;
my $i18n = WebGUI::International->new($session, 'Asset');
# This could potentially time out, so we'll render a progress bar.
my $pb = WebGUI::ProgressBar->new($session);
my @stack;
return $pb->run(
title => $i18n->get('Copy Assets'),
icon => $session->url->extras('adminConsole/assets.gif'),
code => sub {
my $bar = shift;
my $newAsset = $self->duplicateBranch($childrenOnly);
$bar->update($i18n->get('cut'));
my $redirect = $self->_wwwCopyFinish($newAsset);
return $redirect ? $self->getUrl : $self->getContainer->getUrl;
},
wrap => {
'WebGUI::Asset::duplicateBranch' => sub {
my ($bar, $original, $asset, @args) = @_;
push(@stack, $asset->getTitle);
my $ret = $asset->$original(@args);
pop(@stack);
return $ret;
},
'WebGUI::Asset::duplicate' => sub {
my ($bar, $original, $asset, @args) = @_;
my $name = join '/', @stack, $asset->getTitle;
$bar->update($name);
return $asset->$original(@args);
},
}
);
}
#-------------------------------------------------------------------
sub _wwwCopySingle {
my $self = shift;
my $newAsset = $self->duplicate({skipAutoCommitWorkflows => 1});
my $redirect = $self->_wwwCopyFinish($newAsset);
return $redirect ? undef : $self->getContainer->www_view;
}
#-------------------------------------------------------------------

View file

@ -233,7 +233,7 @@ sub createAccount {
$formField = $field->formField($properties, undef, undef, undef, $defaultValue);
}
else {
$formField = $field->formField($properties, undef, undef, undef, undef, undef, 'useFormDefault');
$formField = $field->formField($properties);
}

View file

@ -1,151 +0,0 @@
package WebGUI::Cache::CHI;
use strict;
use base 'WebGUI::Cache';
use File::Temp qw/tempdir/;
use CHI;
=head1 NAME
WebGUI::Cache::CHI - CHI cache driver
=head1 DESCRIPTION
This is a WebGUI Cache driver to the CHI cache interface. This allows WebGUI
sites to use any CHI::Driver like FastMmap and Memcached
=head1 METHODS
=cut
#----------------------------------------------------------------------------
=head2 delete ( )
Delete the current key
=cut
sub delete {
my ( $self ) = @_;
return $self->{_chi}->remove( $self->{_key} );
}
#----------------------------------------------------------------------------
=head2 deleteChunk ( partialKey )
Delete multiple keys from the cache
=cut
sub deleteChunk {
my ( $self, $key ) = @_;
$key = $self->parseKey( $key );
for my $checkKey ( $self->{_chi}->get_keys ) {
if ( $checkKey =~ /^\Q$key/ ) {
$self->{_chi}->remove( $checkKey );
}
}
}
#----------------------------------------------------------------------------
=head2 flush ( )
Delete the entire cache namespace
=cut
sub flush {
my ( $self ) = @_;
$self->{_chi}->purge;
}
#----------------------------------------------------------------------------
=head2 get ( )
Get the data in the current key
=cut
sub get {
my ( $self ) = @_;
return $self->{_chi}->get( $self->{_key} );
}
#----------------------------------------------------------------------------
=head2 new ( session, key [, namespace] )
Create a new WebGUI::Cache object with the given key. The namespace defaults
to the current site's configuration file name
=cut
sub new {
my ( $class, $session, $key, $namespace ) = @_;
$namespace ||= $session->config->getFilename;
$key = $class->parseKey( $key );
# Create CHI object from config
my $chi;
unless ( $chi = $session->stow->get( "CHI" ) ) {
my $cacheConf = $session->config->get('cache');
$cacheConf->{namespace} = $namespace;
# Default values
my $resolveConf = sub {
my ($config) = @_;
if ( $config->{driver} =~ /DBI/ ) {
$config->{ dbh } = $session->db->dbh;
}
if ( $config->{driver} =~ /File|FastMmap|BerkeleyDB/ ) {
$config->{ root_dir } ||= tempdir();
}
};
$resolveConf->( $cacheConf );
if ( $cacheConf->{l1_cache} ) {
$resolveConf->( $cacheConf->{l1_cache} );
}
$chi = CHI->new( %{$cacheConf} );
$session->stow->set( "CHI", $chi );
}
return bless { _session => $session, _key => $key, _chi => $chi }, $class;
}
#----------------------------------------------------------------------------
=head2 set ( content [, ttl ] )
Set the content to the current key. ttl is the number of seconds the cache
should live.
=cut
sub set {
my ( $self, $content, $ttl ) = @_;
$ttl ||= 60;
$self->{_chi}->set( $self->{_key}, $content, $ttl );
return;
}
#----------------------------------------------------------------------------
=head2 stats ( )
Get the size of the cache
=cut
sub stats {
my ( $self ) = @_;
return $self->{_chi}->get_size;
}
1;

View file

@ -288,7 +288,7 @@ sub new {
#-------------------------------------------------------------------
=head2 rejectAddRequest ( inviteId )
=head2 rejectAddRequest ( inviteId[,sendNotification] )
Sends a rejection notice, and deletes the invitation.
@ -296,21 +296,30 @@ Sends a rejection notice, and deletes the invitation.
The id of an invitation.
=head3 sendNotification
Boolean indicating whether or not to send out the deny notification. Defaults to true
=cut
sub rejectAddRequest {
my $self = shift;
my $self = shift;
my $inviteId = shift;
my $notify = shift;
my $db = $self->session->db;
my $invite = $self->getAddRequest($inviteId);
my $i18n = WebGUI::International->new($self->session, "Friends");
my $inbox = WebGUI::Inbox->new($self->session);
$inbox->addMessage({
message => sprintf($i18n->get("friends invitation not accepted by user"), $self->user->getWholeName),
subject => $i18n->get('friends invitation not accepted'),
userId => $invite->{inviterId},
status => 'unread',
});
unless (defined $notify && !$notify) { #Notify is defined but not true
$inbox->addMessage({
message => sprintf($i18n->get("friends invitation not accepted by user"), $self->user->getWholeName),
subject => $i18n->get('friends invitation not accepted'),
userId => $invite->{inviterId},
status => 'unread',
});
}
$inbox->getMessage($invite->{messageId})->setStatus('completed');
$self->session->db->deleteRow("friendInvitations", "inviteId", $inviteId);
}

View file

@ -219,6 +219,46 @@ sub autoDelete {
return $self->get("autoDelete");
}
#-------------------------------------------------------------------
=head2 cacheGroupings ( user, is_member )
Adds a record to the grouping for this group into the cache.
=head3 user
User object to set cache for
=head3 is_member
Boolean which indicates whether or not the user passed in is a member of this group
=cut
sub cacheGroupings {
my $self = shift;
my $session = $self->session;
my $groupId = $self->getId;
my $user = shift;
my $isInGroup = shift || 0;
my $userId = $user->userId;
my $sessionId = $session->getId;
### Undocumented - groupMembers can be passed in if it they are already built.
#These exist specifically for WebGUI::User::isInGroup to use and should not be used elsewhere
#unless you know what you are doing
my $groupMembers = shift || $session->cache->get("groupMembers".$groupId) || {};
#Build cache in a special way for visitors
if($userId eq '1') {
$groupMembers->{$userId}->{$sessionId} = { isMember => $isInGroup };
}
else {
$groupMembers->{$userId} = { isMember => $isInGroup };
}
$session->cache->set("groupMembers". $groupId, $groupMembers, $self->groupCacheTimeout);
}
#-------------------------------------------------------------------
@ -229,12 +269,14 @@ Clears all caches for this group and any ancestor groups of the group.
=cut
sub clearCaches {
my $self = shift;
my $self = shift;
my $session = $self->session;
##Clear my cache and the cache of all groups above me.
my $groups = $self->getAllGroupsFor();
my $cache = $self->session->cache;
foreach my $group ( $self->getId, @{ $groups } ) {
$cache->remove("group_".$group);
$cache->remove("groupMembers".$group);
}
my $stow = $self->session->stow;
$stow->delete("groupObj");
@ -509,7 +551,7 @@ sub get {
=head2 getAllGroupsFor ( )
Returns an array reference containing a list of all groups this group is in, recursively.
Returns an array reference containing a list of all groupIds this group is in, recursively.
=cut
@ -563,12 +605,11 @@ sub getAllUsers {
$self->session->errorHandler->fatal("Endless recursive loop detected while determining groups in group.\nRequested groupId: ".$self->getId);
}
my $groups = $self->getGroupsIn();
##Have to iterate twice due to the withoutExpired clause.
foreach my $groupId (@{ $groups }) {
my $subGroup = WebGUI::Group->new($self->session, $groupId);
next
if !$subGroup;
push @users, @{ $subGroup->getAllUsers(1, $withoutExpired, $loopCount) };
push @users, @{ $subGroup->getAllUsers($withoutExpired, $loopCount) };
}
my %users = map { $_ => 1 } @users;
@users = keys %users;
@ -624,7 +665,7 @@ sub getDatabaseUsers {
=head2 getGroupsFor ( )
Returns an array reference containing a list of groups this group is in. This method
Returns an array reference containing a list of groupIds this group is in. This method
does not check recursively backwards up the list of groups.
=cut
@ -698,7 +739,7 @@ Returns the groupId for this group.
sub getId {
my $self = shift;
return $self->{_groupId};
return $self->{_groupId};
}
@ -943,6 +984,373 @@ sub getUsersNotIn {
}
#-------------------------------------------------------------------
=head2 hasDatabaseUser ( userId )
Determine if the user passed in is a member of this group via a database query.
Membership will always be false if no query or database link has been defined
for this group.
=head3 userId
id of the user to check for membership
=cut
sub hasDatabaseUser {
my $self = shift;
my $userId = shift;
my $session = $self->session;
my $gid = $self->getId;
my $query = $self->get("dbQuery");
my $dbLinkId = $self->get("databaseLinkId");
return 0 unless ($userId && $query && defined $dbLinkId);
my $dbLink = WebGUI::DatabaseLink->new($session,$dbLinkId);
unless (defined $dbLink) {
$session->log->error("The database link ".$dbLinkId." no longer exists even though group ".$gid." references it. Group $gid may not be working correctly");
return 0;
}
my $dbh = $dbLink->db;
unless (defined $dbh) {
$session->log->error("Link to database established by could not get database handler for group $gid. This group may not be working correctly");
$dbLink->disconnect;
return 0;
}
WebGUI::Macro::process($self->session,\$query);
#Try to speed up the query by adding a userId filter to the where clause
if ($query =~ m/^\s*SELECT\s*(.*)\s*FROM/i) {
my $uid_ident = $1;
$query =~ s/where/where $uid_ident = '$userId' and/i;
}
my $sth = $dbh->unconditionalRead($query);
unless(defined $sth) {
$session->log->error("Couldn't process unconditional read for database group with group id $gid. This group may not be working correctly");
return 0;
}
unless ($sth->errorCode < 1) {
$session->log->warn("There was a problem with the database query for group ID $gid.");
return 0;
}
while (my ($uid) = $sth->array) {
if ($uid eq $userId) {
return 1;
}
}
return 0;
}
#-------------------------------------------------------------------
=head2 hasIpUser ( userId )
Determine if the user passed in is a member of this group via the lastIP recorded
in the user's session and this group's IpFilter.
Membership will always be false if no IpFilter has been set
=head3 userId
id of the user to check for membership
=cut
sub hasIpUser {
my $self = shift;
my $userId = shift;
my $session = $self->session;
my $IpFilter = $self->ipFilter();
return 0 unless ($IpFilter && $userId);
$IpFilter =~ s/\s//g;
my @filters = split /;/, $IpFilter;
my @ips = $session->db->buildArray(
q{ select lastIP from userSession where expires > ? and userId = ? }
,[ time(), $userId ]
);
foreach my $ip (@ips) {
return 1 if (isInSubnet($ip,\@filters));
}
return 0;
}
#-------------------------------------------------------------------
=head2 hasKarmaUser ( userId )
Determine if the user passed in is a member of this group via the their current
karma setting and this group's karmaThreshold.
If karma is not enabled for this site, membership will always be false.
=head3 userId
id of the user to check for membership
=cut
sub hasKarmaUser {
my $self = shift;
my $userId = shift;
my $session = $self->session;
return 0 unless ($session->setting->get('useKarma') && $userId);
return $session->db->quickScalar(
q{ select count(*) from users where karma >= ? and userId = ? }
,[$self->karmaThreshold,$userId]
);
}
#-------------------------------------------------------------------
=head2 hasLDAPUser ( userId )
Determine if the user passed in is a member of this group via an LDAP
connection
If ldapLink, ldapGroup, and ldapGroupProperty are not configured for this group
membership will always be false.
#TODO - change the way this works to search LDAP for the dn associated with the
userId. That should speed this up a bunch for people using LDAP groups.
=head3 userId
id of the user to check for membership
=cut
sub hasLDAPUser {
my $self = shift;
my $userId = shift;
my $session = $self->session;
my @ldapUsers = ();
my $gid = $self->getId;
### Check LDAP
my $ldapLinkId = $self->get("ldapLinkId");
my $ldapGroup = $self->get("ldapGroup");
my $ldapGroupProperty = $self->get("ldapGroupProperty");
my $ldapRecursiveProperty = $self->get("ldapRecursiveProperty");
my $ldapRecurseFilter = $self->get("ldapRecursiveFilter");
return 0 unless ($ldapLinkId && $ldapGroup && $ldapGroupProperty && $userId);
my $ldapLink = WebGUI::LDAPLink->new($session,$ldapLinkId);
unless ($ldapLink && $ldapLink->bind) {
$self->session->errorHandler->warn("There was a problem connecting to LDAP link $ldapLinkId for group ID $gid.");
return 0;
}
my $people = [];
if($ldapRecursiveProperty) {
$ldapLink->recurseProperty($ldapGroup,$people,$ldapGroupProperty,$ldapRecursiveProperty,$ldapRecurseFilter);
} else {
$people = $ldapLink->getProperty($ldapGroup,$ldapGroupProperty);
}
$ldapLink->unbind;
foreach my $person (@{$people}) {
$person =~ s/\s*,\s*/,/g;
$person = lc($person);
my $personRegExp = "^uid=$person,";
my $uid = $session->db->quickScalar("select userId from authentication where authMethod='LDAP' and fieldName='connectDN' and lower(fieldData) = ? OR lower(fieldData) REGEXP ?",[$person,$personRegExp]);
return 1 if ($uid eq $userId);
}
return 0;
}
#-------------------------------------------------------------------
=head2 hasScratchUser ( userId )
Determine if the user passed in is a member of this group via session scratch
variable settings and this group's scratchFilter.
If no scratchFilter has been set for this group, membership will always be false.
=head3 userId
id of the user to check for membership
=cut
sub hasScratchUser {
my $self = shift;
my $userId = shift;
my $session = $self->session;
my $scratchFilter = $self->scratchFilter();
return 0 unless ($scratchFilter && $userId);
$scratchFilter =~ s/\s//g;
my @filters = split /;/, $scratchFilter;
my @scratchClauses = ();
my @scratchPlaceholders = ( $userId, time() );
foreach my $filter (@filters) {
my ($name, $value) = split /=/, $filter;
push @scratchClauses, "(s.name=? AND s.value=?)";
push @scratchPlaceholders, $name, $value;
}
my $scratchClause = join ' OR ', @scratchClauses;
my $query = qq{
select
count(*)
from
userSession u, userSessionScratch s
where
u.sessionId=s.sessionId AND
u.userId = ? AND
u.expires > ? AND
( $scratchClause )
};
return $session->db->quickScalar($query, [ @scratchPlaceholders ]);
}
#-------------------------------------------------------------------
=head2 hasUser ( user )
Determine if the user passed in is a member of one of the special groups
for this group
=head3 user
user object to check groups for
=cut
sub hasUser {
my $self = shift;
my $session = $self->session;
my $user = shift || WebGUI::User->new($session,3); #Check the admin account if no user is passed in
my $gid = $self->getId;
my $db = $session->db;
my $uid = $user->userId;
### Get what's in session cache for this group
my $isInGroup = $session->stow->get("isInGroup", { noclone => 1 }) || {};
### Check to see that we have a cache built for this user
my $hasCache = (exists $isInGroup->{$uid}->{cached});
### Return what is in the cache if we've already cached this group in the session.
return $isInGroup->{$uid}->{$gid} if ( exists $isInGroup->{$uid}->{$gid} );
### If we dont' have a cache yet, cache all of the groups this user is directly a member of
### this will only happen if there is no cache built for this user and it saves us from running one query per group
unless ($hasCache) {
### Get the list of groups this user is directly a member of
my @groups = $db->buildArray(
q{ select groupId from groupings where userId=? and expireDate > ? }
, [$uid,time()]
);
### Cache the groupings we find
map { $isInGroup->{$uid}->{$_} = 1 } @groups;
### Set a cached flag so someone else doesn't accidentally call stow before us and screw our quick caching method
$isInGroup->{$uid}->{cached} = 1;
### Stow the cache here because we have set the cache for other groups besides this one.
$session->stow->set("isInGroup",$isInGroup);
### Return if we found the user in this group
return 1 if ( $isInGroup->{$uid}->{$gid} );
}
### User was not found directly in this group. Create a list of groups to check deeply and add this group to that list
my $groupsToCheckDeeply = { $gid => 1 };
#Made it here because user is not in the group itself. Now check for direct existance in the sub groups.
#Now build a list of the subgroups for this group that the user is part of
### Check all of the sub groups for direct existance, caching all of the subgroups that we do not find the user
### in our list of groups that need to be checked more deeply
my @groups = ($gid); #Start checking sub groups of this group only
my $loopLimit = 100; #Set a loop limit just to be safe
while (scalar(@groups) && $loopLimit--) {
### Check all of the groups of groups for all of the current @groups array. The query below
### returns the group that was in the group along with whether or not the user is directly a member
my $sqlInStr = $db->quoteAndJoin(\@groups);
my $sth = $db->read(
qq{ select
groupGroupings.groupId, userId
from
groupGroupings
left join groupings on groupGroupings.groupId=groupings.groupId and userId=?
where
inGroup in ($sqlInStr)
}
,[$uid]
);
### Create a subgroup cache for this pass of the loop so we know what groups to check next
my $subgroupCache = {};
while (my ($groupId,$userId) = $sth->array){
next if ($subgroupCache->{$groupId}); #Skip subgroups we've already checked - nothing has changed
### Return true if we find that the user is in the sub group from the session cache - no need to stow any caches here
return 1 if ($isInGroup->{$uid}->{$groupId});
### If the userId field is not null, that means that this user is directly a member of this sub group
if($userId) {
### Stow the result and return true;
$isInGroup->{$uid}->{$groupId} = 1; #Cache the sub group results
$isInGroup->{$uid}->{$gid} = 1; #Cache the results for the group we are checking
$session->stow->set("isInGroup",$isInGroup); #Stow the Cache
return 1;
}
### We made it here because the user is not directly in the subgroup.
$subgroupCache->{$groupId} = 1; #Update the subgroup cache for the next outer loop pass
$groupsToCheckDeeply->{$groupId} = 1; #We need to check this group more deeply
}
### Get the next level of sub groups to check from the subgroupCache keys.
@groups = keys %{$subgroupCache};
}
### Made it here because the user is not directly in the group itself or directly in any of it's subgroups
### We should have a flattened list of groups in this group that we should now check one by one to see if the
### user is is a member via one of the other methods available for groups
foreach my $groupIdInGroup (keys %{$groupsToCheckDeeply}) {
### Instantiate the group
my $groupToCheck = __PACKAGE__->new($session,$groupIdInGroup);
### Check the 'has' method for each of the 'other' group methods available for this user
### perform checks in a least -> most expensive manner. If we find the user, stow the cache and return true
if( $groupToCheck->hasIpUser($uid)
|| $groupToCheck->hasKarmaUser($uid)
|| $groupToCheck->hasScratchUser($uid)
|| $groupToCheck->hasDatabaseUser($uid)
|| $groupToCheck->hasLDAPUser($uid)
) {
#Found the user in one of the 'other' group methods
$isInGroup->{$uid}->{$groupIdInGroup} = 1; #Cache the results for this group so we don't have to check it again
$isInGroup->{$uid}->{$gid} = 1; #Cache the results for the main group because we found the user in one of the subgroups
$session->stow->set("isInGroup",$isInGroup); #Stow the cache
return 1;
}
#Made it here because we did not find the user at all in this subgroup. Cache the result so we don't have to check this subgroup again.
$isInGroup->{$uid}->{$groupIdInGroup} = 0;
}
#If we made it here, that means the user is not in the group or any of it's sub groups
#Cache the result, stow the cache, and return false as this group does not contain the user.
$isInGroup->{$uid}->{$gid} = 0;
$session->stow->set("isInGroup",$isInGroup);
return 0;
}
#-------------------------------------------------------------------

View file

@ -199,6 +199,26 @@ our $HELP = {
related => [ ],
},
'collaboration unsubscribe template' => {
title => 'collaboration unsubscribe template title',
body => '',
fields => [],
isa => [],
variables => [
{ name => 'formHeader',
description => 'unsubscribe formHeader', },
{ name => 'formSubmit',
description => 'unsubscribe formSubmit', },
{ name => 'formEmail',
description => 'unsubscribe formEmail', },
{ name => 'formFooter',
description => 'unsubscribe formFooter', },
{ name => 'formMessage',
description => 'unsubscribe formMessage', },
],
related => [ ],
},
};
1;

View file

@ -250,10 +250,18 @@ our $HELP = {
name => 'form_keywords',
description => 'helpvar form_keywords',
},
{
name => 'form_location',
description => 'helpvar form_location',
},
{
name => 'form_friendsOnly',
description => 'helpvar form_friendsOnly',
},
{
name => 'form_sortBy',
description => 'helpvar form_sortBy',
},
],
},

View file

@ -184,6 +184,7 @@ A reference to the current session.
sub www_editProfile {
my $session = shift;
return $session->privilege->insufficient if $session->user->isVisitor;
my $instance = WebGUI::Content::Account->createInstance($session,"profile");
return $instance->displayContent($instance->callMethod("edit"));
}

View file

@ -145,20 +145,27 @@ A message to be displayed in the status bar.
=cut
{
# Keep the sprintf string short and don't recompute buffer breaker every time
# update is called
my $prefix = '<script type="text/javascript">
/* ' . 'BUFFER BREAKER ' x 1000 . ' */
updateWgProgressBar(';
my $format = q"'%dpx', '%s'";
my $suffix = ');
</script>
';
sub update {
my $self = shift;
my $message = shift;
$message =~ s/'/\\'/g; ##Encode single quotes for JSON;
$self->session->log->preventDebugOutput;
$self->{_counter} += 1;
my $counter = $self->{_counter} += 1;
my $modproxy_buffer_breaker = 'BUFFER BREAKER ' x 1000;
my $text = sprintf(<<EOJS, $self->{_counter}, $message);
<script type="text/javascript">
/* $modproxy_buffer_breaker */
updateWgProgressBar('%dpx', '%s');
</script>
EOJS
my $text = $prefix . sprintf($format, $counter, $message) . $suffix;
local $| = 1; # Tell modperl not to buffer the output
$self->session->output->print($text, 1); #skipMacros
if ($self->{_counter} > 600) {
@ -167,5 +174,92 @@ EOJS
return '';
}
1;
}
#-------------------------------------------------------------------
=head2 run ( options )
starts and finishes a progress bar, running some code in the middle. It
returns 'chunked' for convenience - if you don't use the return value, you
should return 'chunked' yourself.
The following keyword arguments are accepted (either as a bare hash or a
hashref).
=head3 code
A coderef to run in between starting and stopping the progress bar. It is
passed the progress bar instance as its first and only argument. It should
return the url to redirect to with finish(), or a false value.
=head3 arg
An argument (just one) to be passed to code when it is called.
=head3 title
See start().
=head3 icon
See start().
=head3 wrap
A hashref of subroutine names to code references. While code is being called,
these subroutines will be wrapped with the provided code references, which
will be passed the progress bar instance, the original code reference, and any
arguments it would have received, similiar to a Moose 'around' method, e.g.
wrap => {
'WebGUI::Asset::update' => sub {
my $bar = shift;
my $original = shift;
$bar->update('some message');
$original->(@_);
}
}
=cut
sub run {
my $self = shift;
my $args = $_[0];
$args = { @_ } unless ref $args eq 'HASH';
my %original;
my $wrap = $args->{wrap};
$self->start($args->{title}, $args->{icon});
my $url = eval {
for my $name (keys %$wrap) {
my $original = $original{$name} = do { no strict 'refs'; \&$name };
my $wrapper = $wrap->{$name};
no strict 'refs';
*$name = sub {
unshift(@_, $self, $original);
goto &$wrapper;
};
}
$args->{code}->($self, $args->{arg});
};
my $e = $@;
# Always, always restore coderefs
for my $name (keys %original) {
my $c = $original{$name};
if (ref $c eq 'CODE') {
no strict 'refs';
*$name = $c;
}
}
die $e if $e;
return $self->finish($url || $self->session->url->page);
}
1;

View file

@ -183,9 +183,10 @@ the one in this user's current session.
sub validToken {
my ($self) = @_;
my $session = $self->session;
$session->log->debug('HTTP method: '. $session->request->method);
$session->log->debug('CSRF token: '. $session->scratch->get('webguiCsrfToken'));
$session->log->warn('HTTP method: '. $session->request->method);
$session->log->warn('CSRF token: '. $session->scratch->get('webguiCsrfToken'));
return 0 unless $session->request->method eq 'POST';
$session->log->warn('Web token: '. $self->param('webguiCsrfToken'));
return 0 unless $self->param('webguiCsrfToken') eq $session->scratch->get('webguiCsrfToken');
return 1;
}

View file

@ -401,10 +401,16 @@ The string to make compliant. This is usually a page title or a filename.
=cut
sub makeCompliant {
my $self = shift;
my $url = shift;
my $i18n = WebGUI::International->new($self->session);
return $i18n->makeUrlCompliant($url);
my $self = shift;
my $url = shift;
$url =~ s{^\s+}{}; # remove leading whitespace
$url =~ s{\s+$}{}; # remove trailing whitespace
$url =~ s{^/+}{}; # remove leading slashes
$url =~ s{/+$}{}; # remove trailing slashes
$url =~ s{[^\w/:._-]+}{-}g; # replace anything aside from word or other allowed characters with dashes
$url =~ s{//+}{/}g; # remove double slashes
$url =~ s{--+}{-}g; # remove double dashes
return $url;
}
#-------------------------------------------------------------------

View file

@ -82,32 +82,33 @@ sub appendAddressFormVars {
$properties ||= {};
$prefix ||= '';
$var ||= {};
my $hasAddress = keys %{ $properties };
for ( qw{ address1 address2 address3 label firstName lastName city state organization } ) {
$var->{ $prefix . $_ . 'Field' } = WebGUI::Form::text( $session, {
name => $prefix . $_,
maxlength => 35,
defaultValue => $properties->{ $_ } || $form->get($prefix . $_),
defaultValue => $hasAddress ? $properties->{ $_ } : $form->get($prefix . $_),
} );
}
$var->{ $prefix . 'countryField' } =
WebGUI::Form::country( $session,{
name => $prefix . 'country',
defaultValue => $properties->{ country } || $form->get($prefix . 'country' ),
defaultValue => $hasAddress ? $properties->{ country } : $form->get($prefix . 'country' ),
} );
$var->{ $prefix . 'codeField' } =
WebGUI::Form::zipcode( $session, {
name => $prefix . 'code',
defaultValue => $properties->{ code } || $form->get($prefix . 'code' ),
defaultValue => $hasAddress ? $properties->{ code } : $form->get($prefix . 'code' ),
} );
$var->{ $prefix . 'phoneNumberField' } =
WebGUI::Form::phone( $session, {
name => $prefix . 'phoneNumber',
defaultValue => $properties->{ phoneNumber } || $form->get($prefix . 'phoneNumber' ),
defaultValue => $hasAddress ? $properties->{ phoneNumber } : $form->get($prefix . 'phoneNumber' ),
} );
$var->{ $prefix . 'emailField' } =
WebGUI::Form::email( $session, {
name => $prefix . 'email',
defaultValue => $properties->{ email } || $form->get($prefix . 'email' ),
defaultValue => $hasAddress ? $properties->{ email } : $form->get($prefix . 'email' ),
} );
}
@ -328,7 +329,7 @@ sub missingFields {
$addressData = $address;
}
my @missingFields = ();
FIELD: foreach my $field (qw/label firstName lastName address1 city code country phoneNumber/) {
FIELD: foreach my $field (qw/label firstName lastName address1 city state code country phoneNumber/) {
push @missingFields, $field if $addressData->{$field} eq '';
}
return @missingFields;

View file

@ -287,15 +287,39 @@ sub getBillingAddress {
#-------------------------------------------------------------------
=head2 getPaymentGateway ()
=head2 getI18nError ()
Returns the WebGUI::Shop::PayDriver object that is attached to this cart for payment.
Returns an internationalized version of the current error, if it exists.
=cut
sub getPaymentGateway {
my $self = shift;
return WebGUI::Shop::Pay->new($self->session)->getPaymentGateway($self->get("gatewayId"));
sub getI18nError {
my ($self) = @_;
my $error = $self->error;
my $i18n = WebGUI::International->new($self->session, 'Shop');
return $error eq 'no billing address' ? $i18n->get('no billing address')
: $error eq 'no shipping address' ? $i18n->get('no shipping address')
: $error eq 'billing label' ? $i18n->get('billing label')
: $error eq 'billing firstName' ? $i18n->get('billing firstName')
: $error eq 'billing lastName' ? $i18n->get('billing lastName')
: $error eq 'billing address1' ? $i18n->get('billing address1')
: $error eq 'billing city' ? $i18n->get('billing city')
: $error eq 'billing code' ? $i18n->get('billing code')
: $error eq 'billing state' ? $i18n->get('billing state')
: $error eq 'billing country' ? $i18n->get('billing country')
: $error eq 'billing phoneNumber' ? $i18n->get('billing phoneNumber')
: $error eq 'shipping label' ? $i18n->get('shipping label')
: $error eq 'shipping firstName' ? $i18n->get('shipping firstName')
: $error eq 'shipping lastName' ? $i18n->get('shipping lastName')
: $error eq 'shipping address1' ? $i18n->get('shipping address1')
: $error eq 'shipping city' ? $i18n->get('shipping city')
: $error eq 'shipping code' ? $i18n->get('shipping code')
: $error eq 'shipping state' ? $i18n->get('shipping state')
: $error eq 'shipping country' ? $i18n->get('shipping country')
: $error eq 'shipping phoneNumber' ? $i18n->get('shipping phoneNumber')
: $error eq 'no shipping method set' ? $i18n->get('Choose a shipping method and update the cart to checkout')
: $error eq 'no payment gateway set' ? $i18n->get('Choose a payment gateway and update the cart to checkout')
: $error ;
}
#-------------------------------------------------------------------
@ -377,6 +401,19 @@ sub getItemsByAssetId {
#-------------------------------------------------------------------
=head2 getPaymentGateway ()
Returns the WebGUI::Shop::PayDriver object that is attached to this cart for payment.
=cut
sub getPaymentGateway {
my $self = shift;
return WebGUI::Shop::Pay->new($self->session)->getPaymentGateway($self->get("gatewayId"));
}
#-------------------------------------------------------------------
=head2 getPosUser
Returns the userId of the user making a purchase. If there is a cashier and the cashier has specified a user, then that user will be returned. Otherwise, if it's a direct sale then $session->user will be returned.
@ -542,7 +579,7 @@ sub readyForCheckout {
}
if (my @missingFields = $book->missingFields($address->get)) {
$self->error($missingFields[0]);
$self->error('billing '.$missingFields[0]);
return 0;
}
@ -554,7 +591,7 @@ sub readyForCheckout {
}
if (my @missingFields = $book->missingFields($shipAddress->get)) {
$self->error($missingFields[0]);
$self->error('shipping '.$missingFields[0]);
return 0;
}
@ -702,8 +739,9 @@ Updates the cart totals, the address fields and the shipping and billing options
=cut
sub updateFromForm {
my $self = shift;
my $form = $self->session->form;
my $self = shift;
my $session = $self->session;
my $form = $session->form;
foreach my $item (@{$self->getItems}) {
if ($form->get("quantity-".$item->getId) ne "") {
eval { $item->setQuantity($form->get("quantity-".$item->getId)) };
@ -740,12 +778,12 @@ sub updateFromForm {
my $address = $self->getBillingAddress();
$address->update(\%billingData);
}
elsif ($billingAddressId ne 'new_address' && $billingAddressId) {
elsif ($billingAddressId ne 'new_address' && $billingAddressId ne 'update_address' && $billingAddressId) {
##User changed the address selector to another address field
$cartProperties->{billingAddressId} = $billingAddressId;
}
elsif (@missingBillingFields) {
$self->error('missing billing '.$missingBillingFields[0]);
$self->error('billing '.$missingBillingFields[0]);
}
else {
$self->session->log->warn('billing address: something else: ');
@ -763,7 +801,7 @@ sub updateFromForm {
my $shippingAddressId = $form->process('shippingAddressId');
##No missing shipping fields, if we set to the same as the billing fields
if (@missingShippingFields) {
$self->error('missing shipping '.$missingShippingFields[0]);
$self->error('shipping '.$missingShippingFields[0]);
}
if ($shippingAddressId eq 'new_address' && ! @missingShippingFields) {
##Add a new address
@ -775,7 +813,7 @@ sub updateFromForm {
my $address = $self->getBillingAddress();
$address->update(\%shippingData);
}
elsif ($shippingAddressId ne 'new_address' && $shippingAddressId) {
elsif ($shippingAddressId ne 'new_address' && $shippingAddressId ne 'update_address' && $shippingAddressId) {
$cartProperties->{shippingAddressId} = $shippingAddressId;
}
else {
@ -921,7 +959,7 @@ sub www_update {
##Handle rounding errors, and checkout immediately if the amount is 0 since
##at least the ITransact driver won't accept $0 checkout.
if (sprintf('%.2f', $total + $self->calculateShopCreditDeduction($total)) eq '0.00') {
my $transaction = WebGUI::Shop::Transaction->create($session, {self => $self});
my $transaction = WebGUI::Shop::Transaction->create($session, {cart => $self});
$transaction->completePurchase('zero', 'success', 'success');
$self->onCompletePurchase;
$transaction->sendNotifications();
@ -968,7 +1006,7 @@ sub www_view {
my %var = (
%{$self->get},
formHeader => WebGUI::Form::formHeader($session)
formHeader => WebGUI::Form::formHeader($session, { extras => q|id="wgCartId"|, })
. WebGUI::Form::hidden($session, {name=>"shop", value=>"cart"})
. WebGUI::Form::hidden($session, {name=>"method", value=>"update"})
. WebGUI::Form::hidden($session, {name=>"itemId", value=>""})
@ -1117,7 +1155,7 @@ sub www_view {
my $billingAddressId = $self->get('billingAddressId');
if ($billingAddressId) {
$billingAddressOptions{'update_address'} = $i18n->get('Update this address');
$billingAddressOptions{'update_address'} = sprintf $i18n->get('Update %s'), $self->getBillingAddress->get('label');
}
%billingAddressOptions = (%billingAddressOptions, %addressOptions);
@ -1133,7 +1171,7 @@ sub www_view {
my $shippingAddressId = $self->get('shippingAddressId');
if ($shippingAddressId) {
$shippingAddressOptions{'update_address'} = $i18n->get('Update this address');
$shippingAddressOptions{'update_address'} = sprintf $i18n->get('Update %s'), $self->getShippingAddress->get('label');
}
%shippingAddressOptions = (%shippingAddressOptions, %addressOptions);
@ -1183,12 +1221,12 @@ sub www_view {
$var{totalPrice} = $var{subtotalPrice} + $var{shippingPrice} + $var{tax};
my $credit = WebGUI::Shop::Credit->new($session, $posUser->userId);
$var{ inShopCreditAvailable } = $credit->getSum;
$var{ inShopCreditDeduction } = $credit->calculateDeduction($var{totalPrice});
$var{ inShopCreditDeduction } = $self->calculateShopCreditDeduction($var{totalPrice});
$var{ totalPrice } = $self->formatCurrency($var{totalPrice} + $var{inShopCreditDeduction});
foreach my $field (qw/subtotalPrice inShopCreditAvailable inShopCreditDeduction totalPrice shippingPrice tax/) {
$var{$field} = sprintf q|<span id="%sWrap">%s</span>|, $field, $var{$field};
}
$var{ error } = $self->error;
$var{ error } = $self->getI18nError;
# render the cart
my $template = WebGUI::Asset->newById($session, $session->setting->get("shopCartTemplateId"));

View file

@ -49,8 +49,11 @@ The reason for this adjustment.
sub adjust {
my ($self, $amount, $comment) = @_;
my $user = WebGUI::User->new($self->session, $self->userId);
return 0 if $user->isVisitor;
$self->session->db->write("insert into shopCredit (creditId, userId, amount, comment, dateOfAdjustment) values (?,?,?,?,now())",
[$self->session->id->generate, $self->userId, $amount, $comment]);
return $amount;
}
#-------------------------------------------------------------------
@ -179,11 +182,11 @@ sub www_adjust {
my ($class, $session) = @_;
my $admin = WebGUI::Shop::Admin->new($session);
return $session->privilege->insufficient() unless $admin->canManage;
my $form = $session->form;
my $credit = $class->new($session, $form->get('userId'));
$credit->adjust($form->get('amount'), $form->get('comment'));
my $i18n = WebGUI::International->new($session, "Shop");
my $message = sprintf $i18n->get('add credit message'), $form->get('amount'), WebGUI::User->new($session, $form->get('userId'))->username, $credit->getSum;
my $form = $session->form;
my $credit = $class->new($session, $form->get('userId'));
my $amount = $credit->adjust($form->get('amount'), $form->get('comment'));
my $i18n = WebGUI::International->new($session, "Shop");
my $message = sprintf $i18n->get('add credit message'), $amount, WebGUI::User->new($session, $form->get('userId'))->username, $credit->getSum;
return $class->www_manage($session, $message);
}
@ -199,14 +202,16 @@ sub www_manage {
my ($class, $session, $message) = @_;
my $admin = WebGUI::Shop::Admin->new($session);
return $session->privilege->insufficient() unless $admin->canManage;
my $i18n = WebGUI::International->new($session, "Shop");
my $f = WebGUI::HTMLForm->new($session);
$f->hidden(name=>'shop',value=>'credit');
$f->hidden(name=>'method',value=>'adjust');
my $i18n = WebGUI::International->new($session, "Shop");
my $f = WebGUI::HTMLForm->new($session);
my $userId = $session->form->process('userId') || $session->user->userId;
my $user = WebGUI::User->new($session, $userId);
$f->hidden(name => 'shop', value => 'credit');
$f->hidden(name => 'method', value => 'adjust');
$f->user(
name => 'userId',
label => $i18n->get('username'),
value => $session->user->userId,
value => $userId,
);
$f->float(
name => 'amount',
@ -217,6 +222,10 @@ sub www_manage {
label => $i18n->get('notes'),
);
$f->submit;
if (! $message) {
my $credit = $class->new($session, $userId);
$message ||= sprintf $i18n->get('current credit message'), $user->username, $credit->getSum;
}
return $admin->getAdminConsole->render($message.$f->print, $i18n->get('in shop credit'));
}

View file

@ -895,7 +895,7 @@ sub isEnabled {
#-------------------------------------------------------------------
=head2 isInGroup ( [ groupId ] )
=head2 isInGroup ( [groupId ] )
Returns a boolean (0|1) value signifying that the user has the required privileges. Always returns true for Admins.
@ -906,38 +906,47 @@ The group that you wish to verify against the user. Defaults to group with Id 3
=cut
sub isInGroup {
my ($self, $gid) = @_;
$gid = 3 unless $gid;
my $uid = $self->userId;
### The following several checks are to increase performance. If this section were removed, everything would continue to work as normal.
#my $eh = $self->session->errorHandler;
#$eh->warn("Group Id is: $gid for ".$tgroup->name);
return 1 if ($gid eq '7'); # everyone is in the everyone group
return 1 if ($gid eq '1' && $uid eq '1'); # visitors are in the visitors group
return 1 if ($gid eq '2' && $uid ne '1'); # if you're not a visitor, then you're a registered user
### Get data for auxillary checks.
my $isInGroup = $self->session->stow->get("isInGroup", { noclone => 1 });
### Look to see if we've already looked up this group.
return $isInGroup->{$uid}{$gid} if exists $isInGroup->{$uid}{$gid};
### Lookup the actual groupings.
my $group = WebGUI::Group->new($self->session,$gid);
if ( !$group ) {
$group = WebGUI::Group->new($self->session,3);
}
### Check for groups of groups.
my $users = $group->getAllUsers();
foreach my $user (@{$users}) {
$isInGroup->{$user}{$gid} = 1;
if ($uid eq $user) {
$self->session->stow->set("isInGroup",$isInGroup);
return 1;
}
}
$isInGroup->{$uid}{$gid} = 0;
$self->session->stow->set("isInGroup",$isInGroup);
return 0;
}
my ($self, $gid) = @_;
my $session = $self->session;
my $uid = $self->userId;
$gid = 3 unless $gid;
### The following several checks are to increase performance. If this section were removed, everything would continue to work as normal.
return 1 if ($gid eq '7'); # everyone is in the everyone group
return 1 if ($gid eq '1' && $uid eq '1'); # visitors are in the visitors group
return 1 if ($gid eq '2' && $uid ne '1'); # if you're not a visitor, then you're a registered user
### Check stow before we check the cache. Stow is in memory and much faster
my $stow = $session->stow->get("isInGroup", { noclone => 1 }) || {};
return $stow->{$uid}->{$gid} if (exists $stow->{$uid}->{$gid});
### Don't bother checking File Cache if we already have a stow for this group.
### We can find what we need there and save ourselves a bunch of time
my $cache = undef;
my $groupMembers = undef;
unless ($stow->{$uid}->{$gid}) {
$groupMembers = $session->cache->get("groupMembers".$gid) || {};
#If we have this user's membership cached, return what we have stored
if (exists $groupMembers->{$uid}) {
return $groupMembers->{$uid}->{isMember} if (!$self->isVisitor);
return $groupMembers->{$uid}->{$session->getId}->{isMember} #Include the session check for visitors
}
}
### Instantiate the group
my $group = WebGUI::Group->new($session,$gid);
if ( !$group ) {
#Group is not valid, check the admin group
$group = WebGUI::Group->new($session,3);
}
#Check the group for membership
my $isInGroup = $group->hasUser($self);
#Write what we found to file cache
$group->cacheGroupings( $self, $isInGroup, $groupMembers );
return $isInGroup;
}
#-------------------------------------------------------------------

View file

@ -686,11 +686,15 @@ sub rollback {
my $revision = WebGUI::Asset->newById($session, $id, $revisionDate);
next REVISION unless $revision;
$outputSub->(sprintf $i18n->get('Rolling back %s'), $revision->getTitle);
$revision->purgeRevision;
$revision->purgeRevision;
}
my $instance = $self->getWorkflowInstance;
if ($instance) {
$instance->delete;
}
$session->db->write("delete from assetVersionTag where tagId=?", [$tagId]);
$self->clearWorking;
return 1;
$session->db->write("delete from assetVersionTag where tagId=?", [$tagId]);
$self->clearWorking;
return 1;
}
#-------------------------------------------------------------------

View file

@ -113,7 +113,8 @@ sub www_pickStyle {
my $f = $self->getForm;
my $i18n = WebGUI::International->new( $session, "WebGUI" );
my $output = '<h1>' . $i18n->get('1073') . '</h1>';
my $output = '<h1>' . $i18n->get('pick style') . '</h1>'
. '<p>' . $i18n->get('pick style description') . '</p>';
my @styleIds
= $session->db->buildArray(
@ -144,8 +145,9 @@ sub www_pickStyle {
my $class = ++$row % 2 ? " odd" : "";
# Prepare the synopsis
my $synopsis = WebGUI::HTML::format( $style->get('synopsis') );
my $synopsis = $style->get('synopsis');
$synopsis =~ s{(https?://\S+)}{<a href="$1">$1</a>}g;
$synopsis = WebGUI::HTML::format( $synopsis );
$f->raw(
'<div class="stylePicker' . $class . '"><label><input type="radio" name="styleTemplateId" value="' . $style->getId . '"/>'

View file

@ -87,7 +87,7 @@ h1 {
margin: 0;
padding-left: 120px;
background: url(' . $session->url->extras('wg.gif') . ') no-repeat;
background: url(' . $session->url->extras('wg.png') . ') no-repeat;
line-height: 100px;
}
@ -399,14 +399,13 @@ sub www_cleanup {
$starterForm->hidden( name => "styleTemplateId", value => $self->get('styleTemplateId') );
$starterForm->submit( value => $i18n->get( 'yes please' ) );
my $output = '<h1>' . $i18n->get('site starter title') . '</h1>';
$output .= ' <p>' . $i18n->get('site starter body') . '</p>'
my $homeForm = WebGUI::HTMLForm->new( $session, { action => $session->url->gateway, method => "GET" } );
$homeForm->submit( value => $i18n->get('no thanks') );
my $output = '<h1>' . $i18n->get('page builder title') . '</h1>';
$output .= ' <p>' . $i18n->get('page builder body') . '</p>'
. '<div style="float: left">' . $starterForm->print . '</div>'
. sprintf(
'<div style="float: left"><a href="%s">%s</a></div>',
$session->url->gateway,
$i18n->get('no thanks'),
)
. '<div style="float: left">' . $homeForm->print . '</div>'
. '<div style="clear: both">&nbsp;</div>'
;

View file

@ -87,7 +87,7 @@ sub execute {
while (my $invite = $pending->hashRef) {
my $sentOn = WebGUI::DateTime->new($session, $invite->{dateSent});
if (DateTime::Duration->compare($now - $sentOn, $outdated) == 1) {
WebGUI::Friends->new($session, WebGUI::User->new($session, $invite->{friendId}))->rejectAddRequest($invite->{inviteId});
WebGUI::Friends->new($session, WebGUI::User->new($session, $invite->{friendId}))->rejectAddRequest($invite->{inviteId},$session->setting->get("sendRejectNotice"));
}
if (time() - $start > $ttl) {
$pending->finish;

View file

@ -208,7 +208,9 @@ sub execute {
# Tag is approved
elsif ( $instance->getScratch("status") eq "approved" ) {
# Clean up after ourselves
$self->setMessageCompleted( $instance );
if (! $self->setMessageCompleted( $instance ) ) {
return $self->ERROR;
}
$instance->deleteScratch( "status" );
# We're done here
@ -278,7 +280,7 @@ sub sendMessage {
groupId => $groupId,
status => 'pending',
});
$messageIds = join ",", $messageIds, $message->getId;
$messageIds = $messageIds ? join(",", $messageIds, $message->getId) : $message->getId;
}
# Keep track of message Ids so we can complete them
@ -335,23 +337,32 @@ workflow instance we're part of.
=cut
sub setMessageCompleted {
my $self = shift;
my $instance = shift;
my $inbox = WebGUI::Inbox->new( $self->session );
my $self = shift;
my $instance = shift;
my $inbox = WebGUI::Inbox->new( $self->session );
# Set all messages to completed
for my $messageId ( split /,/, $instance->getScratch("messageId") ) {
if($messageId){
my $message = $inbox->getMessage( $messageId );
$message->setCompleted if $message;
for my $messageId ( split /,/, $instance->getScratch("messageId") ) {
if ($messageId) {
my $message = $inbox->getMessage($messageId);
if ($message) {
$message->setCompleted;
}
else {
$self->session->log->error("Could not get inbox message for messageId: $messageId");
return 0;
}
}
}
else {
$self->session->log->error("Malformed workflow instance scratch variable messageId for instance: ". $instance->getId);
return 0;
}
} ## end for my $messageId ( split...)
$instance->deleteScratch( "messageId" );
return;
}
$instance->deleteScratch("messageId");
return 1;
} ## end sub setMessageCompleted
1;

View file

@ -11,16 +11,8 @@ our $LANGUAGE = {
};
sub makeUrlCompliant {
my $value = shift;
$value =~ s/\s+$//; #removes trailing whitespace
$value =~ s/^\s+//; #removes leading whitespace
$value =~ s/ /-/g; #replaces whitespace with hyphens
$value =~ s/\.$//; #removes trailing period
$value =~ s/[^\w\-\.\_\/]//g; #removes characters that would interfere with the url
$value =~ s/^\///; #removes a leading /
$value =~ s/\/$//; #removes a trailing /
$value =~ s/\/\//\//g; #removes double /
return $value;
my $url = shift;
return $url;
}

View file

@ -431,7 +431,7 @@ our $I18N = {
},
'invitation confirm message' => {
message => q{The following users were notified:},
message => q{The following actions were taken:},
lastUpdated => 1225724810,
},
@ -818,6 +818,18 @@ our $I18N = {
lastUpdated => 1242274703,
},
'send reject notice' => {
message => q|Send Reject Friend Notifications|,
context => q|Site setting. A notification is an email that is sent to the user being rejected.|,
lastUpdated => 1242274705,
},
'send reject notice help' => {
message => q|Choose whether or not, upon rejecting a friend request, a notification should be sent to the user being rejected.|,
lastUpdated => 1242274703,
},
};
1;

View file

@ -320,6 +320,11 @@ our $I18N = {
context => q|To remove an item from the clipboard, and put it on the current page.|
},
'Copy Assets' => {
message => q|Copy Assets|,
lastUpdated => 1273518396,
},
'Paste Assets' => {
message => q|Paste Assets|,
lastUpdated => 1245342798,

View file

@ -597,6 +597,12 @@ our $I18N = {
lastUpdated => 1109696029,
},
'Unsubscribe from %s' => {
message => q|Unsubscribe from %s|,
lastUpdated => 1274216526,
context => q|Label for the unsubscribe form. %s will be filled in with the title of the CS.|,
},
'url' => {
message => q|URL|,
lastUpdated => 1109696029,
@ -1580,17 +1586,37 @@ the Collaboration Asset, the user will be notified.|,
message => q|The assetId of this Collaboration System. Unlike the variable assetId, this one will not be overridden by the assetIds inside of Threads or Posts.|,
lastUpdated => 1170543345,
},
'subscription group label' => {
message => q|Subscription Group|,
lastUpdated => 1170543345,
},
'subscription group hoverHelp' => {
message => q|Manage the users in the subscription group for this Collaboration System|,
lastUpdated => 1170543345,
},
'unsubscribe template' => {
message => q|Unsubscribe Template|,
lastUpdated => 1274208100,
},
'unsubscribe template hoverHelp' => {
message => q|Choose a template to help a user, who is not logged in, unsubscribe from either the CS or from a Thread within it.|,
lastUpdated => 1274208493,
},
'unsubscribe instructions' => {
message => q|Please enter in the email address of the user who wants to unsubscribe|,
lastUpdated => 1274208493,
},
'no user email error message' => {
message => q|No user with that email can be found.|,
lastUpdated => 1274208493,
},
'group to edit label' => {
message => q|Group to Edit Posts|,
lastUpdated => 1206733328,
@ -1599,7 +1625,7 @@ the Collaboration Asset, the user will be notified.|,
message => q|A group that is allowed to edit posts after they have been submitted.|,
lastUpdated => 1269283819,
},
'use captcha label' => {
message => q|Use Post Captcha|,
lastUpdated => 1170543345,
@ -1609,7 +1635,7 @@ the Collaboration Asset, the user will be notified.|,
message => q|Choose whether or not to make users verify their humnanity before being able to post to this collaboration system|,
lastUpdated => 1170543345,
},
'captcha label' => {
message => q|Verify your humanity|,
lastUpdated => 1170543345,
@ -1631,7 +1657,7 @@ the Collaboration Asset, the user will be notified.|,
message => q|Keywords|,
lastUpdated => 1170543345,
},
'asset not committed' => {
message => q{<h1>Error!</h1><p>You need to commit this collaboration system before you can create a new thread</p>},
lastUpdated => 1166848379,
@ -1683,6 +1709,48 @@ the Collaboration Asset, the user will be notified.|,
lastUpdated => 0,
},
'unsubscribe formHeader' => {
message => q{HTML code to start the unsubscribe form.},
context => q{Template variable help},
lastUpdated => 0,
},
'unsubscribe formFooter' => {
message => q{HTML code to end the unsubscribe form.},
context => q{Template variable help},
lastUpdated => 0,
},
'unsubscribe formSubmit' => {
message => q{A button to submit the form.},
context => q{Template variable help},
lastUpdated => 0,
},
'unsubscribe formEmail' => {
message => q{A text form with email completion.},
context => q{Template variable help},
lastUpdated => 0,
},
'unsubscribe formMessage' => {
message => q{Internationalized messages to tell the user about errors and successes.},
context => q{Template variable help},
lastUpdated => 0,
},
'You have been unsubscribed' => {
message => q{You have been unsubscribed.},
context => q{status message},
lastUpdated => 0,
},
'collaboration unsubscribe template title' => {
message => q{Collaboration System Unsubscribe Template},
context => q{status message},
lastUpdated => 0,
},
};
1;

View file

@ -277,11 +277,21 @@ our $I18N = {
message => 'The keywords for the files being uploaded.',
lastUpdated => 0,
},
'helpvar form_location' => {
message => 'The location for the files being uploaded.',
lastUpdated => 0,
},
'helpvar form_friendsOnly' => {
message => 'Should the file be friends only?',
lastUpdated => 0,
},
'helpvar form_sortBy' => {
message => 'Property according to which photos should be sorted.',
lastUpdated => 0,
},
'helpvar url_yes' => {
message => 'Confirm the delete of this Album.',
@ -451,13 +461,43 @@ our $I18N = {
lastUpdated => 0,
context => 'Label for the "keywords" field of the Add Archive page',
},
'addArchive location' => {
message => 'Location',
lastUpdated => 0,
context => 'Label for the "location" field of the Add Archive page',
},
'addArchive friendsOnly' => {
message => 'Friends Only',
lastUpdated => 0,
context => 'Label for the "friends only" field of the Add Archive page',
context => 'Label for the "friendsOnly" field of the Add Archive page',
},
'addArchive sortBy' => {
message => 'Sort By',
lastUpdated => 0,
context => 'Label for the "sortBy" field of the Add Archive page',
},
'addArchive sortBy name' => {
message => 'Name',
lastUpdated => 0,
context => 'Label for the "Name" radio button',
},
'addArchive sortBy date' => {
message => 'Date',
lastUpdated => 0,
context => 'Label for the "Date" radio button',
},
'addArchive sortBy fileOrder' => {
message => 'File Order',
lastUpdated => 0,
context => 'Label for the "File Order" radio button',
},
'template addArchive title' => {
message => "Add Zip Archive",
lastUpdated => 0,

View file

@ -245,11 +245,33 @@ our $I18N = {
},
'sortItemsLabel' => {
message => q{Sort feed items by date?},
message => q{Sort items by},
},
'sortItemsLabel description' => {
message => q{If enabled, items will be sorted by date. If disabled, items will be left in the order they appear in the original feed.},
message => q{No order: items will be in semi-random order<br />
Publication Date: sort by item pubDate<br />
Feed Order: Items will be in the order they appeared in the feed}
},
'no order' => {
message => 'No Order',
context => 'name for the sortItems value that indicates that no sorting should be done '
},
'feed order' => {
message => 'Feed Order',
context => 'name for the sortItems value that indicates items should be in the order they appeared in the feed'
},
'publication date ascending' => {
message => 'Publication Date (oldest first)',
context => 'name for the sortItems value that indicates items should be sorted by publication date from oldest to newest'
},
'publication date descending' => {
message => 'Publication Date (newest first)',
context => 'name for the sortItems value that indicates items should be sorted by publication date from newest to oldest'
},
'syndicated content asset template variables title' => {

View file

@ -656,6 +656,12 @@ listing of pages that are related to a specific keyword?| },
context => q{template variable help},
},
'Sub-keywords' => {
message => q{Sub-keywords},
lastUpdated => 0,
context => q{template label},
},
};
1;

View file

@ -59,17 +59,6 @@ our $I18N = {
context => q|Hover help for the summary template field in the configuration form of the Cash module.|
},
'password' => {
message => q|Password|,
lastUpdated => 0,
context => q|Form label in the configuration form of the iTransact module.|
},
'password help' => {
message => q|The password for your ITransact account.|,
lastUpdated => 0,
context => q|Hover help for the password field in the configuration form of the iTransact module.|
},
'Pay' => {
message => q|Pay|,
lastUpdated => 0,

View file

@ -567,6 +567,12 @@ our $I18N = {
context => q|field label|
},
'current credit message' => {
message => q|%s has a total credit of %s.|,
lastUpdated => 0,
context => q|field label|
},
'amount' => {
message => q|Amount|,
lastUpdated => 1213632324,
@ -1695,6 +1701,12 @@ our $I18N = {
context => q|Label to make the user choose a shipping method|,
},
'Choose a payment gateway and update the cart to checkout' => {
message => q|Choose a payment gateway and update the cart to checkout|,
lastUpdated => 0,
context => q|Label to make the user choose a payment gateway|,
},
'receipt email template' => {
message => q|Receipt Email Template|,
lastUpdated => 0,
@ -1755,10 +1767,10 @@ our $I18N = {
context => q|form label for the cart. Allows user to build a new address.|
},
'Update this address' => {
message => q|Update this address|,
'Update %s' => {
message => q|Update address: %s|,
lastUpdated => 0,
context => q|form label for the cart. Allows user to build a new address.|
context => q|form label for the cart. Allows user to edit an existing address. %s will be replaced by the label for the currently selected address, if there is one.|
},
'Choose a payment method' => {
@ -1773,6 +1785,126 @@ our $I18N = {
context => q|form label for the cart. Allows user to choose a payment method. Bart Jol for Minister in 2012!|
},
'no billing address' => {
message => q|Please enter a billing address, or select an existing one.|,
lastUpdated => 0,
context => q|Cart error message|
},
'no shipping address' => {
message => q|Please enter a shipping address, or select an existing one.|,
lastUpdated => 0,
context => q|Cart error message|
},
'billing label' => {
message => q|Please enter a label for the billing address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'billing firstName' => {
message => q|Please enter a first name for the billing address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'billing lastName' => {
message => q|Please enter a last name for the billing address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'billing address1' => {
message => q|Please enter a street address for the billing address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'billing city' => {
message => q|Please enter a city for the billing address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'billing code' => {
message => q|Please enter a postal code for the billing address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'billing state' => {
message => q|Please enter a state or province for the billing address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'billing country' => {
message => q|Please enter a country for the billing address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'billing phoneNumber' => {
message => q|Please enter a phone number for the billing address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'shipping label' => {
message => q|Please enter a label for the shipping address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'shipping firstName' => {
message => q|Please enter a first name for the shipping address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'shipping lastName' => {
message => q|Please enter a last name for the shipping address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'shipping address1' => {
message => q|Please enter a street address for the shipping address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'shipping city' => {
message => q|Please enter a city for the shipping address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'shipping code' => {
message => q|Please enter a postal code for the shipping address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'shipping state' => {
message => q|Please enter a state or province for the shipping address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'shipping country' => {
message => q|Please enter a country for the shipping address.|,
lastUpdated => 0,
context => q|Cart error message|
},
'shipping phoneNumber' => {
message => q|Please enter a phone number for the shipping address.|,
lastUpdated => 0,
context => q|Cart error message|
},
};
1;

View file

@ -4237,14 +4237,14 @@ LongTruncOk=1</p>
context => q{Description for site setting},
},
'site starter title' => {
message => q{Site Starter},
'page builder title' => {
message => q{Page Builder},
lastUpdated => 0,
context => q{Title for the site starter screen.},
context => q{Title for the page builder screen.},
},
'site starter body' => {
message => q{Do you wish to use the WebGUI Site Starter, which will lead you through options to create a custom look and feel for your site, and set up some basic content areas?},
'page builder body' => {
message => q{Would you like to use the Page Builder to select a default set of pages to include on your site, such as an About Us page or discussion forum.},
lastUpdated => 0,
context => q{Body for the site starter screen.},
},
@ -4686,6 +4686,18 @@ Users may override this setting in their profile.
context => 'Label for buttons that take you someplace else'
},
'pick style' => {
message => 'Choose a Design',
lastUpdated => 0,
context => 'Header for the pick style template page',
},
'pick style description' => {
message => 'Select a design to apply to your site. All designs are created from templates that you will have access to from your site, so modifications can be made later.',
lastUpdate => 0,
context => 'Description for pick style template page',
},
};
1;

View file

@ -35,7 +35,7 @@ my $session = WebGUI::Test->session;
my @getTitleTests = getTitleTests($session);
plan tests => 120
plan tests => 121
+ 2*scalar(@getTitleTests) #same tests used for getTitle and getMenuTitle
;
@ -300,6 +300,7 @@ $session->setting->set('urlExtension', undef);
is($importNode->fixUrl('1234'.'_'x235 . 'abcdefghij'), '1234'.'_'x235 . 'abcdefghij', 'fixUrl leaves long URLs under 250 characters alone');
is($importNode->fixUrl('1234'.'_'x250 . 'abcdefghij'), '1234'.'_'x216, 'fixUrl truncates long URLs over 250 characters to 220 characters');
is $importNode->fixUrl('---'), '-', '... 3 dashes are collapsed down to a single dash';
$session->config->set('extrasURL', '/extras');
$session->config->set('uploadsURL', '/uploads');

View file

@ -22,7 +22,7 @@ use WebGUI::Asset;
use WebGUI::VersionTag;
use Test::More; # increment this value for each test you create
plan tests => 12;
plan tests => 27;
my $session = WebGUI::Test->session;
$session->user({userId => 3});
@ -95,9 +95,66 @@ WebGUI::Test->addToCleanup($newVersionTag);
####################################################
note "cut";
is($topFolder->cut, 1, 'returns 1 if successful' );
is($topFolder->state, 'clipboard', '... state set to trash on the trashed asset object');
is($topFolder->cloneFromDb->state, 'clipboard', '... state set to trash in db on object');
is($folder1a->cloneFromDb->state, 'clipboard-limbo', '... state set to clipboard-limbo on child #1');
is($folder1b->cloneFromDb->state, 'clipboard-limbo', '... state set to clipboard-limbo on child #2');
is($folder1a2->cloneFromDb->state, 'clipboard-limbo', '... state set to clipboard-limbo on grandchild #1-1');
is( $topFolder->cut, 1, 'cut: returns 1 if successful' );
is($topFolder->get('state'), 'clipboard', '... state set to trash on the trashed asset object');
is($topFolder->cloneFromDb->get('state'), 'clipboard', '... state set to trash in db on object');
is($folder1a->cloneFromDb->get('state'), 'clipboard-limbo', '... state set to clipboard-limbo on child #1');
is($folder1b->cloneFromDb->get('state'), 'clipboard-limbo', '... state set to clipboard-limbo on child #2');
is($folder1a2->cloneFromDb->get('state'), 'clipboard-limbo', '... state set to clipboard-limbo on grandchild #1-1');
sub is_tree_of_folders {
my ($asset, $depth, $pfx) = @_;
my $recursive; $recursive = sub {
my ($asset, $depth) = @_;
my $pfx = " $pfx $depth";
return 0 unless isa_ok($asset, 'WebGUI::Asset::Wobject::Folder',
"$pfx: this object");
my $children = $asset->getLineage(
['children'], {
statesToInclude => ['clipboard', 'clipboard-limbo' ],
returnObjects => 1,
}
);
return $depth < 2
? is(@$children, 0, "$pfx: leaf childless")
: is(@$children, 1, "$pfx: has child")
&& $recursive->($children->[0], $depth - 1);
};
my $pass = $recursive->($asset, $depth);
undef $recursive;
my $message = "$pfx is tree of folders";
return $pass ? pass $message : fail $message;
}
# test www_copy
my $tag = WebGUI::VersionTag->create($session);
$tag->setWorking;
WebGUI::Test->addToCleanup($tag);
my $tempspace = WebGUI::Asset->getTempspace($session);
my $folder = {className => 'WebGUI::Asset::Wobject::Folder'};
my $root = $tempspace->addChild($folder);
my $child = $root->addChild($folder);
my $grandchild = $child->addChild($folder);
sub copied {
for my $a (@{$tempspace->getAssetsInClipboard}) {
if ($a->getParent->getId eq $tempspace->getId) {
return $a;
}
}
return undef;
}
my @methods = qw(Single Children Descendants);
for my $i (0..2) {
my $meth = "_wwwCopy$methods[$i]";
$root->$meth();
my $clip = copied();
is_tree_of_folders($clip, $i+1, $meth);
$clip->purge;
}

View file

@ -25,7 +25,10 @@ use Test::Deep;
my $session = WebGUI::Test->session;
my $node = WebGUI::Asset->getImportNode($session);
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->set({name=>"Album Test"});
$versionTag->set({name=>"Add Archive to Album Test"});
addToCleanup($versionTag);
my $gallery
= $node->addChild({
className => "WebGUI::Asset::Wobject::Gallery",
@ -35,6 +38,7 @@ my $gallery
groupIdEdit => 3, # Admins
ownerUserId => 3, # Admin
});
my $album
= $gallery->addChild({
className => "WebGUI::Asset::Wobject::GalleryAlbum",
@ -46,48 +50,128 @@ my $album
skipAutoCommitWorkflows => 1,
});
$album->addArchive( WebGUI::Test->getTestCollateralPath('elephant_images.zip') );
# Properties applied to every photo in the archive
my $properties = {
keywords => "something",
location => "somewhere",
friendsOnly => "1",
};
$versionTag->commit;
#----------------------------------------------------------------------------
# Tests
plan tests => 5;
plan tests => 11;
#----------------------------------------------------------------------------
# Test the addArchive sub
# elephant_images.zip contains three jpgs: Aana1.jpg, Aana2.jpg, Aana3.jpg
$versionTag = WebGUI::VersionTag->getWorking($session);
$album->addArchive( WebGUI::Test->getTestCollateralPath('elephant_images.zip'), $properties );
my $images = $album->getLineage(['descendants'], { returnObjects => 1 });
is( scalar @$images, 3, "addArchive() adds one asset per image" );
cmp_deeply(
cmp_bag(
[ map { $_->get("filename") } @$images ],
bag( "Aana1.jpg", "Aana2.jpg", "Aana3.jpg" ),
[ "Aana1.jpg", "Aana2.jpg", "Aana3.jpg" ],
"Names of files attached to Photo assets match filenames in archive"
);
cmp_deeply(
cmp_bag(
[ map { $_->get("title") } @$images ],
bag( "Aana1", "Aana2", "Aana3" ),
[ "Aana1", "Aana2", "Aana3" ],
"Titles of Photo assets match filenames in archive excluding extensions"
);
cmp_deeply(
cmp_bag(
[ map { $_->get("menuTitle") } @$images ],
bag( "Aana1", "Aana2", "Aana3" ),
[ "Aana1", "Aana2", "Aana3" ],
"Menu titles of Photo assets match filenames in archive excluding extensions"
);
cmp_deeply(
cmp_bag(
[ map { $_->get("url") } @$images ],
bag(
[
$session->url->urlize( $album->getUrl . "/Aana1" ),
$session->url->urlize( $album->getUrl . "/Aana2" ),
$session->url->urlize( $album->getUrl . "/Aana3" ),
),
],
"URLs of Photo assets match filenames in archive excluding extensions"
);
cmp_bag(
[ map { $_->get("keywords") } @$images ],
[ "something", "something", "something" ],
"Keywords of Photo assets match keywords in properties"
);
cmp_bag(
[ map { $_->get("location") } @$images ],
[ "somewhere", "somewhere", "somewhere" ],
"Location of Photo assets match keywords in properties"
);
cmp_bag(
[ map { $_->get("friendsOnly") } @$images ],
[ "1", "1", "1" ],
"Photo assets are viewable by friends only"
);
# Empty gallery album
$versionTag->rollback;
#----------------------------------------------------------------------------
# Test the sorting option of addArchive sub
# gallery_archive_sorting_test.zip contains four jpgs: photo1.jpg, photo2.jpg, photo3.jpg and photo4.jpg
# The following test covers sorting by date and name. Testing fileOrder is not possible, because
# it's machine dependent.
$versionTag = WebGUI::VersionTag->getWorking($session);
# Add photos sorted by file order (default)
$album->addArchive( WebGUI::Test->getTestCollateralPath('gallery_archive_sorting_test.zip'), $properties, 'fileOrder' );
# Get all children
my $images = $album->getLineage(['descendants'], { returnObjects => 1 });
# Check order
cmp_bag(
[ map { $_->get("filename") } @{ $images } ],
[ "photo1.jpg", "photo4.jpg", "photo3.jpg", "photo2.jpg", ],
"Photos sorted by file order (all files exist)"
);
# Empty gallery album
$versionTag->rollback;
$versionTag = WebGUI::VersionTag->getWorking($session);
# Add photos sorted by date
$album->addArchive( WebGUI::Test->getTestCollateralPath('gallery_archive_sorting_test.zip'), $properties, 'date' );
# Get all children
my $images = $album->getLineage(['descendants'], { returnObjects => 1 });
# Check order
cmp_deeply(
[ map { $_->get("filename") } @$images ],
[ "photo4.jpg", "photo1.jpg", "photo3.jpg", "photo2.jpg" ],
"Photos sorted by date"
);
# Empty gallery album
$versionTag->rollback;
$versionTag = WebGUI::VersionTag->getWorking($session);
# Add photos sorted by name
$album->addArchive( WebGUI::Test->getTestCollateralPath('gallery_archive_sorting_test.zip'), $properties, 'name' );
# Get all children
my $images = $album->getLineage(['descendants'], { returnObjects => 1 });
# Check order
cmp_deeply(
[ map { $_->get("filename") } @$images ],
[ "photo1.jpg", "photo2.jpg", "photo3.jpg", "photo4.jpg" ],
"Photos sorted by name"
);
# Empty gallery album
$versionTag->rollback;
#----------------------------------------------------------------------------
# Test the www_addArchive page
#----------------------------------------------------------------------------
# Cleanup
END {
$versionTag->rollback;
}

View file

@ -247,7 +247,7 @@ $session->user({userId => 1});
cmp_deeply(
$templateVars,
{
canPostStories => 0,
canPostStories => bool(0),
mode => 'view',
addStoryUrl => '',
date_loop => [
@ -411,9 +411,6 @@ $archive->update({storiesPerPage => 25});
$templateVars = $archive->viewTemplateVariables('search');
is($templateVars->{mode}, 'search', 'viewTemplateVariables mode == search');
use Data::Dumper;
diag Dumper $templateVars->{date_loop};
cmp_bag(
$templateVars->{date_loop},
[

View file

@ -20,7 +20,7 @@ use Data::Dumper;
use WebGUI::Test;
use WebGUI::Session;
use Test::More tests => 22; # increment this value for each test you create
use Test::More tests => 27; # increment this value for each test you create
use Test::Deep;
use WebGUI::Asset::Wobject::SyndicatedContent;
use XML::FeedPP;
@ -113,7 +113,7 @@ ok($processed_template, "A response was received from processTemplate.");
#
####################################################################
##Construct a feed with no description, so the resulting template variables can
##Construct a feed with no description so the resulting template variables can
##be checked for an undef description
my $feed = XML::FeedPP->new(<<EOFEED);
<?xml version="1.0" encoding="UTF-8" ?>
@ -140,37 +140,82 @@ EOFEED
my $vars = $syndicated_content->getTemplateVariables($feed);
ok( defined $vars->{item_loop}->[0]->{description}, 'getTemplateVariables: description is not undefined');
##Construct a feed with a wrapped description, to check for paragraph handling.
$feed = XML::FeedPP->new(<<EOFEED);
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>The WebGUI buglist</title>
<link>/tbb</link>
<copyright /><pubDate>Mon, 12 Oct 2009 11:54:28 -0500</pubDate>
<description />
<item>
<title>Description with wrapped HTML paragraphs</title>
<link>http://www.webgui.org/use/bugs/tracker/11563</link>
<author>serif</author>
<epochDate>1254854387</epochDate>
<guid isPermaLink="true">http://www.webgui.org/use/bugs/tracker/11563</guid>
<pubDate>Mon, 14 May 2010 8:12:00 -0500</pubDate>
<description>
&lt;p&gt;In the attached feed, there is a hidden return line character from the
Rich Text editor in the first sentence of the description. When using a Syndicated Content
for the feed, the variable descriptionFirstParagraph variable cuts off at this return line
character, creating invalid markup.&lt;/p&gt;
&lt;p&gt;No more text is shown of the first paragraph beyond the bold characters of the first line.&lt;/p&gt;
&lt;p&gt;Third paragraph, for completeness.&lt;/p&gt;
</description>
</item>
</channel>
</rss>
EOFEED
$vars = $syndicated_content->getTemplateVariables($feed);
is $vars->{item_loop}->[0]->{descriptionFirstParagraph},
"<p>In the attached feed, there is a hidden return line character from the Rich Text editor in the first sentence of the description. When using a Syndicated Content for the feed, the variable descriptionFirstParagraph variable cuts off at this return line character, creating invalid markup.</p>",
'... first paragraph, when HTML is used';
is $vars->{item_loop}->[0]->{descriptionFirst2paragraphs},
"<p>In the attached feed, there is a hidden return line character from the Rich Text editor in the first sentence of the description. When using a Syndicated Content for the feed, the variable descriptionFirstParagraph variable cuts off at this return line character, creating invalid markup.</p><p>No more text is shown of the first paragraph beyond the bold characters of the first line.</p>",
'... first paragraph, when HTML is used';
####################################################################
#
# generateFeed, hasTerms
#
####################################################################
my $tbbUrl = 'http://www.plainblack.com/tbb.rss';
$syndicated_content->update({
rssUrl => $tbbUrl,
hasTerms => 'WebGUI',
});
sub withCachedFeed {
my ($url, $path, $block) = @_;
$syndicated_content->update({ rssUrl => $url });
open my $rssFile, '<', WebGUI::Test->getTestCollateralPath('tbb.rss')
or die "Unable to get RSS file";
my $rssContent = do { local $/; <$rssFile>; };
close $rssFile;
$session->cache->set($tbbUrl, $rssContent, 60);
open my $file, '<', WebGUI::Test->getTestCollateralPath($path)
or die "Unable to get RSS file: $path";
my $content = do { local $/; <$file> };
close $file;
my $filteredFeed = $syndicated_content->generateFeed();
$session->cache->set($url, $content, 60);
$block->();
$session->cache->remove($url);
}
cmp_deeply(
[ map { $_->title } $filteredFeed->get_item() ],
[
'Google Picasa Plugin for WebGUI Gallery',
'WebGUI Roadmap',
'WebGUI 8 Performance',
],
'generateFeed: filters items based on the terms being in title, or description'
);
sub titles_are {
my ($expected, $message) = @_;
my $feed = $syndicated_content->generateFeed;
my @got = map { $_->title } $feed->get_item;
cmp_deeply \@got, $expected, $message;
}
$session->cache->remove($tbbUrl);
$syndicated_content->update({ hasTerms => 'WebGUI' });
withCachedFeed 'http://www.plainblack.com/tbb.rss', 'tbb.rss', sub {
titles_are(
[
'Google Picasa Plugin for WebGUI Gallery',
'WebGUI Roadmap',
'WebGUI 8 Performance',
],
'generateFeed: filters items based on the terms being in title, or description'
);
};
####################################################################
#
@ -178,25 +223,46 @@ $session->cache->remove($tbbUrl);
#
####################################################################
##Feed with no links or pubDates.
my $oncpUrl = 'http://www.oncp.gob.ve/oncp.xml';
$syndicated_content->update({
rssUrl => $oncpUrl,
hasTerms => '',
maxHeadlines => 50,
});
open my $rssFile, '<', WebGUI::Test->getTestCollateralPath('oncp.xml')
or die "Unable to get RSS file: oncp.xml";
my $rssContent = do { local $/; <$rssFile>; };
close $rssFile;
$session->cache->set($oncpUrl, $rssContent, 60);
withCachedFeed 'http://www.oncp.gob.ve/oncp.xml', 'oncp.xml', sub {
my $oddFeed1 = $syndicated_content->generateFeed();
my $oddFeed1 = $syndicated_content->generateFeed();
my @oddItems = $oddFeed1->get_item();
is (@oddItems, 13, 'feed has items even without pubDates or links');
};
my @oddItems = $oddFeed1->get_item();
is (@oddItems, 13, 'feed has items even without pubDates or links');
####################################################################
#
# sorting
#
####################################################################
$session->cache->remove($oncpUrl);
withCachedFeed 'http://www.plainblack.com/tbb.rss', 'tbb_odd.rss', sub {
my @ascending = (
'I have arrived in Lisboa!',
'WebGUI 8 Performance',
'WebGUI Roadmap',
'Google Picasa Plugin for WebGUI Gallery',
);
my @descending = reverse @ascending;
my @feed = (
'WebGUI Roadmap',
'Google Picasa Plugin for WebGUI Gallery',
'I have arrived in Lisboa!',
'WebGUI 8 Performance',
);
$syndicated_content->update({ sortItems => 'pubDate_asc' });
titles_are \@ascending, 'ascending sort';
$syndicated_content->update({ sortItems => 'pubDate_des' });
titles_are \@descending, 'descending sort';
$syndicated_content->update({ sortItems => 'feed' });
titles_are \@feed, 'feed order';
};

174
t/Group.t
View file

@ -73,8 +73,26 @@ my @ipTests = (
},
);
my @ldapTests = (
{
dn => 'uid=Byron Hadley,o=shawshank',
comment => 'bad dn for group',
expect => 0,
},
{
dn => 'uid=Andy Dufresne,o=shawshank',
comment => 'good dn for group',
expect => 1,
},
{
dn => 'uid=Bogs Diamond,o=shawshank',
comment => 'another good dn for group',
expect => 1,
},
);
plan tests => (151 + scalar(@scratchTests) + scalar(@ipTests)); # increment this value for each test you create
plan tests => (164 + (scalar(@scratchTests) * 2) + scalar(@ipTests)); # increment this value for each test you create
my $session = WebGUI::Test->session;
$session->cache->remove('myTestKey');
@ -165,16 +183,44 @@ $optionGroup->delete;
#
################################################################
my $ldapProps = WebGUI::Test->getSmokeLDAPProps();
$session->db->setRow('ldapLink', 'ldapLinkId', $ldapProps, $ldapProps->{ldapLinkId});
my $ldap = WebGUI::LDAPLink->new($session, $ldapProps->{ldapLinkId});
is($ldap->getValue("ldapLinkId"),$ldapProps->{ldapLinkId},'ldap link created properly');
addToCleanup($ldap);
my @shawshank;
foreach my $idx (0..$#ldapTests) {
$shawshank[$idx] = WebGUI::User->new($session, "new");
$shawshank[$idx]->username("shawshank$idx");
$shawshank[$idx]->authMethod("LDAP");
my $auth = $shawshank[$idx]->authInstance;
$auth->saveParams($shawshank[$idx]->getId,$shawshank[$idx]->authMethod,{
connectDN => $ldapTests[$idx]->{dn},
ldapConnection => $ldap->getValue("ldapLinkId"),
ldapUrl => $ldap->getValue("ldapUrl"),
});
}
WebGUI::Test->usersToDelete(@shawshank);
my $lGroup = WebGUI::Group->new($session, 'new');
$lGroup->ldapGroup('LDAP group');
is($lGroup->ldapGroup(), 'LDAP group', 'ldapGroup set and fetched correctly');
$lGroup->ldapGroup('cn=Convicts,o=shawshank');
is($lGroup->ldapGroup(), 'cn=Convicts,o=shawshank', 'ldapGroup set and fetched correctly');
$lGroup->ldapGroupProperty('LDAP group property');
is($lGroup->ldapGroupProperty(), 'LDAP group property', 'ldapGroup set and fetched correctly');
$lGroup->ldapGroupProperty('member');
is($lGroup->ldapGroupProperty(), 'member', 'ldapGroup set and fetched correctly');
$lGroup->ldapLinkId('LDAP link id');
is($lGroup->ldapLinkId(), 'LDAP link id', 'ldapLinkId set and fetched correctly');
$lGroup->ldapLinkId($ldapProps->{ldapLinkId});
is($lGroup->ldapLinkId(),$ldapProps->{ldapLinkId}, 'ldapLinkId set and fetched correctly');
is_deeply(
[ (map { $lGroup->hasLDAPUser($_->getId) } @shawshank) ],
[0, 1, 1],
'shawshank user 2, and 3 found in lGroup users from LDAP'
);
$lGroup->ldapRecursiveProperty('LDAP recursive property');
is($lGroup->ldapRecursiveProperty(), 'LDAP recursive property', 'ldapRecursiveProperty set and fetched correctly');
@ -240,6 +286,7 @@ cmp_bag($gB->getGroupsIn(), [$gA->getId, 3], 'Group A is in Group B');
cmp_bag($gA->getGroupsFor(), [$gB->getId], 'Group B contains Group A');
cmp_bag($gA->getGroupsIn(), [3], 'Admin added to group A automatically');
diag $gA->getId;
$gA->addGroups([$gB->getId]);
cmp_bag($gA->getGroupsIn(), [3], 'Not allowed to create recursive group loops');
@ -414,7 +461,7 @@ cmp_ok($expirationDate-time(), '>', 50, 'checking expire offset override on addU
################################################################
#
# getDatabaseUsers
# getDatabaseUsers & hasDatabaseUsers
#
################################################################
@ -435,7 +482,16 @@ cmp_bag($mobUsers, [map {$_->userId} @mob], 'verify SQL table built correctly');
is( $gY->databaseLinkId, 0, "Group Y's databaseLinkId is set to WebGUI");
$gY->dbQuery(q!select userId from myUserTable!);
is( $session->stow->get('isInGroup'), undef, 'setting dbQuery clears cached isInGroup');
$session->cache->remove($gZ->getId);
is( $mob[0]->isInGroup($gY->getId), 1, 'mob[0] is in group Y after setting dbQuery');
is( $mob[0]->isInGroup($gZ->getId), 1, 'mob[0] isInGroup Z');
ok( isIn($mob[0]->userId, @{ $gY->getAllUsers() }), 'mob[0] in list of group Y users');
ok( !isIn($mob[0]->userId, @{ $gZ->getUsers() }), 'mob[0] not in list of group Z users');
ok( isIn($mob[0]->userId, @{ $gZ->getAllUsers() }), 'mob[0] in list of group Z users, recursively');
$gY->clearCaches;
my @mobIds = map { $_->userId } @mob;
@ -445,13 +501,17 @@ cmp_bag(
'all mob users in list of group Y users from database'
);
is( $mob[0]->isInGroup($gY->getId), 1, 'mob[0] is in group Y after setting dbQuery');
is( $mob[0]->isInGroup($gZ->getId), 1, 'mob[0] isInGroup Z');
$session->db->write('delete from myUserTable where userId=?',[$mob[0]->getId]);
my $inDb = $session->db->quickScalar("select count(*) from myUserTable where userId=?",[$mob[0]->getId]);
ok ( !$inDb, 'mob[0] no longer in myUserTable');
WebGUI::Cache->new($session, ["groupMembers",$gY->getId])->delete; #Delete cache so we get a good test
$session->stow->delete("isInGroup"); #Delete stow so we get a good test
ok( isIn($mob[0]->userId, @{ $gY->getAllUsers() }), 'mob[0] in list of group Y users');
ok( !isIn($mob[0]->userId, @{ $gZ->getUsers() }), 'mob[0] not in list of group Z users');
ok( isIn($mob[0]->userId, @{ $gZ->getAllUsers() }), 'mob[0] in list of group Z users, recursively');
is_deeply(
[ (map { $gY->hasDatabaseUser($_->getId) } @mob) ],
[0, 1, 1],
'mob users 1,2 found in list of group Y users from database'
);
##Karma tests
@ -497,6 +557,12 @@ is_deeply(
'karma disabled in settings, no users in group'
);
is_deeply(
[ (map { $gK->hasKarmaUser($_->getId) } @chameleons) ],
[0, 0, 0, 0],
'karma disabled in settings, group K has no users via karma threshold'
);
$session->setting->set('useKarma', 1);
$gK->clearCaches; ##Clear cache since previous data is wrong
@ -506,6 +572,12 @@ is_deeply(
'chameleons 1, 2 and 3 are in group K via karma threshold'
);
is_deeply(
[ (map { $gK->hasKarmaUser($_->getId) } @chameleons) ],
[0, 1, 1, 1],
'group K has chameleons 1, 2 and 3 via karma threshold'
);
cmp_bag(
$gK->getKarmaUsers,
[ (map { $_->userId() } @chameleons[1..3]) ],
@ -560,10 +632,20 @@ foreach my $idx (0..$#scratchTests) {
WebGUI::Test->addToCleanup(@itchies);
WebGUI::Test->addToCleanup(@sessionBank);
#isInGroup test
foreach my $scratchTest (@scratchTests) {
is($scratchTest->{user}->isInGroup($gS->getId), $scratchTest->{expect}, $scratchTest->{comment});
}
WebGUI::Cache->new($session, $gS->getId)->delete(); ##Delete cached key for testing
$session->stow->delete("isInGroup");
#hasScratchUser test
foreach my $scratchTest (@scratchTests) {
is($gS->hasScratchUser($scratchTest->{user}->getId), $scratchTest->{expect}, $scratchTest->{comment}." - hasScratchUser");
}
cmp_bag(
$gS->getScratchUsers,
[ (map { $_->{user}->userId() } grep { $_->{expect} } @scratchTests) ],
@ -576,6 +658,33 @@ cmp_bag(
'getAllUsers for group with scratch'
);
{ ##Add scope to force cleanup
note "Checking for user Visitor session leak";
my $remoteSession = WebGUI::Test->newSession;
$remoteSession->user({userId => 1});
$remoteSession->scratch->set('remote','nok');
my $localScratchGroup = WebGUI::Group->new($session, 'new');
$localScratchGroup->name("Local IP Group");
$localScratchGroup->scratchFilter('local=ok');
ok !$remoteSession->user->isInGroup($localScratchGroup->getId), 'Remote Visitor fails to be in the scratch group';
my $localSession = WebGUI::Test->newSession;
WebGUI::Test->addToCleanup($localScratchGroup, $remoteSession, $localSession);
$localSession->user({userId => 1});
$remoteSession->scratch->set('local','ok');
$localScratchGroup->clearCaches;
ok $localSession->user->isInGroup($localScratchGroup->getId), 'Local Visitor is in the scratch group';
$remoteSession->stow->delete('isInGroup');
ok !$remoteSession->user->isInGroup($localScratchGroup->getId), 'Remove Visitor is not in the scratch group, even though a different Visitor passed';
}
@sessionBank = ();
my @tcps = ();
@ -617,10 +726,45 @@ cmp_bag(
'getUsers for group with IP filter'
);
is_deeply(
[ (map { $gI->hasIpUser($_->{user}->getId) } @ipTests) ],
[ (map { $_->{expect} } @ipTests) ],
'hasIpUsers for group with IP filter'
);
foreach my $ipTest (@ipTests) {
is($ipTest->{user}->isInGroup($gI->getId), $ipTest->{expect}, $ipTest->{comment});
}
{ ##Add scope to force cleanup
note "Checking for user Visitor session leak";
$ENV{REMOTE_ADDR} = '191.168.1.1';
my $remoteSession = WebGUI::Test->newSession;
$remoteSession->user({userId => 1});
my $localIpGroup = WebGUI::Group->new($session, 'new');
$localIpGroup->name("Local IP Group");
$localIpGroup->ipFilter('192.168.33.0/24');
ok !$remoteSession->user->isInGroup($localIpGroup->getId), 'Remote Visitor fails to be in the group';
$ENV{REMOTE_ADDR} = '192.168.33.1';
my $localSession = WebGUI::Test->newSession;
WebGUI::Test->addToCleanup($localIpGroup, $remoteSession, $localSession);
$localSession->user({userId => 1});
$localIpGroup->clearCaches;
ok $localSession->user->isInGroup($localIpGroup->getId), 'Local Visitor is in the group';
$remoteSession->stow->delete('isInGroup');
ok !$remoteSession->user->isInGroup($localIpGroup->getId), 'Remove Visitor is not in the group, even though a different Visitor passed';
}
##Cache check.
my $cacheDude = WebGUI::User->new($session, "new");

145
t/ProgressBar.t Normal file
View file

@ -0,0 +1,145 @@
#-------------------------------------------------------------------
# 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
#------------------------------------------------------------------
{
package WebGUI::Test::ProgressBar;
use warnings;
use strict;
sub new { bless {}, shift }
sub foo { $_[0]->{foo} = $_[1] }
sub bar { $_[0]->{bar} = $_[1] }
}
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";
use Test::More;
use Test::MockObject::Extends;
use WebGUI::Test;
use WebGUI::Session;
my $session = WebGUI::Test->session;
# Test the run method of ProgessBar -- it does some symbol table
# manipulation...
my $TestTitle = 'test title';
my $TestIcon = '/test/icon';
my $TestUrl = 'http://test.com/url';
my ($started, $finished);
my @updates = qw(one two not used);
sub mockbar {
Test::MockObject::Extends->new(WebGUI::ProgressBar->new($session));
}
my $pb = mockbar
->mock(start => sub {
my ($self, $title, $icon) = @_;
is $title, $TestTitle, 'title';
is $icon, $TestIcon, 'icon';
ok !$started, q"hadn't started yet";
$started = 1;
})
->mock(update => sub {
my ($self, $message) = @_;
my $expected = shift(@updates);
is $message, $expected, 'message';
})
->mock(finish => sub {
my ($self, $url) = @_;
is $url, $TestUrl, 'url';
ok !$finished, q"hadn't finished yet";
$finished = 1;
return 'chunked';
});
my $object = WebGUI::Test::ProgressBar->new;
ok !$object->{foo}, 'no foo';
ok !$object->{bar}, 'no bar';
sub wrapper {
my ($bar, $original, $obj, $val) = @_;
$bar->update($val);
$obj->$original($val);
}
is $pb->run(
arg => 'argument',
title => $TestTitle,
icon => $TestIcon,
code => sub {
my ($bar, $arg) = @_;
isa_ok $bar, 'WebGUI::ProgressBar', 'code invocant';
is $arg, 'argument', 'code argument';
ok $started, 'started';
ok !$finished, 'not finished yet';
is $object->foo('one'), 'one', 'wrapped return';
is $object->bar('two'), 'two', 'wrapped return (again)';
return $TestUrl;
},
wrap => {
'WebGUI::Test::ProgressBar::foo' => \&wrapper,
'WebGUI::Test::ProgressBar::bar' => \&wrapper,
}
), 'chunked', 'run return value';
ok $finished, 'finished now';
is $object->{foo}, 'one', 'foo original called';
is $object->{bar}, 'two', 'bar original called';
$object->foo('foo');
is $object->{foo}, 'foo', 'foo still works';
$object->bar('bar');
is $object->{bar}, 'bar', 'bar still works';
is @updates, 2, 'no shifting from updates after run';
delete @{$object}{qw(foo bar)};
my $updated;
# make sure that the symbol table machinations work even when something dies
$pb = mockbar->mock(start => sub {})
->mock(finish => sub {})
->mock(update => sub { $updated = 1 });
eval {
$pb->run(
code => sub {
$object->foo('foo');
$object->bar('bar');
},
wrap => {
'WebGUI::Test::ProgressBar::foo' => \&wrapper,
'WebGUI::Test::ProgressBar::bar' => sub { die "blar!\n" }
}
);
};
my $e = $@;
is $e, "blar!\n", 'exception propogated';
is $object->{foo}, 'foo', 'foo after die';
ok !$object->{bar}, 'bar did not get set';
$object->bar('bar');
is $object->{bar}, 'bar', 'but it works now';
ok $updated, 'update called for foo';
$updated = 0;
$object->foo('ignored');
ok !$updated, 'update not called for foo';
done_testing;
#vim:ft=perl

View file

@ -50,7 +50,7 @@ my @getRefererUrlTests = (
);
use Test::More;
plan tests => 79 + scalar(@getRefererUrlTests);
plan tests => 83 + scalar(@getRefererUrlTests);
my $session = WebGUI::Test->session;
my $request = $session->request;
@ -81,7 +81,7 @@ is( $url2, $url.'?a=b;c=d', 'append second pair');
#
#######################################
my $gateway = $session->config->get('gateway');
WebGUI::Test->originalConfig('gateway');
$session->config->set('gateway', '/');
is( $session->config->get('gateway'), '/', 'Set gateway for downstream tests');
@ -127,10 +127,7 @@ my $setting_hostToUse = $session->setting->get('hostToUse');
$session->setting->set('hostToUse', 'HTTP_HOST');
my $sitename = $session->config->get('sitename')->[0];
is( $session->url->getSiteURL, 'http://'.$sitename, 'getSiteURL from config as http_host');
my $config_port;
if ($session->config->get('webServerPort')) {
$config_port = $session->config->get('webServerPort');
}
WebGUI::Test->originalConfig('webServerPort');
$session->url->setSiteURL('http://webgui.org');
is( $session->url->getSiteURL, 'http://webgui.org', 'override config setting with setSiteURL');
@ -147,7 +144,7 @@ $env->{HTTP_HOST} = "devsite.com";
$session->url->setSiteURL(undef);
is( $session->url->getSiteURL, 'http://'.$sitename, 'getSiteURL where requested host is not a configured site');
my @config_sitename = @{ $session->config->get('sitename') };
WebGUI::Test->originalConfig('sitename');
$session->config->addToArray('sitename', 'devsite.com');
$session->url->setSiteURL(undef);
is( $session->url->getSiteURL, 'http://devsite.com', 'getSiteURL where requested host is not the first configured site');
@ -166,14 +163,7 @@ is( $session->url->getSiteURL, 'http://'.$sitename.':8880', 'getSiteURL with a n
$session->url->setSiteURL('http://'.$sitename);
is( $session->url->getSiteURL, 'http://'.$sitename, 'restore config setting');
$session->config->set('sitename', \@config_sitename);
$session->setting->set('hostToUse', $setting_hostToUse);
if ($config_port) {
$session->config->set('webServerPort', $config_port);
}
else {
$session->config->delete('webServerPort');
}
$url = 'level1 /level2/level3 ';
$url2 = 'level1-/level2/level3';
@ -277,14 +267,10 @@ is($session->url->makeAbsolute('page1'), '/page1', 'makeAbsolute: default baseUr
#
#######################################
my $origExtras = $session->config->get('extrasURL');
my $extras = $origExtras;
my $extras = WebGUI::Test->originalConfig('extrasURL');
my $savecdn = $session->config->get('cdn');
if ($savecdn) {
$session->config->delete('cdn');
}
# Note: the CDN configuration will be reverted in the END
WebGUI::Test->originalConfig('cdn');
$session->config->delete('cdn');
is($session->url->extras, $extras.'/', 'extras method returns URL to extras with a trailing slash');
is($session->url->extras('foo.html'), join('/', $extras,'foo.html'), 'extras method appends to the extras url');
@ -322,11 +308,6 @@ is($session->url->extras('/dir1/foo.html'), join('', $cdnCfg->{extrasSsl}, 'dir1
'extras using extrasSsl with HTTPS');
$env->{'psgi.url_scheme'} = "http";
$session->config->set('extrasURL', $origExtras);
# partial cleanup here; complete cleanup in END block
$session->config->delete('cdn');
#######################################
#
# escape and unescape
@ -354,10 +335,14 @@ is($session->url->urlize('HOME/PATH1'), 'home/path1', 'urlize: urls are lower ca
is($session->url->urlize('home/'), 'home', '... trailing slashes removed');
is($session->url->urlize('home is where the heart is'), 'home-is-where-the-heart-is', '... makeCompliant translates spaces to dashes');
is($session->url->urlize('/home'), 'home', '... removes initial slash');
is($session->url->urlize('home/../out-of-bounds'), 'home/out-of-bounds', '... removes multiple ../');
is($session->url->urlize('home/./here'), 'home/here', '... removes multiple ./');
is($session->url->urlize('home/../out-of-bounds'), 'home/out-of-bounds', '... removes ../');
is($session->url->urlize('home/./here'), 'home/here', '... removes ./');
is($session->url->urlize('home/../../out-of-bounds'), 'home/out-of-bounds', '... removes multiple ../');
is($session->url->urlize('home/././here'), 'home/here', '... removes multiple ./');
is($session->url->urlize('home -- here'), 'home-here', 'multiple dashes collapsed');
is($session->url->urlize('home!@#$%^&*here'), 'home-here', 'non-word characters collapsed to single dash');
is($session->url->urlize("home\x{2267}here"), 'home-here', 'non-word international characters removed');
is($session->url->urlize("home\x{1EE9}here"), "home\x{1EE9}here", 'word international characters not removed');
#######################################
#
@ -405,6 +390,7 @@ TODO: {
}
my $versionTag = WebGUI::VersionTag->getWorking($session);
WebGUI::Test->addToCleanup($versionTag);
my $statefulAsset = WebGUI::Asset->getRoot($session)->addChild({ className => 'WebGUI::Asset::Snippet' });
$versionTag->commit;
$session->asset( $statefulAsset );
@ -436,7 +422,7 @@ is(
#
#######################################
my $origSSLEnabled = $session->config->get('sslEnabled');
WebGUI::Test->originalConfig('sslEnabled');
##Test all the false cases, first
@ -472,9 +458,3 @@ ok($session->url->forceSecureConnection(), 'forced secure connection with no url
ok($session->http->isRedirect, '... and redirect status code was set');
is($session->http->getRedirectLocation, $secureUrl, '... and redirect status code was set');
$session->config->set('sslEnabled', $origSSLEnabled);
END { ##Always clean-up
$session->asset($sessionAsset);
$versionTag->rollback if defined $versionTag;
}

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>The Black Blog</title>
<link>/tbb</link>
<copyright/>
<pubDate>Mon, 12 Oct 2009 11:54:28 -0500</pubDate>
<description/>
<item>
<title>WebGUI Roadmap</title>
<link>http://www.plainblack.com/tbb/webgui-roadmap</link>
<author>JT</author>
<epochDate>1254325377</epochDate>
<guid isPermaLink="true">http://www.plainblack.com/tbb/webgui-roadmap</guid>
<pubDate>Wed, 30 Sep 2009 10:42:57 -0500</pubDate>
<userDefined1/>
<userDefined2/>
<userDefined3/>
<userDefined4/>
<userDefined5/>
<description>The new roadmap is online.</description>
</item>
<item>
<title>Google Picasa Plugin for WebGUI Gallery</title>
<link>http://www.plainblack.com/tbb/google-picasa-plugin-for-webgui-gallery</link>
<author>JT</author>
<epochDate>1254854387</epochDate>
<guid isPermaLink="true">http://www.plainblack.com/tbb/google-picasa-plugin-for-webgui-gallery</guid>
<pubDate>Tue, 06 Oct 2009 13:39:47 -0500</pubDate>
<userDefined1/>
<userDefined2/>
<userDefined3/>
<userDefined4/>
<userDefined5/>
<description>Today we unveil the Google Picasa plugin for WebGUI Gallery.</description>
</item>
<item>
<title>I have arrived in Lisboa!</title>
<link>http://www.plainblack.com/tbb/i-have-arrived-in-lisboa</link>
<author>JT</author>
<epochDate>1249140064</epochDate>
<guid isPermaLink="true">http://www.plainblack.com/tbb/i-have-arrived-in-lisboa</guid>
<pubDate>Sat, 01 Aug 2009 10:21:04 -0500</pubDate>
<userDefined1/>
<userDefined2/>
<userDefined3/>
<userDefined4/>
<userDefined5/>
<description>I&apos;m in Lisbon, Portugal for YAPC::EU.</description>
</item>
<item>
<title>WebGUI 8 Performance</title>
<link>http://www.plainblack.com/tbb/webgui-8-performance</link>
<author>JT</author>
<epochDate>1254236976</epochDate>
<guid isPermaLink="true">http://www.plainblack.com/tbb/webgui-8-performance</guid>
<pubDate>Tue, 29 Sep 2009 10:09:36 -0500</pubDate>
<userDefined1/>
<userDefined2/>
<userDefined3/>
<userDefined4/>
<userDefined5/>
<description>WebGUI 8 is going to be the fastest version of WebGUI ever released.</description>
</item>
</channel>
</rss>

View file

@ -71,7 +71,7 @@ sub moveMaintenance {
sub addMaintenancePageToConfig {
my $session = shift;
print "\tAdd maintenance page entry to the config file " unless $quiet;
$session->config->set('maintenancePage', '/data/WebGUI/var/www/maintenance.html');
$session->config->set('maintenancePage', '/data/WebGUI/www/maintenance.html');
print "DONE!\n" unless $quiet;
}
@ -79,9 +79,9 @@ sub moveFileLocations {
my $session = shift;
print "\tMoving preload files " unless $quiet;
unlink '../../sbin/preload.custom.example';
rename '../../sbin/preload.custom', File::Spec->catfile(WebGUI::Paths->etc, 'preload.custom');
rename '../../sbin/preload.custom', File::Spec->catfile(WebGUI::Paths->configBase, 'preload.custom');
unlink '../../sbin/preload.exclude.example';
rename '../../sbin/preload.exclude', File::Spec->catfile(WebGUI::Paths->etc, 'preload.exclude');
rename '../../sbin/preload.exclude', File::Spec->catfile(WebGUI::Paths->configBase, 'preload.exclude');
unlink '../../lib/default.ttf';
print "Done.\n" unless $quiet;
}

View file

@ -242,7 +242,7 @@
var self = this,
e = args.elements,
f = document.forms[0],
f = document.getElementById('wgCartId'),
checks = f.sameShippingAsBilling,
sameChange;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

BIN
www/extras/wg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB