Merge commit 'f2e0fb509a' into WebGUI8. Some tests still failing.
This commit is contained in:
commit
385931aaab
92 changed files with 1966 additions and 650 deletions
|
|
@ -1,3 +1,24 @@
|
|||
7.9.6
|
||||
- new checkbox in the asset manager for clearing the package flag on import
|
||||
- fixed #11597: manageTrash and newlines
|
||||
- fixed #11577: Gallery Album: "Sort by" radio list missing in "Add Archive" view
|
||||
- fixed #11576: Default WebGUI config has a bad macro
|
||||
- fixed #11578: Collaboration System: add edit stamp uses wrong user
|
||||
- added #9774: More owner information in the gallery
|
||||
- fixed #11581: Calendar problems
|
||||
- fixed #11583: EMS: Tokens do not follow their permissions
|
||||
- fixed #11584: Errors on checkout when payment problems occur
|
||||
- fixed #11582: Registering with a .mobi email address
|
||||
- fixed #11580: Date not populated for Story Archive RSS feed
|
||||
- fixed #11587: Thingy, no fields and undefined statement handles
|
||||
- fixed #11589: Syndicated Content: Return raw text for sentence and word template variables
|
||||
- fixed #11573: user has no way of knowing what they are currently using
|
||||
- fixed #11603: Shelf, template variables for sub shelves
|
||||
- added #11504: Allow search by location in the gallery
|
||||
- migrate to getLineageIterator to save memory
|
||||
- add findBrokenAssets.pl to find and fix/delete broken assets
|
||||
- change to use weaken() to save memory
|
||||
|
||||
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
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -17,6 +17,12 @@ save you many hours of grief.
|
|||
- Moose
|
||||
- CHI
|
||||
|
||||
|
||||
7.9.6
|
||||
--------------------------------------------------------------------
|
||||
* The javascript check for email addresses has been removed.
|
||||
|
||||
|
||||
7.9.5
|
||||
--------------------------------------------------------------------
|
||||
* Starting in WebGUI 7.9.4, the CHI and Cache::FastMmap modules are required.
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
161
docs/upgrades/upgrade_7.9.5-7.9.6.pl
Normal file
161
docs/upgrades/upgrade_7.9.5-7.9.6.pl
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# WebGUI is Copyright 2001-2009 Plain Black Corporation.
|
||||
#-------------------------------------------------------------------
|
||||
# Please read the legal notices (docs/legal.txt) and the license
|
||||
# (docs/license.txt) that came with this distribution before using
|
||||
# this software.
|
||||
#-------------------------------------------------------------------
|
||||
# http://www.plainblack.com info@plainblack.com
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
our ($webguiRoot);
|
||||
|
||||
BEGIN {
|
||||
$webguiRoot = "../..";
|
||||
unshift (@INC, $webguiRoot."/lib");
|
||||
}
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
use WebGUI::Session;
|
||||
use WebGUI::Storage;
|
||||
use WebGUI::Asset;
|
||||
|
||||
|
||||
my $toVersion = '7.9.6';
|
||||
my $quiet; # this line required
|
||||
|
||||
|
||||
my $session = start(); # this line required
|
||||
|
||||
# upgrade functions go here
|
||||
fixConvertUTCMacroName($session);
|
||||
dropOldEMSTableColumn($session);
|
||||
addIndexForInbox($session);
|
||||
|
||||
finish($session); # this line required
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Describe what our function does
|
||||
#sub exampleFunction {
|
||||
# my $session = shift;
|
||||
# print "\tWe're doing some stuff here that you should know about... " unless $quiet;
|
||||
# # and here's our code
|
||||
# print "DONE!\n" unless $quiet;
|
||||
#}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Add keys and indicies to groupGroupings to help speed up group queries
|
||||
sub addIndexForInbox {
|
||||
my $session = shift;
|
||||
print "\tAdding index to inbox_messageState... " unless $quiet;
|
||||
my $sth = $session->db->read('show create table inbox_messageState');
|
||||
my ($field,$stmt) = $sth->array;
|
||||
$sth->finish;
|
||||
unless ($stmt =~ m/KEY `userId_deleted_isRead`/i) {
|
||||
$session->db->write("alter table inbox_messageState add index userId_deleted_isRead (userId,deleted,isRead)");
|
||||
}
|
||||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Describe what our function does
|
||||
sub fixConvertUTCMacroName {
|
||||
my $session = shift;
|
||||
print "\tFix the name of the ConvertUTCToTZ macro in the config file... " unless $quiet;
|
||||
$session->config->deleteFromHash('macros', 'ConvertToUTC');
|
||||
$session->config->addToHash('macros', 'ConvertUTCToTZ', 'ConvertUTCToTZ');
|
||||
# and here's our code
|
||||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Describe what our function does
|
||||
sub dropOldEMSTableColumn {
|
||||
my $session = shift;
|
||||
print "\tDrop an old column from the EventMangementSystem table that is no longer used... " unless $quiet;
|
||||
$session->db->write(q|ALTER TABLE EventManagementSystem DROP COLUMN groupToApproveEvents|);
|
||||
# and here's our code
|
||||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
|
||||
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Add a package to the import node
|
||||
sub addPackage {
|
||||
my $session = shift;
|
||||
my $file = shift;
|
||||
|
||||
print "\tUpgrading package $file\n" unless $quiet;
|
||||
# Make a storage location for the package
|
||||
my $storage = WebGUI::Storage->createTemp( $session );
|
||||
$storage->addFileFromFilesystem( $file );
|
||||
|
||||
# Import the package into the import node
|
||||
my $package = eval {
|
||||
my $node = WebGUI::Asset->getImportNode($session);
|
||||
$node->importPackage( $storage, {
|
||||
overwriteLatest => 1,
|
||||
clearPackageFlag => 1,
|
||||
setDefaultTemplate => 1,
|
||||
} );
|
||||
};
|
||||
|
||||
if ($package eq 'corrupt') {
|
||||
die "Corrupt package found in $file. Stopping upgrade.\n";
|
||||
}
|
||||
if ($@ || !defined $package) {
|
||||
die "Error during package import on $file: $@\nStopping upgrade\n.";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#-------------------------------------------------
|
||||
sub start {
|
||||
my $configFile;
|
||||
$|=1; #disable output buffering
|
||||
GetOptions(
|
||||
'configFile=s'=>\$configFile,
|
||||
'quiet'=>\$quiet
|
||||
);
|
||||
my $session = WebGUI::Session->open($webguiRoot,$configFile);
|
||||
$session->user({userId=>3});
|
||||
my $versionTag = WebGUI::VersionTag->getWorking($session);
|
||||
$versionTag->set({name=>"Upgrade to ".$toVersion});
|
||||
return $session;
|
||||
}
|
||||
|
||||
#-------------------------------------------------
|
||||
sub finish {
|
||||
my $session = shift;
|
||||
updateTemplates($session);
|
||||
my $versionTag = WebGUI::VersionTag->getWorking($session);
|
||||
$versionTag->commit;
|
||||
$session->db->write("insert into webguiVersion values (".$session->db->quote($toVersion).",'upgrade',".time().")");
|
||||
$session->close();
|
||||
}
|
||||
|
||||
#-------------------------------------------------
|
||||
sub updateTemplates {
|
||||
my $session = shift;
|
||||
return undef unless (-d "packages-".$toVersion);
|
||||
print "\tUpdating packages.\n" unless ($quiet);
|
||||
opendir(DIR,"packages-".$toVersion);
|
||||
my @files = readdir(DIR);
|
||||
closedir(DIR);
|
||||
my $newFolder = undef;
|
||||
foreach my $file (@files) {
|
||||
next unless ($file =~ /\.wgpkg$/);
|
||||
# Fix the filename to include a path
|
||||
$file = "packages-" . $toVersion . "/" . $file;
|
||||
addPackage( $session, $file );
|
||||
}
|
||||
}
|
||||
|
||||
#vim:ft=perl
|
||||
|
|
@ -808,7 +808,7 @@
|
|||
"BackToSite" : "BackToSite",
|
||||
"CanEditText" : "CanEditText",
|
||||
"CartItemCount" : "CartItemCount",
|
||||
"ConvertToUTC" : "ConvertToUTC",
|
||||
"ConvertUTCToTZ" : "ConvertUTCToTZ",
|
||||
"c" : "c_companyName",
|
||||
"D" : "D_date",
|
||||
"DeactivateAccount": "DeactivateAccount",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ package WebGUI::Asset;
|
|||
|
||||
=cut
|
||||
|
||||
use Scalar::Util qw( blessed );
|
||||
use Scalar::Util qw( blessed weaken );
|
||||
use Clone qw(clone);
|
||||
use JSON;
|
||||
use HTML::Packer;
|
||||
|
|
|
|||
|
|
@ -585,8 +585,7 @@ sub getEventNext {
|
|||
'assetData.assetId',
|
||||
);
|
||||
|
||||
my $events = $self->getLineage(['siblings'], {
|
||||
#returnObjects => 1,
|
||||
my $events = $self->getLineageIterator(['siblings'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::Event'],
|
||||
joinClass => 'WebGUI::Asset::Event',
|
||||
orderByClause => join(",", @orderByColumns),
|
||||
|
|
@ -594,9 +593,12 @@ sub getEventNext {
|
|||
limit => 1,
|
||||
});
|
||||
|
||||
|
||||
return undef unless $events->[0];
|
||||
return WebGUI::Asset->newById($self->session,$events->[0]);
|
||||
my $nextEvent;
|
||||
eval { $nextEvent = $events->() };
|
||||
if ( WebGUI::Error->caught('WebGUI::Error::ObjecNotFound') ) {
|
||||
return undef; # Normal error
|
||||
}
|
||||
return $nextEvent;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -642,8 +644,7 @@ sub getEventPrev {
|
|||
'assetData.assetId DESC',
|
||||
);
|
||||
|
||||
my $events = $self->getLineage(['siblings'], {
|
||||
#returnObjects => 1,
|
||||
my $events = $self->getLineageIterator(['siblings'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::Event'],
|
||||
joinClass => 'WebGUI::Asset::Event',
|
||||
orderByClause => join(",",@orderByColumns),
|
||||
|
|
@ -651,8 +652,12 @@ sub getEventPrev {
|
|||
limit => 1,
|
||||
});
|
||||
|
||||
return undef unless $events->[0];
|
||||
return WebGUI::Asset->newById($self->session,$events->[0]);
|
||||
my $prevEvent;
|
||||
eval { $prevEvent = $events->() };
|
||||
if ( WebGUI::Error->caught( 'WebGUI::Error::ObjectNotFound' ) ) {
|
||||
return undef; # Normal error
|
||||
}
|
||||
return $prevEvent;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1490,35 +1495,46 @@ override processPropertiesFromFormPost => sub {
|
|||
|
||||
# Delete old events
|
||||
if ($old_id) {
|
||||
my $events = $self->getLineage(["siblings"], {
|
||||
returnObjects => 1,
|
||||
my $events = $self->getLineageIterator(["siblings"], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::Event'],
|
||||
joinClass => 'WebGUI::Asset::Event',
|
||||
whereClause => qq{Event.recurId = "$old_id"},
|
||||
});
|
||||
$_->purge for @$events;
|
||||
while ( 1 ) {
|
||||
my $event;
|
||||
eval { $event = $events->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error(sprintf "Couldn't instance event asset %s to delete it", $x->id);
|
||||
next;
|
||||
}
|
||||
last unless $event;
|
||||
$event->purge;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
# TODO: Give users a form property to decide what events to update
|
||||
# TODO: Make a workflow activity to do this, so that updating
|
||||
# 1 million events doesn't kill the server.
|
||||
# TODO: Make this use WebGUI::ProgressBar so 1 million events doesn't kill the server.
|
||||
# Just update related events
|
||||
my %properties = %{ $self->get };
|
||||
delete $properties{startDate};
|
||||
delete $properties{endDate};
|
||||
delete $properties{url}; # addRevision will create a new url for us
|
||||
|
||||
my $events = $self->getLineage(["siblings"], {
|
||||
#returnObjects => 1,
|
||||
my $events = $self->getLineageIterator(["siblings"], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::Event'],
|
||||
joinClass => 'WebGUI::Asset::Event',
|
||||
whereClause => q{Event.recurId = "}.$self->recurId.q{"},
|
||||
});
|
||||
|
||||
for my $eventId (@{$events}) {
|
||||
my $event = WebGUI::Asset->newById($session, $eventId);
|
||||
|
||||
while ( 1 ) {
|
||||
my $event;
|
||||
eval { $event = $events->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error(sprintf "Couldn't instance event asset %s to update it", $x->id);
|
||||
next;
|
||||
}
|
||||
last unless $event;
|
||||
# Add a revision
|
||||
$properties{ startDate } = $event->startDate;
|
||||
$properties{ endDate } = $event->endDate;
|
||||
|
|
|
|||
|
|
@ -371,6 +371,7 @@ around indexContent => sub {
|
|||
my $self = shift;
|
||||
my $indexer = $self->$orig(@_);
|
||||
$indexer->addFile($self->getStorageLocation->getPath($self->filename));
|
||||
return $indexer;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -549,7 +549,10 @@ sub getTemplateVars {
|
|||
$var->{ canComment } = $self->canComment;
|
||||
$var->{ canEdit } = $self->canEdit;
|
||||
$var->{ numberOfComments } = scalar @{ $self->getCommentIds };
|
||||
$var->{ ownerUsername } = $owner->profileField("alias") || $owner->username;
|
||||
$var->{ ownerUsername } = $owner->get("username");
|
||||
$var->{ ownerAlias } = $owner->get("alias") || $owner->get("username");
|
||||
$var->{ ownerId } = $owner->getId;
|
||||
$var->{ ownerProfileUrl } = $owner->getProfileUrl;
|
||||
$var->{ url } = $self->getUrl;
|
||||
$var->{ url_addArchive } = $self->getParent->getUrl('func=addArchive'),
|
||||
$var->{ url_delete } = $self->getUrl('func=delete');
|
||||
|
|
|
|||
|
|
@ -349,6 +349,22 @@ sub getThumbnailUrl {
|
|||
);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 indexContent ( )
|
||||
|
||||
Indexing the content of the Photo. See WebGUI::Asset::indexContent() for
|
||||
additonal details.
|
||||
|
||||
=cut
|
||||
|
||||
sub indexContent {
|
||||
my $self = shift;
|
||||
my $indexer = $self->SUPER::indexContent;
|
||||
$indexer->addKeywords($self->get("location"));
|
||||
return $indexer;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 makeResolutions ( [resolutions] )
|
||||
|
|
|
|||
|
|
@ -115,14 +115,12 @@ sub _fixReplyCount {
|
|||
my $self = shift;
|
||||
my $asset = shift;
|
||||
|
||||
my $lastPost = $asset->getLineage( [ qw{ self descendants } ], {
|
||||
returnObjects => 1,
|
||||
my $lastPostId = $asset->getLineage( [ qw{ self descendants } ], {
|
||||
isa => 'WebGUI::Asset::Post',
|
||||
orderByClause => 'assetData.revisionDate desc',
|
||||
limit => 1,
|
||||
} )->[0];
|
||||
|
||||
if ($lastPost) {
|
||||
if (my $lastPost = WebGUI::Asset->newById( $self->session, $lastPostId ) ) {
|
||||
$asset->incrementReplies( $lastPost->revisionDate, $lastPost->getId );
|
||||
}
|
||||
else {
|
||||
|
|
@ -690,23 +688,25 @@ sub getTemplateVars {
|
|||
unless ($self->storageId eq "") {
|
||||
my $storage = $self->getStorageLocation;
|
||||
foreach my $filename (@{$storage->getFiles}) {
|
||||
if (!$gotImage && $storage->isImage($filename)) {
|
||||
$var{"image.url"} = $storage->getUrl($filename);
|
||||
my $isImage = $storage->isImage($filename);
|
||||
my $fileUrl = $storage->getUrl($filename);
|
||||
if (!$gotImage && $isImage) {
|
||||
$var{"image.url"} = $fileUrl;
|
||||
$var{"image.thumbnail"} = $storage->getThumbnailUrl($filename);
|
||||
$gotImage = 1;
|
||||
}
|
||||
if (!$gotAttachment && !$storage->isImage($filename)) {
|
||||
$var{"attachment.url"} = $storage->getUrl($filename);
|
||||
if (!$gotAttachment && !$isImage) {
|
||||
$var{"attachment.url"} = $fileUrl;
|
||||
$var{"attachment.icon"} = $storage->getFileIconUrl($filename);
|
||||
$var{"attachment.name"} = $filename;
|
||||
$gotAttachment = 1;
|
||||
}
|
||||
push(@{$var{"attachment_loop"}}, {
|
||||
url=>$storage->getUrl($filename),
|
||||
icon=>$storage->getFileIconUrl($filename),
|
||||
filename=>$filename,
|
||||
thumbnail=>$storage->getThumbnailUrl($filename),
|
||||
isImage=>$storage->isImage($filename)
|
||||
url =>$fileUrl,
|
||||
icon =>$var{"attachment.icon"},
|
||||
filename =>$filename,
|
||||
thumbnail =>$var{"image.thumbnail"},
|
||||
isImage =>$isImage
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -983,10 +983,7 @@ override paste => sub {
|
|||
super();
|
||||
|
||||
# First, figure out what Thread we're under
|
||||
my $thread = $self->getLineage( [ qw{ self ancestors } ], {
|
||||
returnObjects => 1,
|
||||
isa => 'WebGUI::Asset::Post::Thread',
|
||||
} )->[0];
|
||||
my $thread = $self->getThread;
|
||||
|
||||
# If the pasted asset is not a thread we'll have to update the threadId of it and all posts below it.
|
||||
if ( $self->threadId ne $self->getId ) {
|
||||
|
|
@ -1083,10 +1080,9 @@ sub postProcess {
|
|||
$self->trash;
|
||||
}
|
||||
}
|
||||
my $user = WebGUI::User->new($self->session, $self->ownerUserId);
|
||||
my $i18n = WebGUI::International->new($self->session, "Asset_Post");
|
||||
if ($self->getThread->getParent->addEditStampToPosts) {
|
||||
$data{content} .= "<p>\n\n --- (".$i18n->get('Edited_on')." ".$self->session->datetime->epochToHuman(undef,"%z %Z [GMT%O]")." ".$i18n->get('By')." ".$user->profileField("alias").") --- \n</p>";
|
||||
if ($self->getThread->getParent->get("addEditStampToPosts")) {
|
||||
$data{content} .= "<p>\n\n --- (".$i18n->get('Edited_on')." ".$self->session->datetime->epochToHuman(undef,"%z %Z [GMT%O]")." ".$i18n->get('By')." ".$self->session->user->profileField("alias").") --- \n</p>";
|
||||
}
|
||||
$data{url} = $self->fixUrl($self->getThread->url."/1") if ($self->isReply && $self->isNew);
|
||||
$data{groupIdView} = $self->getThread->getParent->groupIdView;
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ Returns a list of the post objects in this thread, including the thread post its
|
|||
|
||||
sub getPosts {
|
||||
my $self = shift;
|
||||
$self->getLineage(["self","descendants"], {
|
||||
return $self->getLineage(["self","descendants"], {
|
||||
returnObjects => 1,
|
||||
includeArchived => 1,
|
||||
includeOnlyClasses => ["WebGUI::Asset::Post","WebGUI::Asset::Post::Thread"],
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ Takes form variable badgeId and add the token to the cart.
|
|||
|
||||
sub www_addToCart {
|
||||
my ($self) = @_;
|
||||
return $self->session->privilege->noAccess() unless $self->getParent->canView;
|
||||
return $self->session->privilege->noAccess() unless $self->getParent->canView && $self->canView;
|
||||
my $badgeId = $self->session->form->get('badgeId');
|
||||
$self->addToCart({badgeId=>$badgeId});
|
||||
return $self->getParent->www_buildBadge($badgeId);
|
||||
|
|
|
|||
|
|
@ -329,7 +329,15 @@ sub getThingOptions {
|
|||
tie my %options, 'Tie::IxHash', ( "" => "" );
|
||||
my $thingyIter = WebGUI::Asset->getRoot($session)
|
||||
->getLineageIterator( ['descendants'], { includeOnlyClasses => ['WebGUI::Asset::Wobject::Thingy'], } );
|
||||
while ( my $thingy = $thingyIter->() ) {
|
||||
while ( 1 ) {
|
||||
my $thingy;
|
||||
eval { $thingy = $thingyIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $thingy;
|
||||
|
||||
tie my %things, 'Tie::IxHash', (
|
||||
$session->db->buildHash( "SELECT thingId, label FROM Thingy_things WHERE assetId=?", [ $thingy->getId ] ) );
|
||||
$options{ $thingy->title } = \%things;
|
||||
|
|
|
|||
|
|
@ -506,8 +506,10 @@ sub getRssData {
|
|||
title => $self->headline || $self->getTitle,
|
||||
description => $self->story,
|
||||
'link' => $self->getUrl,
|
||||
guid => $self->getUrl,
|
||||
author => $self->byline,
|
||||
date => $self->lastModified,
|
||||
pubDate => $self->session->datetime->epochToMail($self->creationDate),
|
||||
};
|
||||
return $data;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -474,13 +474,19 @@ use WebGUI::Workflow::Cron;
|
|||
#-------------------------------------------------------------------
|
||||
sub _computePostCount {
|
||||
my $self = shift;
|
||||
return scalar @{$self->getLineage(['descendants'], {includeOnlyClasses => ['WebGUI::Asset::Post']})};
|
||||
return $self->getDescendantCount({
|
||||
includeOnlyClasses => ['WebGUI::Asset::Post'],
|
||||
statusToInclude => ['approved'],
|
||||
});
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub _computeThreadCount {
|
||||
my $self = shift;
|
||||
return scalar @{$self->getLineage(['children'], {includeOnlyClasses => ['WebGUI::Asset::Post::Thread']})};
|
||||
return $self->getChildCount({
|
||||
includeOnlyClasses => ['WebGUI::Asset::Post::Thread'],
|
||||
statusToInclude => ['approved'],
|
||||
});
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -1393,21 +1399,29 @@ and direction.
|
|||
|
||||
sub processPropertiesFromFormPost {
|
||||
my $self = shift;
|
||||
my $updatePrivs = ($self->session->form->process("groupIdView") ne $self->groupIdView || $self->session->form->process("groupIdEdit") ne $self->groupIdEdit);
|
||||
my $updatePrivs = ($self->session->form->process("groupIdView") ne $self->groupIdView || $self->session->form->process("groupIdEdit") ne $self->groupIdEdit);
|
||||
$self->next::method;
|
||||
if ($self->subscriptionGroupId eq "") {
|
||||
$self->createSubscriptionGroup;
|
||||
}
|
||||
if ($updatePrivs) {
|
||||
foreach my $descendant (@{$self->getLineage(["descendants"],{returnObjects=>1})}) {
|
||||
$descendant->update({
|
||||
groupIdView=>$self->groupIdView,
|
||||
groupIdEdit=>$self->groupIdEdit
|
||||
});
|
||||
}
|
||||
if ($updatePrivs) {
|
||||
my $descendantIter = $self->getLineageIterator(['descendants']);
|
||||
while ( 1 ) {
|
||||
my $descendant;
|
||||
eval { $descendant = $descendantIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $descendant;
|
||||
$descendant->update({
|
||||
groupIdView=>$self->groupIdView,
|
||||
groupIdEdit=>$self->groupIdEdit
|
||||
});
|
||||
}
|
||||
$self->session->scratch->delete($self->getId."_sortBy");
|
||||
$self->session->scratch->delete($self->getId."_sortDir");
|
||||
}
|
||||
$self->session->scratch->delete($self->getId."_sortBy");
|
||||
$self->session->scratch->delete($self->getId."_sortDir");
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1702,16 +1716,21 @@ sub www_unarchiveAll {
|
|||
my $pb = WebGUI::ProgressBar->new($session);
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_Collaboration');
|
||||
$pb->start($i18n->get('unarchive all'), $self->getUrl('func=edit'));
|
||||
my $threadIds = $self->getLineage(['children'],{
|
||||
my $threadIter = $self->getLineageIterator(['children'],{
|
||||
includeOnlyClasses => [ 'WebGUI::Asset::Post::Thread' ],
|
||||
statusToInclude => [ 'archived' ],
|
||||
} );
|
||||
ASSET: foreach my $threadId (@$threadIds) {
|
||||
my $thread = WebGUI::Asset->newPending($session, $threadId);
|
||||
if (!$thread || !$thread->canEdit) {
|
||||
next ASSET;
|
||||
ASSET: while ( 1 ) {
|
||||
my $thread;
|
||||
eval { $thread = $threadIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $thread;
|
||||
if ($thread->canEdit) {
|
||||
$thread->unarchive;
|
||||
}
|
||||
$thread->unarchive;
|
||||
}
|
||||
return $pb->finish( $self->getUrl('func=edit') );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,6 +175,45 @@ sub getContentPositionsDefault {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getEditForm
|
||||
|
||||
Extend the base method to display lists of assets to hide or show.
|
||||
|
||||
=cut
|
||||
|
||||
sub getEditForm {
|
||||
my $self = shift;
|
||||
my $tabform = $self->SUPER::getEditForm;
|
||||
my $i18n = WebGUI::International->new($self->session, "Asset_Dashboard");
|
||||
if ($self->session->form->process("func") ne "add") {
|
||||
my @assetsToHide = split("\n",$self->getValue("assetsToHide"));
|
||||
my $childIter = $self->getLineageIterator(["children"],{excludeClasses=>["WebGUI::Asset::Wobject::Layout"]});
|
||||
my %childIds;
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
$childIds{$child->getId} = $child->getTitle.' ['.ref($child).']';
|
||||
}
|
||||
$tabform->getTab("display")->checkList(
|
||||
-name=>"assetsToHide",
|
||||
-value=>\@assetsToHide,
|
||||
-options=>\%childIds,
|
||||
-label=>$i18n->get('assets to hide'),
|
||||
-hoverHelp=>$i18n->get('assets to hide description'),
|
||||
-vertical=>1,
|
||||
-uiLevel=>9
|
||||
);
|
||||
}
|
||||
return $tabform;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 initialize
|
||||
|
||||
Add the unique profile field that holds content positions for this dashboard.
|
||||
|
|
@ -218,18 +257,25 @@ their templates.
|
|||
|
||||
=cut
|
||||
|
||||
sub prepareView {
|
||||
override prepareView => sub {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView;
|
||||
my $children = $self->getLineage( ["children"], { returnObjects=>1, excludeClasses=>["WebGUI::Asset::Wobject::Layout","WebGUI::Asset::Wobject::Dashboard"] });
|
||||
super();
|
||||
my @hidden = split("\n",$self->assetsToHide);
|
||||
foreach my $child (@{$children}) {
|
||||
my $childIter = $self->getLineageIterator( ["children"], {excludeClasses=>["WebGUI::Asset::Wobject::Layout","WebGUI::Asset::Wobject::Dashboard"] });
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
unless (isIn($child->getId, @hidden) || !($child->canView)) {
|
||||
$self->session->style->setRawHeadTags($child->getExtraHeadTags);
|
||||
$child->prepareView;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -286,8 +332,9 @@ sub view {
|
|||
$self->session->style->setScript( $self->session->url->extras('yui/build/utilities/utilities.js'));
|
||||
|
||||
my $templateId = $self->templateId;
|
||||
my $children = $self->getLineage( ["children"], { returnObjects=>1, excludeClasses=>["WebGUI::Asset::Wobject::Layout","WebGUI::Asset::Wobject::Dashboard"] });
|
||||
# XXX Not using getLineageIterator because we loop over the children three times...
|
||||
# I'm sure there's a more efficient way to do this. We'll figure it out someday.
|
||||
my $children = $self->getLineage( ["children"], { returnObjects=>1, excludeClasses=>["WebGUI::Asset::Wobject::Layout","WebGUI::Asset::Wobject::Dashboard"] });
|
||||
my @positions = split(/\./,$self->getContentPositions);
|
||||
my @hidden = split("\n",$self->assetsToHide);
|
||||
foreach my $child (@{$children}) {
|
||||
|
|
|
|||
|
|
@ -615,10 +615,10 @@ returns true if the EMS has subission forms attached
|
|||
sub hasSubmissionForms {
|
||||
my $self = shift;
|
||||
# are there ~any~ forms attached to this ems?
|
||||
my $res = $self->getLineage(['children'],{ limit => 1,
|
||||
my $count = $self->getDescendantCount({
|
||||
includeOnlyClasses => ['WebGUI::Asset::EMSSubmissionForm'],
|
||||
} );
|
||||
return scalar(@$res);
|
||||
return $count;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -1046,12 +1046,12 @@ then call www_editSubmission on it
|
|||
sub www_editSubmission {
|
||||
my $self = shift;
|
||||
my $submissionId = $self->session->form->get('submissionId');
|
||||
my $asset = $self->getLineage(['descendants'], { returnObjects => 1,
|
||||
my $asset = $self->getLineageIterator(['descendants'], {
|
||||
joinClass => "WebGUI::Asset::EMSSubmission",
|
||||
whereClause => 'submissionId = ' . int($submissionId),
|
||||
includeOnlyClasses => ['WebGUI::Asset::EMSSubmission'],
|
||||
} );
|
||||
return $asset->[0]->www_editSubmission;
|
||||
return $asset->()->www_editSubmission;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1397,6 +1397,7 @@ sub www_getBadgesAsJson {
|
|||
my ($db, $form) = $session->quick(qw(db form));
|
||||
my %results = ();
|
||||
$results{records} = [];
|
||||
# TODO: Use getLineageIterator here instead
|
||||
BADGE: foreach my $badge (@{$self->getBadges}) {
|
||||
next BADGE unless $badge->canView;
|
||||
push(@{$results{records}}, {
|
||||
|
|
@ -1965,7 +1966,8 @@ sub www_getTokensAsJson {
|
|||
my ($db, $form) = $session->quick(qw(db form));
|
||||
my %results = ();
|
||||
$results{records} = []; ##Initialize to an empty array
|
||||
foreach my $token (@{$self->getTokens}) {
|
||||
TOKEN: foreach my $token (@{$self->getTokens}) {
|
||||
next TOKEN unless $token->canView;
|
||||
push(@{$results{records}}, {
|
||||
title => $token->getTitle,
|
||||
description => $token->description,
|
||||
|
|
|
|||
|
|
@ -104,7 +104,15 @@ Overridden to check the revision dates of children as well
|
|||
sub getContentLastModified {
|
||||
my $self = shift;
|
||||
my $mtime = $self->revisionDate;
|
||||
foreach my $child (@{ $self->getLineage(["children"],{returnObjects=>1}) }) {
|
||||
my $childIter = $self->getLineageIterator(["children"]);
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
my $child_mtime = $child->getContentLastModified;
|
||||
$mtime = $child_mtime if ($child_mtime > $mtime);
|
||||
}
|
||||
|
|
@ -216,17 +224,24 @@ sub view {
|
|||
my $vars = $self->getTemplateVars;
|
||||
# TODO: Getting the children template vars should be a seperate method.
|
||||
|
||||
my %rules = ( returnObjects => 1);
|
||||
my %rules = ( );
|
||||
if ( $self->sortAlphabetically ) {
|
||||
$rules{ orderByClause } = "assetData.title " . $self->sortOrder;
|
||||
$rules{ orderByClause } = "assetData.title " . $self->get( "sortOrder" );
|
||||
}
|
||||
else {
|
||||
$rules{ orderByClause } = "asset.lineage " . $self->sortOrder;
|
||||
}
|
||||
|
||||
my $children = $self->getLineage( ["children"], \%rules);
|
||||
foreach my $child ( @{ $children } ) {
|
||||
# TODO: Instead of this it should be using $child->getTemplateVars || $child->get
|
||||
my $childIter = $self->getLineageIterator( ["children"], \%rules);
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
# TODO: Instead of this it should be using $child->getTemplateVars || $child->get
|
||||
if ( $child->isa("WebGUI::Asset::Wobject::Folder") ) {
|
||||
push @{ $vars->{ "subfolder_loop" } }, {
|
||||
id => $child->getId,
|
||||
|
|
|
|||
|
|
@ -325,8 +325,8 @@ with 'WebGUI::Role::Asset::RssFeed';
|
|||
|
||||
|
||||
use JSON;
|
||||
use Tie::IxHash;
|
||||
use WebGUI::International;
|
||||
use WebGUI::Search;
|
||||
use XML::Simple;
|
||||
use WebGUI::HTML;
|
||||
|
||||
|
|
@ -388,7 +388,13 @@ sub appendTemplateVarsSearchForm {
|
|||
name => "keywords",
|
||||
value => scalar $form->get("keywords"),
|
||||
});
|
||||
|
||||
|
||||
$var->{ searchForm_location }
|
||||
= WebGUI::Form::text( $session, {
|
||||
name => "location",
|
||||
value => $form->get("location"),
|
||||
});
|
||||
|
||||
# Search classes
|
||||
tie my %searchClassOptions, 'Tie::IxHash', (
|
||||
'WebGUI::Asset::File::GalleryFile::Photo' => $i18n->get("search class photo"),
|
||||
|
|
@ -763,6 +769,7 @@ Other keys are valid, see C<WebGUI::Search::search()> for details.
|
|||
sub getSearchPaginator {
|
||||
my $self = shift;
|
||||
my $rules = shift;
|
||||
my $session = $self->session;
|
||||
|
||||
$rules->{ lineage } = [ $self->lineage ];
|
||||
|
||||
|
|
@ -913,17 +920,21 @@ sub hasSpaceAvailable {
|
|||
# Compile the amount of disk space used
|
||||
my $maxSpace = $self->maxSpacePerUser * ( 1_024 ** 2 ); # maxSpacePerUser is in MB
|
||||
my $spaceUsed = 0;
|
||||
my $fileIds
|
||||
= $self->getLineage( [ 'descendants' ], {
|
||||
my $fileIter
|
||||
= $self->getLineageIterator( [ 'descendants' ], {
|
||||
joinClass => 'WebGUI::Asset::File::GalleryFile',
|
||||
whereClause => 'ownerUserId = ' . $db->quote( $userId ),
|
||||
} );
|
||||
|
||||
for my $assetId ( @{ $fileIds } ) {
|
||||
my $asset = WebGUI::Asset->newById( $self->session, $assetId );
|
||||
next unless $asset;
|
||||
$spaceUsed += $asset->assetSize;
|
||||
|
||||
while ( 1 ) {
|
||||
my $file;
|
||||
eval { $file = $fileIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $file;
|
||||
$spaceUsed += $file->get( 'assetSize' );
|
||||
return 0 if ( $spaceUsed + $spaceWanted >= $maxSpace );
|
||||
}
|
||||
|
||||
|
|
@ -1340,45 +1351,61 @@ sub www_listAlbumsService {
|
|||
return JSON->new->pretty->encode($document);
|
||||
}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 www_search ( )
|
||||
=head2 search ( )
|
||||
|
||||
Search through the GalleryAlbums and files in this gallery. Show the form to
|
||||
search and display the results if necessary.
|
||||
Helper method for C<www_search> containing all the search logic. Executes a
|
||||
search depending on search form parameters. Returns undef if no search was
|
||||
executed. Otherwise an array is returned containing the following elements:
|
||||
|
||||
=head3 paginator
|
||||
|
||||
A paginator object containing the search results.
|
||||
|
||||
=head3 keywords
|
||||
|
||||
Search keywords assembled from search form fields.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_search {
|
||||
sub search {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $form = $session->form;
|
||||
my $db = $session->db;
|
||||
my $columns;
|
||||
|
||||
my $var = $self->getTemplateVars;
|
||||
# NOTE: Search form is added as part of getTemplateVars()
|
||||
|
||||
# Get search results, if necessary.
|
||||
# Check whether we have to do a search
|
||||
my $doSearch
|
||||
= (
|
||||
$form->get( 'basicSearch' ) || $form->get( 'keywords' )
|
||||
|| $form->get( 'title' ) || $form->get( 'description' )
|
||||
|| $form->get( 'userId' ) || $form->get( 'className' )
|
||||
|| $form->get( 'creationDate_after' ) || $form->get( 'creationDate_before' )
|
||||
$form->get( 'basicSearch' ) || $form->get( 'keywords' )
|
||||
|| $form->get( 'location' ) || $form->get( 'title' )
|
||||
|| $form->get( 'description' ) || $form->get( 'userId' )
|
||||
|| $form->get( 'className' ) || $form->get( 'creationDate_after' )
|
||||
|| $form->get( 'creationDate_before' )
|
||||
);
|
||||
|
||||
if ( $doSearch ) {
|
||||
# Keywords to search on
|
||||
# Do not add a space to the
|
||||
if ( $doSearch ) {
|
||||
# Keywords to search on.
|
||||
my $keywords;
|
||||
FORMVAR: foreach my $formVar (qw/ basicSearch keywords title description /) {
|
||||
FORMVAR: foreach my $formVar (qw/ basicSearch keywords location title description /) {
|
||||
my $var = $form->get($formVar);
|
||||
next FORMVAR unless $var;
|
||||
$keywords = join ' ', $keywords, $var;
|
||||
}
|
||||
# Remove leading whitespace
|
||||
$keywords =~ s/^\s+//;
|
||||
|
||||
# Build a where clause from the advanced options
|
||||
# Lineage search can capture gallery
|
||||
# Note that adding criteria to the where clause alone will not work. If
|
||||
# you want to cover additional properties you need to make sure that
|
||||
# - the property is added to $keywords above
|
||||
# - the property is included in index keywords by overriding the indexContent method of respective classes (usually Photo or GalleryFile)
|
||||
# - the respective table is joined in (usually via joinClass parameter of getSearchPaginator)
|
||||
# - the column containing the property is included in the query (usually via column parameter of getSearchPaginator)
|
||||
my $where = q{assetIndex.assetId <> '} . $self->getId . q{'};
|
||||
if ( $form->get("title") ) {
|
||||
$where .= q{ AND assetData.title LIKE }
|
||||
|
|
@ -1390,11 +1417,18 @@ sub www_search {
|
|||
. $db->quote( '%' . $form->get("description") . '%' )
|
||||
;
|
||||
}
|
||||
if ( $form->get("location") && ( $form->get("className") eq 'WebGUI::Asset::File::GalleryFile::Photo'
|
||||
|| $form->get("className") eq '' ) ) {
|
||||
$where .= q{ AND Photo.location LIKE }
|
||||
. $db->quote( '%' . $form->get("location") . '%' )
|
||||
;
|
||||
push (@{$columns}, 'Photo.location');
|
||||
}
|
||||
if ( $form->get("userId") ) {
|
||||
$where .= q{ AND assetData.ownerUserId = }
|
||||
. $db->quote( $form->get("userId") )
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
my $oneYearAgo = WebGUI::DateTime->new( $session, time )->add( years => -1 )->epoch;
|
||||
my $dateAfter = $form->get("creationDate_after", "dateTime", $oneYearAgo);
|
||||
|
|
@ -1408,45 +1442,75 @@ sub www_search {
|
|||
}
|
||||
|
||||
# Classes
|
||||
my $joinClass = [
|
||||
my $classes = [
|
||||
'WebGUI::Asset::Wobject::GalleryAlbum',
|
||||
'WebGUI::Asset::File::GalleryFile::Photo',
|
||||
];
|
||||
if ( $form->get("className") ) {
|
||||
$joinClass = [ $form->get('className') ];
|
||||
$classes = [ $form->get('className') ];
|
||||
}
|
||||
$where .= q{ AND assetIndex.className IN ( } . $db->quoteAndJoin( $joinClass ) . q{ ) };
|
||||
|
||||
|
||||
# Build a URL for the pagination
|
||||
my $url
|
||||
= $self->getUrl(
|
||||
'func=search;'
|
||||
. 'basicSearch=' . $form->get('basicSearch') . ';'
|
||||
. 'keywords=' . $form->get('keywords') . ';'
|
||||
. 'location=' . $form->get('location') . ';'
|
||||
. 'title=' . $form->get('title') . ';'
|
||||
. 'description=' . $form->get('description') . ';'
|
||||
. 'creationDate_after=' . $dateAfter . ';'
|
||||
. 'creationDate_before=' . $dateBefore . ';'
|
||||
. 'userId=' . $form->get("userId") . ';'
|
||||
);
|
||||
for my $class ( @$joinClass ) {
|
||||
for my $class ( @$classes ) {
|
||||
$url .= 'className=' . $class . ';';
|
||||
}
|
||||
|
||||
my $p
|
||||
|
||||
my $paginator
|
||||
= $self->getSearchPaginator( {
|
||||
url => $url,
|
||||
keywords => $keywords,
|
||||
where => $where,
|
||||
joinClass => $joinClass,
|
||||
classes => $classes,
|
||||
joinClass => $classes,
|
||||
columns => $columns,
|
||||
creationDate => $creationDate,
|
||||
} );
|
||||
} );
|
||||
|
||||
return ( $paginator, $keywords );
|
||||
}
|
||||
|
||||
# Return undef to indicate that no search was executed
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 www_search ( )
|
||||
|
||||
Search through the GalleryAlbums and files in this gallery. Show the form to
|
||||
search and display the results if necessary.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_search {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
|
||||
my $var = $self->getTemplateVars;
|
||||
# NOTE: Search form is added as part of getTemplateVars()
|
||||
|
||||
# Execute search and retrieve search result paginator and keywords
|
||||
my ( $paginator, $keywords ) = $self->search;
|
||||
|
||||
if( $paginator ) {
|
||||
# Provide search keywords as template variable
|
||||
$var->{ keywords } = $keywords;
|
||||
|
||||
$p->appendTemplateVars( $var );
|
||||
for my $result ( @{ $p->getPageData } ) {
|
||||
# Add search results
|
||||
$paginator->appendTemplateVars( $var );
|
||||
for my $result ( @{ $paginator->getPageData } ) {
|
||||
my $asset = WebGUI::Asset->newById( $session, $result->{assetId} );
|
||||
push @{ $var->{search_results} }, {
|
||||
%{ $asset->getTemplateVars },
|
||||
|
|
|
|||
|
|
@ -1438,9 +1438,9 @@ sub www_edit {
|
|||
elsif ( grep { $_ =~ /^rotateLeft-(.{22})$/ } $form->param ) {
|
||||
my $assetId = ( grep { $_ =~ /^rotateLeft-(.{22})$/ } $form->param )[0];
|
||||
$assetId =~ s/^rotateLeft-//;
|
||||
my $asset = WebGUI::Asset->newByDynamicClass( $session, $assetId );
|
||||
my $asset = eval { WebGUI::Asset->newById( $session, $assetId ); };
|
||||
|
||||
if ( $asset ) {
|
||||
if ( ! Exception::Class->caught() ) {
|
||||
# Add revision and create a new version tag by doing so
|
||||
my $newRevision = $asset->addRevision;
|
||||
# Rotate photo (i.e. all attached image files) by 90° CCW
|
||||
|
|
@ -1456,9 +1456,9 @@ sub www_edit {
|
|||
elsif ( grep { $_ =~ /^rotateRight-(.{22})$/ } $form->param ) {
|
||||
my $assetId = ( grep { $_ =~ /^rotateRight-(.{22})$/ } $form->param )[0];
|
||||
$assetId =~ s/^rotateRight-//;
|
||||
my $asset = WebGUI::Asset->newByDynamicClass( $session, $assetId );
|
||||
my $asset = WebGUI::Asset->newById( $session, $assetId );
|
||||
|
||||
if ( $asset ) {
|
||||
if ( Exception::Class->caught() ) {
|
||||
# Add revision and create a new version tag by doing so
|
||||
my $newRevision = $asset->addRevision;
|
||||
# Rotate photo (i.e. all attached image files) by 90° CW
|
||||
|
|
|
|||
|
|
@ -160,9 +160,16 @@ override getEditForm => sub {
|
|||
}
|
||||
else {
|
||||
my @assetsToHide = split("\n",$self->assetsToHide);
|
||||
my $children = $self->getLineage(["children"],{"returnObjects"=>1, excludeClasses=>["WebGUI::Asset::Wobject::Layout"]});
|
||||
my $childIter = $self->getLineageIterator(["children"],{excludeClasses=>["WebGUI::Asset::Wobject::Layout"]});
|
||||
my %childIds;
|
||||
foreach my $child (@{$children}) {
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
$childIds{$child->getId} = $child->getTitle;
|
||||
}
|
||||
$extraFields{assetsToHide} = {
|
||||
|
|
@ -236,11 +243,18 @@ sub prepareView {
|
|||
|
||||
my %placeHolder;
|
||||
my @children;
|
||||
|
||||
for my $child ( @{ $self->getLineage( ["children"], {
|
||||
returnObjects => 1,
|
||||
|
||||
my $childIter = $self->getLineageIterator( ["children"], {
|
||||
excludeClasses => ["WebGUI::Asset::Wobject::Layout"],
|
||||
} ) } ) {
|
||||
} );
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
my $assetId = $child->getId;
|
||||
next
|
||||
if ($hidden{$assetId} || ! $child->canView);
|
||||
|
|
@ -393,7 +407,15 @@ override getContentLastModified => sub {
|
|||
# Buggo: this is a little too conservative. Children that are hidden maybe shouldn't count. Hm.
|
||||
my $self = shift;
|
||||
my $mtime = super();
|
||||
foreach my $child (@{$self->getLineage(["children"],{returnObjects=>1, excludeClasses=>['WebGUI::Asset::Wobject::Layout']})}) {
|
||||
my $childIter = $self->getLineageIterator(["children"],{excludeClasses=>['WebGUI::Asset::Wobject::Layout']});
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
my $child_mtime = $child->getContentLastModified;
|
||||
$mtime = $child_mtime if ($child_mtime > $mtime);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -300,11 +300,17 @@ sub deleteAttribute {
|
|||
[$attributeId,$self->getId]);
|
||||
|
||||
# recalculate scores for MatrixListings
|
||||
my @listings = @{ $self->getLineage(['descendants'], {
|
||||
my $listingIter = $self->getLineageIterator(['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
|
||||
returnObjects => 1,
|
||||
}) };
|
||||
foreach my $listing (@listings){
|
||||
});
|
||||
while ( 1 ) {
|
||||
my $listing;
|
||||
eval { $listing = $listingIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $listing;
|
||||
$listing->updateScore;
|
||||
}
|
||||
|
||||
|
|
@ -618,17 +624,23 @@ sub view {
|
|||
|
||||
if ($self->canEdit){
|
||||
# Get all the MatrixListings that are still pending.
|
||||
my @pendingListings = @{ $self->getLineage(['descendants'], {
|
||||
my $pendingIter = $self->getLineageIterator(['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
|
||||
orderByClause => "revisionDate asc",
|
||||
returnObjects => 1,
|
||||
statusToInclude => ['pending'],
|
||||
}) };
|
||||
foreach my $pendingListing (@pendingListings){
|
||||
});
|
||||
while ( 1 ) {
|
||||
my $pending;
|
||||
eval { $pending = $pendingIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $pending;
|
||||
push (@{ $var->{pending_loop} }, {
|
||||
url => $pendingListing->getUrl
|
||||
."?func=view;revision=".$pendingListing->revisionDate,
|
||||
name => $pendingListing->title,
|
||||
url => $pending->getUrl
|
||||
."?func=view;revision=".$pending->revisionDate,
|
||||
name => $pending->title,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -705,18 +717,23 @@ sub view {
|
|||
|
||||
# Get the 5 MatrixListings that were last updated as objects using getLineage.
|
||||
|
||||
my @lastUpdatedListings = @{ $self->getLineage(['descendants'], {
|
||||
my $lastUpdatedIter = $self->getLineageIterator(['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
|
||||
joinClass => "WebGUI::Asset::MatrixListing",
|
||||
orderByClause => "lastUpdated desc",
|
||||
limit => 5,
|
||||
returnObjects => 1,
|
||||
}) };
|
||||
foreach my $lastUpdatedListing (@lastUpdatedListings){
|
||||
});
|
||||
for ( 1..5 ) {
|
||||
my $lastUpdated;
|
||||
eval { $lastUpdated = $lastUpdatedIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $lastUpdated;
|
||||
push (@{ $varStatistics->{last_updated_loop} }, {
|
||||
url => $lastUpdatedListing->getUrl,
|
||||
name => $lastUpdatedListing->title,
|
||||
lastUpdated => $session->datetime->epochToHuman($lastUpdatedListing->lastUpdated,"%z")
|
||||
url => $lastUpdated->getUrl,
|
||||
name => $lastUpdated->title,
|
||||
lastUpdated => $session->datetime->epochToHuman($lastUpdated->lastUpdated,"%z")
|
||||
});
|
||||
}
|
||||
$varStatistics->{lastUpdated_sortButton} = "<span id='sortByUpdated'><button type='button'>"
|
||||
|
|
|
|||
|
|
@ -96,8 +96,15 @@ sub view {
|
|||
my $first;
|
||||
my @forum_loop;
|
||||
my $i18n = WebGUI::International->new($self->session,"Asset_MessageBoard");
|
||||
my $children = $self->getLineage(["children"],{includeOnlyClasses=>["WebGUI::Asset::Wobject::Collaboration"],returnObjects=>1});
|
||||
foreach my $child (@{$children}) {
|
||||
my $childIter = $self->getLineageIterator(["children"],{includeOnlyClasses=>["WebGUI::Asset::Wobject::Collaboration"]});
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
$count++;
|
||||
next unless ($child->canView);
|
||||
if ($count == 1) {
|
||||
|
|
|
|||
|
|
@ -369,44 +369,49 @@ sub view {
|
|||
# we've got to determine what our start point is based upon user conditions
|
||||
my $start;
|
||||
$self->session->asset(WebGUI::Asset->newByUrl($self->session)) unless ($self->session->asset);
|
||||
my $current = $self->session->asset;
|
||||
|
||||
my $var = {'page_loop' => []};
|
||||
|
||||
my $current = $self->session->asset;
|
||||
# no current asset is set
|
||||
unless (defined $current) {
|
||||
$current = WebGUI::Asset->getDefault($self->session);
|
||||
}
|
||||
|
||||
my @interestingProperties = ('assetId', 'parentId', 'ownerUserId', 'synopsis', 'newWindow');
|
||||
# Add properties from current asset
|
||||
foreach my $property (@interestingProperties) {
|
||||
$var->{'currentPage.'.$property} = $current->$property;
|
||||
}
|
||||
$var->{'currentPage.menuTitle'} = $current->getMenuTitle;
|
||||
$var->{'currentPage.title'} = $current->getTitle;
|
||||
$var->{'currentPage.isHome'} = ($current->getId eq $self->session->setting->get("defaultPage"));
|
||||
$var->{'currentPage.url'} = $current->getUrl;
|
||||
$var->{'currentPage.hasChild'} = $current->hasChildren;
|
||||
$var->{'currentPage.rank'} = $current->getRank;
|
||||
$var->{'currentPage.rankIs'.$current->getRank} = 1;
|
||||
|
||||
# Build the asset tree
|
||||
if ($self->startType eq "specificUrl") {
|
||||
$start = WebGUI::Asset->newByUrl($self->session,$self->startPoint);
|
||||
} elsif ($self->startType eq "relativeToRoot") {
|
||||
}
|
||||
elsif ($self->startType eq "relativeToRoot") {
|
||||
unless (($self->startPoint+1) >= $current->getLineageLength) {
|
||||
$start = WebGUI::Asset->newByLineage($self->session,substr($current->lineage,0, ($self->startPoint + 1) * 6));
|
||||
}
|
||||
} elsif ($self->startType eq "relativeToCurrentUrl") {
|
||||
}
|
||||
elsif ($self->startType eq "relativeToCurrentUrl") {
|
||||
$start = WebGUI::Asset->newByLineage($self->session,substr($current->lineage,0, ($current->getLineageLength + $self->startPoint) * 6));
|
||||
}
|
||||
$start = $current unless (defined $start); # if none of the above results in a start point, then the current page must be it
|
||||
my @includedRelationships = split("\n",$self->assetsToInclude);
|
||||
|
||||
my %rules;
|
||||
$rules{returnObjects} = 1;
|
||||
$rules{endingLineageLength} = $start->getLineageLength+$self->descendantEndPoint;
|
||||
$rules{assetToPedigree} = $current if (isIn("pedigree",@includedRelationships));
|
||||
$rules{ancestorLimit} = $self->ancestorEndPoint;
|
||||
$rules{orderByClause} = 'rpad(asset.lineage, 255, 9) desc' if ($self->reversePageLoop);
|
||||
my @interestingProperties = ('assetId', 'parentId', 'ownerUserId', 'synopsis', 'newWindow');
|
||||
my $assets = $start->getLineage(\@includedRelationships,\%rules);
|
||||
my $var = {'page_loop' => []};
|
||||
foreach my $property (@interestingProperties) {
|
||||
$var->{'currentPage.'.$property} = $current->$property;
|
||||
}
|
||||
$var->{'currentPage.menuTitle'} = $current->getMenuTitle;
|
||||
$var->{'currentPage.title'} = $current->getTitle;
|
||||
$var->{'currentPage.isHome'} = ($current->getId eq $self->session->setting->get("defaultPage"));
|
||||
$var->{'currentPage.url'} = $current->getUrl;
|
||||
$var->{'currentPage.hasChild'} = $current->hasChildren;
|
||||
$var->{'currentPage.rank'} = $current->getRank;
|
||||
$var->{'currentPage.rankIs'.$current->getRank} = 1;
|
||||
my $currentLineage = $current->lineage;
|
||||
my $lineageToSkip = "noskip";
|
||||
my $absoluteDepthOfLastPage;
|
||||
|
|
@ -414,8 +419,7 @@ sub view {
|
|||
my %lastChildren;
|
||||
my $previousPageData = undef;
|
||||
my $eh = $self->session->errorHandler;
|
||||
foreach my $asset (@{$assets}) {
|
||||
|
||||
while ( my $asset = $assets->() ) {
|
||||
# skip pages we shouldn't see
|
||||
my $pageLineage = $asset->lineage;
|
||||
next if ($pageLineage =~ m/^$lineageToSkip/);
|
||||
|
|
|
|||
|
|
@ -266,12 +266,20 @@ sub view {
|
|||
|
||||
# get other shelves
|
||||
my @childShelves = ();
|
||||
SHELF: foreach my $child (@{$self->getLineage(['children'],{returnObjects=>1,includeOnlyClasses=>['WebGUI::Asset::Wobject::Shelf']})}) {
|
||||
my $childIter = $self->getLineageIterator(['children'],{includeOnlyClasses=>['WebGUI::Asset::Wobject::Shelf']});
|
||||
SHELF: while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
next SHELF unless $child->canView;
|
||||
my $properties = $child->get;
|
||||
$child->{url} = $child->getUrl;
|
||||
$child->{title} = $child->getTitle;
|
||||
push @childShelves, $child;
|
||||
$properties->{url} = $child->getUrl;
|
||||
$properties->{title} = $child->getTitle;
|
||||
push @childShelves, $properties;
|
||||
}
|
||||
|
||||
# get other child skus
|
||||
|
|
|
|||
|
|
@ -369,14 +369,21 @@ for generating an RSS and Atom feeds.
|
|||
|
||||
sub getRssFeedItems {
|
||||
my $self = shift;
|
||||
my $stories = $self->getLineageIterator(['descendants'],{
|
||||
my $storyIter = $self->getLineageIterator(['descendants'],{
|
||||
excludeClasses => ['WebGUI::Asset::Wobject::Folder'],
|
||||
orderByClause => 'creationDate desc, lineage',
|
||||
returnObjects => 1,
|
||||
limit => $self->itemsPerFeed,
|
||||
});
|
||||
my $storyData = [];
|
||||
while (my $story = $stories->()) {
|
||||
while ( 1 ) {
|
||||
my $story;
|
||||
eval { $story = $storyIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $story;
|
||||
push @{ $storyData }, $story->getRssData;
|
||||
}
|
||||
return $storyData;
|
||||
|
|
|
|||
|
|
@ -280,17 +280,19 @@ sub getTemplateVariables {
|
|||
$item{guid} = WebGUI::HTML::filter(scalar $object->guid, 'javascript');
|
||||
$item{link} = WebGUI::HTML::filter(scalar $object->link, 'javascript');
|
||||
my $description = WebGUI::HTML::filter(scalar($object->description), 'javascript');
|
||||
my $raw_description = WebGUI::HTML::filter($description, 'all');
|
||||
$raw_description =~ s/^\s+//s;
|
||||
$item{description} = defined $description ? $description : '';
|
||||
$item{descriptionFirst100words} = $item{description};
|
||||
$item{descriptionFirst100words} =~ s/(((\S+)\s+){100}).*/$1/s;
|
||||
$item{descriptionFirst100words} = $raw_description;
|
||||
$item{descriptionFirst100words} =~ s/(((\S+)\s+){1,100}).*/$1/ms;
|
||||
$item{descriptionFirst75words} = $item{descriptionFirst100words};
|
||||
$item{descriptionFirst75words} =~ s/(((\S+)\s+){75}).*/$1/s;
|
||||
$item{descriptionFirst75words} =~ s/(((\S+)\s+){1,75}).*/$1/ms;
|
||||
$item{descriptionFirst50words} = $item{descriptionFirst75words};
|
||||
$item{descriptionFirst50words} =~ s/(((\S+)\s+){50}).*/$1/s;
|
||||
$item{descriptionFirst50words} =~ s/(((\S+)\s+){1,50}).*/$1/ms;
|
||||
$item{descriptionFirst25words} = $item{descriptionFirst50words};
|
||||
$item{descriptionFirst25words} =~ s/(((\S+)\s+){25}).*/$1/s;
|
||||
$item{descriptionFirst25words} =~ s/(((\S+)\s+){1,25}).*/$1/ms;
|
||||
$item{descriptionFirst10words} = $item{descriptionFirst25words};
|
||||
$item{descriptionFirst10words} =~ s/(((\S+)\s+){10}).*/$1/s;
|
||||
$item{descriptionFirst10words} =~ s/(((\S+)\s+){1,10}).*/$1/ms;
|
||||
if ($description =~ /<p>/) {
|
||||
my $html = $description;
|
||||
$html =~ tr/\n/ /s;
|
||||
|
|
@ -304,12 +306,12 @@ sub getTemplateVariables {
|
|||
$item{descriptionFirstParagraph} = $item{descriptionFirst2paragraphs};
|
||||
$item{descriptionFirstParagraph} =~ s/^(.*?\n).*/$1/s;
|
||||
}
|
||||
$item{descriptionFirst4sentences} = $item{description};
|
||||
$item{descriptionFirst4sentences} =~ s/^((.*?\.){4}).*/$1/s;
|
||||
$item{descriptionFirst4sentences} = $raw_description;
|
||||
$item{descriptionFirst4sentences} =~ s/^((.*?\.){1,4}).*/$1/s;
|
||||
$item{descriptionFirst3sentences} = $item{descriptionFirst4sentences};
|
||||
$item{descriptionFirst3sentences} =~ s/^((.*?\.){3}).*/$1/s;
|
||||
$item{descriptionFirst3sentences} =~ s/^((.*?\.){1,3}).*/$1/s;
|
||||
$item{descriptionFirst2sentences} = $item{descriptionFirst3sentences};
|
||||
$item{descriptionFirst2sentences} =~ s/^((.*?\.){2}).*/$1/s;
|
||||
$item{descriptionFirst2sentences} =~ s/^((.*?\.){1,2}).*/$1/s;
|
||||
$item{descriptionFirstSentence} = $item{descriptionFirst2sentences};
|
||||
$item{descriptionFirstSentence} =~ s/^(.*?\.).*/$1/s;
|
||||
push @{$var{item_loop}}, \%item;
|
||||
|
|
|
|||
|
|
@ -3299,18 +3299,20 @@ sequenceNumber');
|
|||
$self->session->cache->set("query_".$thingId, $query, 30*60);
|
||||
|
||||
$paginatePage = $self->session->form->param('pn') || 1;
|
||||
$currentUrl = $self->session->url->append($currentUrl, "orderBy=".$orderBy) if $orderBy;
|
||||
|
||||
$currentUrl = $self->session->url->append($currentUrl, "orderBy=".$orderBy) if $orderBy;
|
||||
|
||||
$p = WebGUI::Paginator->new($self->session,$currentUrl,$thingProperties->{thingsPerPage}, undef, $paginatePage);
|
||||
|
||||
my $sth = $self->session->db->read($query) if ! $noFields;
|
||||
my @visibleResults;
|
||||
while (my $result = $sth->hashRef){
|
||||
if ($self->canViewThingData($thingId,$result->{thingDataId})){
|
||||
push(@visibleResults,$result);
|
||||
if (! $noFields) {
|
||||
my $sth = $self->session->db->read($query) if ! $noFields;
|
||||
while (my $result = $sth->hashRef){
|
||||
if ($self->canViewThingData($thingId,$result->{thingDataId})){
|
||||
push(@visibleResults,$result);
|
||||
}
|
||||
}
|
||||
}
|
||||
$p->setDataByArrayRef(\@visibleResults) if ! $noFields;
|
||||
$p->setDataByArrayRef(\@visibleResults);
|
||||
|
||||
$searchResults = $p->getPageData($paginatePage);
|
||||
foreach my $searchResult (@$searchResults){
|
||||
|
|
|
|||
|
|
@ -253,15 +253,19 @@ sub appendMostPopular {
|
|||
my $self = shift;
|
||||
my $var = shift;
|
||||
my $limit = shift || $self->get("mostPopularCount");
|
||||
foreach my $asset (@{$self->getLineage(["children"],{returnObjects=>1, limit=>$limit, includeOnlyClasses=>["WebGUI::Asset::WikiPage"], joinClass => 'WebGUI::Asset::WikiPage', orderByClause => 'WikiPage.views DESC'})}) {
|
||||
if (defined $asset) {
|
||||
my $assetIter = $self->getLineageIterator(["children"],{limit=>$limit, includeOnlyClasses=>["WebGUI::Asset::WikiPage"], joinClass => 'WebGUI::Asset::WikiPage', orderByClause => 'WikiPage.views DESC'});
|
||||
while ( 1 ) {
|
||||
my $asset;
|
||||
eval { $asset = $assetIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $asset;
|
||||
push(@{$var->{mostPopular}}, {
|
||||
title=>$asset->getTitle,
|
||||
url=>$asset->getUrl,
|
||||
});
|
||||
} else {
|
||||
$self->session->errorHandler->error("Couldn't instanciate wikipage for master ".$self->getId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -729,20 +733,31 @@ Extend the master method to propagate view and edit permissions down to the wiki
|
|||
|
||||
=cut
|
||||
|
||||
sub processPropertiesFromFormPost {
|
||||
override processPropertiesFromFormPost => sub {
|
||||
my $self = shift;
|
||||
my $groupsChanged =
|
||||
(($self->session->form->process('groupIdView') ne $self->groupIdView)
|
||||
or ($self->session->form->process('groupIdEdit') ne $self->groupIdEdit));
|
||||
my $ret = $self->next::method(@_);
|
||||
my $ret = super();
|
||||
if ($groupsChanged) {
|
||||
foreach my $child (@{$self->getLineage(['children'], {returnObjects => 1})}) {
|
||||
$child->update({ groupIdView => $self->groupIdView,
|
||||
groupIdEdit => $self->groupIdEdit });
|
||||
# XXX Should this do descendants for WikiPage attachments?
|
||||
my $childIter = $self->getLineageIterator(['children']);
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
$child->update({
|
||||
groupIdView => $self->get('groupIdView'),
|
||||
groupIdEdit => $self->get('groupIdEdit')
|
||||
});
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
};
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -53,10 +53,19 @@ sub duplicateBranch {
|
|||
my $childrenOnly = shift;
|
||||
|
||||
my $newAsset = $self->duplicate({skipAutoCommitWorkflows=>1,skipNotification=>1});
|
||||
# Correctly handle positions for Layout assets
|
||||
my $contentPositions = $self->get("contentPositions");
|
||||
my $assetsToHide = $self->get("assetsToHide");
|
||||
|
||||
foreach my $child (@{$self->getLineage(["children"],{returnObjects=>1})}) {
|
||||
my $childIter = $self->getLineageIterator(["children"]);
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
my $newChild = $childrenOnly ? $child->duplicate({skipAutoCommitWorkflows=>1, skipNotification=>1}) : $child->duplicateBranch;
|
||||
$newChild->setParent($newAsset);
|
||||
my ($oldChildId, $newChildId) = ($child->getId, $newChild->getId);
|
||||
|
|
@ -355,11 +364,18 @@ sub www_editBranchSave {
|
|||
$urlBase = $form->text("baseUrl");
|
||||
$endOfUrl = $form->selectBox("endOfUrl");
|
||||
}
|
||||
my $descendants = $self->getLineage(["self","descendants"],{returnObjects=>1});
|
||||
DESCENDANT: foreach my $descendant (@{$descendants}) {
|
||||
my $descendantIter = $self->getLineageIterator(["self","descendants"]);
|
||||
while ( 1 ) {
|
||||
my $descendant;
|
||||
eval { $descendant = $descendantIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $descendant;
|
||||
if ( !$descendant->canEdit ) {
|
||||
$pb->update(sprintf $i18n->get('skipping %s'), $descendant->getTitle);
|
||||
next DESCENDANT;
|
||||
next;
|
||||
}
|
||||
$pb->update(sprintf $i18n->get('editing %s'), $descendant->getTitle);
|
||||
my $url;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,15 @@ sub cut {
|
|||
$session->db->write("update asset set state='clipboard', stateChangedBy=?, stateChanged=? where assetId=?", [$session->user->userId, time(), $self->getId]);
|
||||
$session->db->commit;
|
||||
$self->state("clipboard");
|
||||
foreach my $asset ($self, @{$self->getLineage(['descendants'], {returnObjects => 1})}) {
|
||||
my $assetIter = $self->getLineageIterator(['descendants']);
|
||||
while ( 1 ) {
|
||||
my $asset;
|
||||
eval { $asset = $assetIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $asset;
|
||||
$asset->purgeCache;
|
||||
$asset->updateHistory('cut');
|
||||
}
|
||||
|
|
@ -215,11 +223,18 @@ sub paste {
|
|||
|
||||
# Update lineage in search index.
|
||||
$self->purgeCache;
|
||||
my $updateAssets = $pastedAsset->getLineage(['self', 'descendants'], {returnObjects => 1});
|
||||
my $assetIter = $pastedAsset->getLineageIterator(['self', 'descendants']);
|
||||
while ( 1 ) {
|
||||
my $asset;
|
||||
eval { $asset = $assetIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $asset;
|
||||
|
||||
foreach (@{$updateAssets}) {
|
||||
$outputSub->(sprintf $i18n->get('indexing %s'), $pastedAsset->getTitle) if defined $outputSub;
|
||||
$_->indexContent();
|
||||
$asset->indexContent();
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
@ -489,7 +504,7 @@ sub www_duplicateList {
|
|||
foreach my $assetId ($session->form->param("assetId")) {
|
||||
my $asset = WebGUI::Asset->newById($session,$assetId);
|
||||
if ($asset->canEdit) {
|
||||
my $newAsset = $asset->duplicate;
|
||||
my $newAsset = $asset->duplicate({skipAutoCommitWorkflows => 1, });
|
||||
$newAsset->update({ title=>$newAsset->getTitle.' (copy)'});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,20 +308,22 @@ sub exportBranch {
|
|||
my $indexFileName = $options->{indexFileName};
|
||||
my $extrasUploadAction = $options->{extrasUploadAction};
|
||||
my $rootUrlAction = $options->{rootUrlAction};
|
||||
my $exportedCount = 0;
|
||||
|
||||
my $i18n;
|
||||
if ( $reportSession ) {
|
||||
$i18n = WebGUI::International->new($self->session, 'Asset');
|
||||
}
|
||||
|
||||
my $exportedCount = 0;
|
||||
my $assetIds = $self->exportGetDescendants(undef, $depth);
|
||||
foreach my $assetId ( @{$assetIds} ) {
|
||||
|
||||
my $exportAsset = sub {
|
||||
my ( $assetId ) = @_;
|
||||
# Must be created once for each asset, since session is supposed to only handle
|
||||
# one main asset
|
||||
my $outputSession = $self->session->duplicate;
|
||||
my $osGuard = Scope::Guard->new(sub {
|
||||
$outputSession->close;
|
||||
$outputSession = undef;
|
||||
});
|
||||
|
||||
my $asset = WebGUI::Asset->newById($outputSession, $assetId);
|
||||
|
|
@ -376,6 +378,16 @@ sub exportBranch {
|
|||
if ( $reportSession ) {
|
||||
$reportSession->output->print($i18n->get('done'));
|
||||
}
|
||||
|
||||
#use Devel::Cycle;
|
||||
#warn "CHECKING on " . ref( $asset ) . ' ID: ' . $asset->getId . "\n";
|
||||
#find_cycle( $asset );
|
||||
};
|
||||
|
||||
|
||||
my $assetIds = $self->exportGetDescendants(undef, $depth);
|
||||
foreach my $assetId ( @{$assetIds} ) {
|
||||
$exportAsset->( $assetId );
|
||||
}
|
||||
|
||||
# handle symlinking
|
||||
|
|
@ -435,13 +447,23 @@ boolean indicating whether or not this asset is exportable.
|
|||
sub exportCheckExportable {
|
||||
my $self = shift;
|
||||
|
||||
# We have ourself already, check it first
|
||||
return 0 unless $self->get('isExportable');
|
||||
|
||||
# get this asset's ancestors. return objects as a shortcut since we'd be
|
||||
# instantiating them all anyway.
|
||||
my $assets = $self->getLineage( ['ancestors'], { returnObjects => 1 } );
|
||||
my $assetIter = $self->getLineageIterator( ['self','ancestors'] );
|
||||
|
||||
# process each one. return false if any of the assets in the lineage, or
|
||||
# this asset itself, isn't exportable.
|
||||
foreach my $asset ( @{$assets}, $self ) {
|
||||
while ( 1 ) {
|
||||
my $asset;
|
||||
eval { $asset = $assetIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $asset;
|
||||
return 0 unless $asset->get('isExportable');
|
||||
}
|
||||
|
||||
|
|
@ -523,6 +545,9 @@ sub exportGetDescendants {
|
|||
orderByClause => 'assetData.url DESC',
|
||||
} );
|
||||
|
||||
#use Data::Dumper;
|
||||
#warn "Assets: " . scalar( @$assetIds );
|
||||
|
||||
return $assetIds;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -223,36 +223,106 @@ Returns the number of children this asset has. This excludes assets in the trash
|
|||
|
||||
=head3 opts
|
||||
|
||||
A hashref of options. Currently only one option is supported.
|
||||
A hashref of options.
|
||||
|
||||
=head4 includeTrash
|
||||
|
||||
If this value of this hash key is true, then assets in any state will be counted. Normally,
|
||||
only those that are published or achived are counted.
|
||||
|
||||
=head4 includeOnlyClasses
|
||||
|
||||
Only count these classes. Arrayref of class names
|
||||
|
||||
=head4 statusToInclude
|
||||
|
||||
Arrayref of status to include
|
||||
|
||||
=cut
|
||||
|
||||
sub getChildCount {
|
||||
my $self = shift;
|
||||
my $opts = shift || {};
|
||||
my $stateWhere = $opts->{includeTrash} ? '' : "asset.state='published' and";
|
||||
my ($count) = $self->session->db->quickArray("select count(distinct asset.assetId) from asset, assetData where asset.assetId=assetData.assetId and $stateWhere parentId=? and (assetData.status in ('approved', 'archived') or assetData.tagId=?)", [$self->getId, $self->session->scratch->get('versionTag')]);
|
||||
my $opt = shift || {};
|
||||
$opt->{ statusToInclude } ||= [ 'approved', 'archived' ];
|
||||
|
||||
my $db = $self->session->db;
|
||||
my $sql = "select count(distinct asset.assetId)
|
||||
from asset, assetData
|
||||
where asset.assetId=assetData.assetId
|
||||
and parentId=?
|
||||
and (assetData.status in (" . $db->quoteAndJoin( $opt->{statusToInclude} ) . ")
|
||||
or assetData.tagId=?)";
|
||||
my @params = ( $self->getId, $self->session->scratch->get('versionTag') );
|
||||
|
||||
if ( !$opt->{ includeTrash } ) {
|
||||
$sql .= ' AND asset.state=?';
|
||||
push @params, "published";
|
||||
}
|
||||
# XXX This code is duplicated in getLineageSql and getDescendantCount. Merge the three ways?
|
||||
if ( $opt->{ includeOnlyClasses } ) {
|
||||
my @classes;
|
||||
if ( !ref $opt->{includeOnlyClasses} eq 'ARRAY' ) {
|
||||
@classes = $opt->{includeOnlyClasses};
|
||||
}
|
||||
else {
|
||||
@classes = @{ $opt->{includeOnlyClasses} };
|
||||
}
|
||||
$sql .= "AND className IN (" . join( ',', ("?") x @classes ) . ")";
|
||||
push @params, @classes;
|
||||
}
|
||||
my $count = $self->session->db->quickScalar($sql, \@params);
|
||||
return $count;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getDescendantCount ( )
|
||||
=head2 getDescendantCount ( opts )
|
||||
|
||||
Returns the number of descendants this asset has. This includes only assets that are published, and not
|
||||
in the clipboard or trash.
|
||||
|
||||
=head3 opts
|
||||
|
||||
=head4 includeOnlyClasses
|
||||
|
||||
Only count these classes. Arrayref of class names
|
||||
|
||||
=head4 statusToInclude
|
||||
|
||||
Arrayref of status to include
|
||||
|
||||
=cut
|
||||
|
||||
sub getDescendantCount {
|
||||
my $self = shift;
|
||||
my ($count) = $self->session->db->quickArray("select count(distinct asset.assetId) from asset, assetData where asset.assetId=assetData.assetId and asset.state = 'published' and assetData.status in ('approved','archived') and asset.lineage like ?", [$self->get("lineage")."%"]);
|
||||
$count--; # have to subtract self
|
||||
my $opt = shift || {};
|
||||
$opt->{ statusToInclude } ||= [ 'approved', 'archived' ];
|
||||
|
||||
my $db = $self->session->db;
|
||||
|
||||
my $sql = "select count(distinct asset.assetId)
|
||||
from asset, assetData
|
||||
where asset.assetId = assetData.assetId
|
||||
and asset.assetId != ?
|
||||
and asset.state = 'published'
|
||||
and assetData.status in (" . $db->quoteAndJoin( $opt->{statusToInclude} ) . ")
|
||||
and asset.lineage like ? ";
|
||||
my @params = ( $self->getId, $self->get("lineage")."%" );
|
||||
|
||||
# XXX This code is duplicated in getLineageSql and getChildCount. Merge the three ways?
|
||||
if ( $opt->{includeOnlyClasses} ) {
|
||||
my @classes;
|
||||
if ( !ref $opt->{includeOnlyClasses} eq 'ARRAY' ) {
|
||||
@classes = $opt->{includeOnlyClasses};
|
||||
}
|
||||
else {
|
||||
@classes = @{ $opt->{includeOnlyClasses} };
|
||||
}
|
||||
$sql .= "AND className IN (" . join( ',', ("?") x @classes ) . ")";
|
||||
push @params, @classes;
|
||||
}
|
||||
|
||||
my $count = $self->session->db->quickScalar($sql, \@params);
|
||||
return $count;
|
||||
}
|
||||
|
||||
|
|
@ -927,14 +997,21 @@ sub setRank {
|
|||
my $parentLineage = $self->getParentLineage;
|
||||
|
||||
my $reverse = ($newRank < $currentRank) ? 1 : 0;
|
||||
my $siblings = $self->getLineage(["siblings"],{returnObjects=>1, invertTree=>$reverse});
|
||||
|
||||
my $temp = substr($self->session->id->generate(),0,6);
|
||||
my $previous = $self->lineage;
|
||||
$self->session->db->beginTransaction;
|
||||
$outputSub->('moving %s aside', $self->getTitle);
|
||||
$self->cascadeLineage($temp);
|
||||
foreach my $sibling (@{$siblings}) {
|
||||
my $siblingIter = $self->getLineageIterator(["siblings"],{invertTree=>$reverse});
|
||||
while ( 1 ) {
|
||||
my $sibling;
|
||||
eval { $sibling = $siblingIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $sibling;
|
||||
if (isBetween($sibling->getRank, $newRank, $currentRank)) {
|
||||
$outputSub->('moving %s', $sibling->getTitle);
|
||||
$sibling->cascadeLineage($previous);
|
||||
|
|
|
|||
|
|
@ -64,7 +64,15 @@ Turns this package into a package file and returns the storage location object o
|
|||
sub exportPackage {
|
||||
my $self = shift;
|
||||
my $storage = WebGUI::Storage->createTemp($self->session);
|
||||
foreach my $asset (@{$self->getLineage(["self","descendants"],{returnObjects=>1, statusToInclude=>['approved', 'archived']})}) {
|
||||
my $assetIter = $self->getLineageIterator(["self","descendants"],{statusToInclude=>['approved', 'archived']});
|
||||
while ( 1 ) {
|
||||
my $asset;
|
||||
eval { $asset = $assetIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $asset;
|
||||
my $data = $asset->exportAssetData;
|
||||
$storage->addFileFromScalar($data->{properties}{lineage}.".json", JSON->new->utf8->pretty->encode($data));
|
||||
foreach my $storageId (@{$data->{storage}}) {
|
||||
|
|
@ -348,10 +356,12 @@ sub www_exportPackage {
|
|||
=cut
|
||||
|
||||
sub www_importPackage {
|
||||
my $self = shift;
|
||||
return $self->session->privilege->insufficient() unless ($self->canEdit && $self->session->user->isInGroup(4));
|
||||
my $storage = WebGUI::Storage->createTemp($self->session);
|
||||
my $inheritPermissions = $self->session->form->process('inheritPermissions');
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
return $session->privilege->insufficient() unless ($self->canEdit && $session->user->isInGroup(4));
|
||||
|
||||
my $form = $session->form;
|
||||
my $storage = WebGUI::Storage->createTemp($session);
|
||||
|
||||
##This is a hack. It should use the WebGUI::Form::File API to insulate
|
||||
##us from future form name changes.
|
||||
|
|
@ -359,19 +369,25 @@ sub www_importPackage {
|
|||
|
||||
my $error = "";
|
||||
if ($storage->getFileExtension($storage->getFiles->[0]) eq "wgpkg") {
|
||||
$error = $self->importPackage($storage, {inheritPermissions => $inheritPermissions});
|
||||
$error = $self->importPackage(
|
||||
$storage, {
|
||||
inheritPermissions => $form->get('inheritPermissions'),
|
||||
clearPackageFlag => $form->get('clearPackageFlag'),
|
||||
}
|
||||
);
|
||||
}
|
||||
if (!blessed $error) {
|
||||
my $i18n = WebGUI::International->new($self->session, "Asset");
|
||||
if ($error eq 'corrupt') {
|
||||
return $self->session->style->userStyle($i18n->get("package corrupt"));
|
||||
}
|
||||
else {
|
||||
return $self->session->style->userStyle($i18n->get("package extract error"));
|
||||
}
|
||||
my $i18n = WebGUI::International->new($session, "Asset");
|
||||
my $style = $session->style;
|
||||
if ($error eq 'corrupt') {
|
||||
return $style->userStyle($i18n->get("package corrupt"));
|
||||
}
|
||||
else {
|
||||
return $style->userStyle($i18n->get("package extract error"));
|
||||
}
|
||||
}
|
||||
# Handle autocommit workflows
|
||||
if (WebGUI::VersionTag->autoCommitWorkingIfEnabled($self->session, {
|
||||
if (WebGUI::VersionTag->autoCommitWorkingIfEnabled($session, {
|
||||
allowComments => 1,
|
||||
returnUrl => $self->getUrl,
|
||||
}) eq 'redirect') {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ package WebGUI::Asset;
|
|||
|
||||
use strict;
|
||||
use WebGUI::Utility qw(isIn formatBytes);
|
||||
use JSON;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
|
|
@ -140,24 +141,23 @@ sub purge {
|
|||
}
|
||||
|
||||
# assassinate the offspring
|
||||
my $kids = $self->getLineage(["children"],{
|
||||
returnObjects => 1,
|
||||
my $childIter = $self->getLineageIterator(["children"],{
|
||||
statesToInclude => [qw(published clipboard clipboard-limbo trash trash-limbo)],
|
||||
statusToInclude => [qw(approved archived pending)],
|
||||
});
|
||||
foreach my $kid (@{$kids}) {
|
||||
# Technically get lineage should never return an undefined object from getLineage when called like this, but it did so this saves the world from destruction.
|
||||
if (defined $kid) {
|
||||
unless ($kid->purge) {
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
unless ($child->purge) {
|
||||
$session->errorHandler->security("delete one of (".$self->getId.")'s children which is a system protected page");
|
||||
$outputSub->(sprintf $i18n->get('Trying to delete system page %s. Aborting'), $self->getTitle);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$outputSub->($i18n->get('Undefined child'));
|
||||
$session->errorHandler->error("getLineage returned an undefined object in the AssetTrash->purge method. Unable to purge asset.");
|
||||
}
|
||||
}
|
||||
|
||||
# Delete shortcuts to this asset
|
||||
|
|
@ -265,7 +265,15 @@ sub trash {
|
|||
return undef;
|
||||
}
|
||||
|
||||
foreach my $asset ($self, @{$self->getLineage(['descendants'], {returnObjects => 1})}) {
|
||||
my $assetIter = $self->getLineageIterator(['self','descendants']);
|
||||
while ( 1 ) {
|
||||
my $asset;
|
||||
eval { $asset = $assetIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $asset;
|
||||
$outputSub->($i18n->get('Clearing search index'));
|
||||
my $index = WebGUI::Search::Index->new($asset);
|
||||
$index->delete;
|
||||
|
|
@ -418,21 +426,37 @@ sub www_manageTrash {
|
|||
assetManager.AddColumn('".$i18n->get("last updated")."','','center','');
|
||||
assetManager.AddColumn('".$i18n->get("size")."','','right','');
|
||||
\n";
|
||||
|
||||
# To avoid string escaping issues
|
||||
my $json = JSON->new;
|
||||
my $amethod = sub {
|
||||
my ($method, @args) = @_;
|
||||
my $array = $json->encode(\@args);
|
||||
$array =~ s/^\[//;
|
||||
$array =~ s/\]$//;
|
||||
$output .= "assetManager.$method($array);\n";
|
||||
};
|
||||
foreach my $child (@{$self->getAssetsInTrash($limit)}) {
|
||||
my $title = $child->getTitle;
|
||||
$title =~ s/\'/\\\'/g;
|
||||
my $title = $child->getTitle;
|
||||
my $plus =$child->getChildCount({includeTrash => 1}) ? "+ " : " ";
|
||||
$output .= "assetManager.AddLine('"
|
||||
.WebGUI::Form::checkbox($self->session, {
|
||||
name=>'assetId',
|
||||
value=>$child->getId
|
||||
})
|
||||
."','" . $plus . "<a href=\"".$child->getUrl("op=assetManager")."\">" . $title
|
||||
."</a>','<p style=\"display:inline;vertical-align:middle;\"><img src=\"".$child->getIcon(1)."\" style=\"vertical-align:middle;border-style:none;\" alt=\"".$child->getName."\" /></p> ".$child->getName
|
||||
."','".$self->session->datetime->epochToHuman($child->get("revisionDate"))
|
||||
."','".formatBytes($child->get("assetSize"))."');\n";
|
||||
$output .= "assetManager.AddLineSortData('','".$title."','".$child->getName
|
||||
."','".$child->get("revisionDate")."','".$child->get("assetSize")."');\n";
|
||||
$amethod->('AddLine',
|
||||
WebGUI::Form::checkbox($self->session, {
|
||||
name=>'assetId',
|
||||
value=>$child->getId
|
||||
}),
|
||||
qq($plus<a href=").$child->getUrl("op=assetManager")
|
||||
.qq(">$title</a>),
|
||||
'<p style="display:inline;vertical-align:middle;"><img src="'
|
||||
.$child->getIcon(1)
|
||||
.'" style="vertical-align:middle;border-style:none;" alt='
|
||||
.$child->getName .'" /></p> ' . $child->getName,
|
||||
$self->session->datetime->epochToHuman($child->get("revisionDate")),
|
||||
formatBytes($child->get("assetSize"))
|
||||
);
|
||||
$amethod->('AddLineSortData',
|
||||
'', $title, $child->getName,
|
||||
$child->get('revisionDate'), $child->get('assetSize')
|
||||
);
|
||||
}
|
||||
$output .= '
|
||||
assetManager.AddButton("'.$i18n->get("restore").'","restoreList","manageTrash");
|
||||
|
|
|
|||
|
|
@ -170,7 +170,6 @@ around new => sub {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 readAllConfigs ( )
|
||||
|
|
|
|||
|
|
@ -49,20 +49,25 @@ sub handler {
|
|||
# Only handle op=ajaxGetI18N
|
||||
return undef unless ( $session->form->get( "op" ) eq "ajaxGetI18N" );
|
||||
|
||||
my $json = $session->form->get( "request" );
|
||||
my $namespaces = JSON->new->decode( $json );
|
||||
my $i18n = WebGUI::International->new( $session );
|
||||
my $response = {};
|
||||
my $json = $session->form->get( "request" );
|
||||
my $namespaces = eval { JSON->new->decode( $json ) };
|
||||
unless ($@) {
|
||||
my $i18n = WebGUI::International->new( $session );
|
||||
|
||||
for my $ns ( keys %{ $namespaces } ) {
|
||||
for my $key ( @{ $namespaces->{ $ns } } ) {
|
||||
$response->{ $ns }->{ $key } = $i18n->get( $key, $ns );
|
||||
for my $ns ( keys %{ $namespaces } ) {
|
||||
for my $key ( @{ $namespaces->{ $ns } } ) {
|
||||
$response->{ $ns }->{ $key } = $i18n->get( $key, $ns );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
$session->log->warn("User ".$session->user->username." tried to execute ajaxGetI18n but could not decode JSON string: $json");
|
||||
}
|
||||
$session->http->setMimeType( "application/json" );
|
||||
return JSON->new->encode( $response );
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
|
|
|
|||
|
|
@ -384,13 +384,20 @@ ENDHTML
|
|||
|
||||
### Crumbtrail
|
||||
my $crumb_markup = '<li><a href="%s">%s</a> ></li>';
|
||||
my $ancestors = $currentAsset->getLineage( ['ancestors'], { returnObjects => 1 } );
|
||||
my $ancestorIter = $currentAsset->getLineageIterator( ['ancestors'] );
|
||||
|
||||
$output .= '<ol id="crumbtrail">';
|
||||
for my $asset ( @{ $ancestors } ) {
|
||||
while ( 1 ) {
|
||||
my $ancestor;
|
||||
eval { $ancestor = $ancestorIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $ancestor;
|
||||
$output .= sprintf $crumb_markup,
|
||||
$asset->getUrl( 'op=assetManager;method=manage' ),
|
||||
$asset->get( "menuTitle" ),
|
||||
$ancestor->getUrl( 'op=assetManager;method=manage' ),
|
||||
$ancestor->get( "menuTitle" ),
|
||||
;
|
||||
}
|
||||
|
||||
|
|
@ -476,6 +483,8 @@ EOHTML
|
|||
. WebGUI::Form::hidden($session, {name=>"func", value=>"importPackage"})
|
||||
. '<div><input type="file" name="packageFile" size="30" style="font-size: 10px;" /></div>'
|
||||
. '<div style="font-size: 10px">'
|
||||
. WebGUI::Form::checkbox($session, { label => $i18n->get('clear package flag'), checked => 0, name => 'clearPackageFlag', value => 1 })
|
||||
. '<br />'
|
||||
. WebGUI::Form::checkbox($session, { label => $i18n->get('inherit parent permissions'), checked => 1, name => 'inheritPermissions', value => 1 })
|
||||
. ' ' . WebGUI::Form::submit($session, { value=>$i18n->get("import"), 'extras' => ' ' })
|
||||
. '</div>'
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ sub handler {
|
|||
}
|
||||
|
||||
my $pages = WebGUI::Asset->getRoot($session)->getLineageIterator(["self","descendants"],{
|
||||
returnObjects => 1,
|
||||
includeOnlyClasses => ["WebGUI::Asset::Wobject::Layout"],
|
||||
whereClause => $whereClause,
|
||||
limit => 20000
|
||||
|
|
|
|||
|
|
@ -184,8 +184,15 @@ sub www_assetTree {
|
|||
$session->http->setCacheControl("none");
|
||||
my $base = WebGUI::Asset->newByUrl($session) || WebGUI::Asset->getRoot($session);
|
||||
my @crumb;
|
||||
my $ancestors = $base->getLineage(["self","ancestors"],{returnObjects=>1});
|
||||
foreach my $ancestor (@{$ancestors}) {
|
||||
my $ancestorIter = $base->getLineageIterator(["self","ancestors"]);
|
||||
while ( 1 ) {
|
||||
my $ancestor;
|
||||
eval { $ancestor = $ancestorIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $ancestor;
|
||||
my $url = $ancestor->getUrl("op=formHelper;sub=assetTree;class=Asset;formId=".$session->form->process("formId"));
|
||||
$url .= ";classLimiter=".$session->form->process("classLimiter","className") if ($session->form->process("classLimiter","className"));
|
||||
push(@crumb,'<a href="'.$url.'" class="crumb">'.$ancestor->get("menuTitle").'</a>');
|
||||
|
|
@ -224,10 +231,17 @@ sub www_assetTree {
|
|||
</style></head><body>
|
||||
<div class="base">
|
||||
<div class="crumbTrail">'.join(" > ", @crumb)."</div><br />\n";
|
||||
my $children = $base->getLineage(["children","self"],{returnObjects=>1});
|
||||
my $childIter = $base->getLineageIterator(["children","self"]);
|
||||
my $i18n = WebGUI::International->new($session);
|
||||
my $limit = $session->form->process("classLimiter","className");
|
||||
foreach my $child (@{$children}) {
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
next unless $child->canView;
|
||||
if ($limit eq "" || $child->get("className") =~ /^$limit/) {
|
||||
my $tempChild = $child->get("title");
|
||||
|
|
|
|||
|
|
@ -99,20 +99,4 @@ sub isDynamicCompatible {
|
|||
return 1;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 toHtml ( )
|
||||
|
||||
Renders an email address field.
|
||||
|
||||
=cut
|
||||
|
||||
sub toHtml {
|
||||
my $self = shift;
|
||||
$self->session->style->setScript($self->session->url->extras('emailCheck.js'));
|
||||
$self->{_params}{extras} .= ' onchange="emailCheck(this.value)" ';
|
||||
return $self->SUPER::toHtml;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
|
|
|||
|
|
@ -208,13 +208,27 @@ JS
|
|||
my $output = '<div class="nav">';
|
||||
my $base = WebGUI::Asset->newByUrl($session) || WebGUI::Asset->getRoot($session);
|
||||
my @crumb;
|
||||
my $ancestors = $base->getLineage(["self","ancestors"],{returnObjects=>1});
|
||||
foreach my $ancestor (@{$ancestors}) {
|
||||
my $ancestorIter = $base->getLineageIterator(["self","ancestors"]);
|
||||
while ( 1 ) {
|
||||
my $ancestor;
|
||||
eval { $ancestor = $ancestorIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $ancestor;
|
||||
push(@crumb,'<a href="'.$ancestor->getUrl("op=formHelper;class=HTMLArea;sub=pageTree").'" class="crumb">'.$ancestor->get("menuTitle").'</a>');
|
||||
}
|
||||
$output .= '<div class="crumbTrail">'.join(" > ", @crumb)."</div>\n<ul>";
|
||||
my $children = $base->getLineage(["children"],{returnObjects=>1});
|
||||
foreach my $child (@{$children}) {
|
||||
my $childIter = $base->getLineageIterator(["children"]);
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
next unless $child->canView;
|
||||
$output .= '<li><a href="#" class="selectLink" onclick="selectLink(\'' . $child->get('url') . '\'); return false;">['
|
||||
. $i18n->get("select") . ']</a> <a href="' . $child->getUrl("op=formHelper;class=HTMLArea;sub=pageTree")
|
||||
|
|
@ -253,8 +267,15 @@ JS
|
|||
|
||||
my @crumb;
|
||||
my $media;
|
||||
my $ancestors = $base->getLineage(["self","ancestors"],{returnObjects=>1});
|
||||
foreach my $ancestor (@{$ancestors}) {
|
||||
my $ancestorIter = $base->getLineageIterator(["self","ancestors"]);
|
||||
while ( 1 ) {
|
||||
my $ancestor;
|
||||
eval { $ancestor = $ancestorIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $ancestor;
|
||||
push(@crumb,'<a href="'.$ancestor->getUrl("op=formHelper;class=HTMLArea;sub=imageTree").'" class="crumb">'.$ancestor->get("menuTitle").'</a>');
|
||||
if ($ancestor->get('assetId') eq 'PBasset000000000000003') {
|
||||
$media = $ancestor;
|
||||
|
|
@ -276,8 +297,8 @@ JS
|
|||
$output .= '<div class="crumbTrail">'.join(" > ", @crumb)."</div>\n<ul>";
|
||||
|
||||
my $useAssetUrls = $session->config->get("richEditorsUseAssetUrls");
|
||||
my $children = $base->getLineage(["children"],{returnObjects=>1});
|
||||
foreach my $child (@{$children}) {
|
||||
my $children = $base->getLineage(["children"]);
|
||||
while ( my $child = $children->() ) {
|
||||
next unless $child->canView;
|
||||
$output .= '<li>';
|
||||
if ($child->isa('WebGUI::Asset::File::Image')) {
|
||||
|
|
|
|||
|
|
@ -125,8 +125,18 @@ the available Rich Text Editor assets.
|
|||
|
||||
sub getOptions {
|
||||
my $self = shift;
|
||||
my $editors = WebGUI::Asset->getRoot($self->session)->getLineage(['descendants'], {includeOnlyClasses => ['WebGUI::Asset::RichEdit'], returnObjects => 1});
|
||||
my %options = map { $_->getId => $_->getTitle } @$editors;
|
||||
my $editorIter = WebGUI::Asset->getRoot($self->session)->getLineageIterator( ['descendants'], {includeOnlyClasses => ['WebGUI::Asset::RichEdit']});
|
||||
my %options;
|
||||
while ( 1 ) {
|
||||
my $editor;
|
||||
eval { $editor = $editorIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $editor;
|
||||
$options{ $editor->getId } = $editor->getTitle;
|
||||
}
|
||||
return \%options;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use WebGUI::Pluggable;
|
|||
require WebGUI::Asset;
|
||||
use WebGUI::International;
|
||||
use WebGUI::DatabaseLink;
|
||||
use Scalar::Util qw( weaken );
|
||||
|
||||
=head1 NAME
|
||||
|
||||
|
|
@ -1504,6 +1505,7 @@ sub new {
|
|||
|
||||
my $class = shift;
|
||||
$self->{_session} = shift;
|
||||
weaken( $self->{_session} );
|
||||
$self->{_groupId} = shift;
|
||||
my $override = shift;
|
||||
my $noAdmin = shift;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ our $HELP = {
|
|||
name => 'searchForm_keywords',
|
||||
description => 'helpvar searchForm_keywords',
|
||||
},
|
||||
{
|
||||
name => 'searchForm_location',
|
||||
description => 'helpvar searchForm_location',
|
||||
},
|
||||
{
|
||||
name => 'searchForm_className',
|
||||
description => 'helpvar searchForm_className',
|
||||
|
|
|
|||
|
|
@ -62,6 +62,18 @@ our $HELP = {
|
|||
name => 'ownerUsername',
|
||||
description => 'helpvar ownerUsername',
|
||||
},
|
||||
{
|
||||
name => 'ownerAlias',
|
||||
description => 'helpvar ownerAlias',
|
||||
},
|
||||
{
|
||||
name => 'ownerId',
|
||||
description => 'helpvar ownerId',
|
||||
},
|
||||
{
|
||||
name => 'ownerProfileUrl',
|
||||
description => 'helpvar ownerProfileUrl',
|
||||
},
|
||||
{
|
||||
name => 'thumbnailUrl',
|
||||
description => 'helpvar thumbnailUrl',
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ our $HELP = {
|
|||
{
|
||||
name => "language_langEng",
|
||||
},
|
||||
{
|
||||
name => "language_isCurrent",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,20 +44,25 @@ This macro takes a templateId to show the links
|
|||
sub process {
|
||||
my $session = shift;
|
||||
my $templateId = shift || "_aE16Rr1-bXBf8SIaLZjCg";
|
||||
my $template = eval { WebGUI::Asset::Template->newById($session, $templateId); };
|
||||
my $template = eval { WebGUI::Asset->newById($session, $templateId); };
|
||||
if (Exception::Class->caught()) {
|
||||
return "Could not instanciate template with id [$templateId]" unless $template;
|
||||
}
|
||||
my $i18n = WebGUI::International->new($session);
|
||||
my $languages = $i18n->getLanguages();
|
||||
my $currentLanguage = $session->scratch->get('language')
|
||||
? $session->scratch->get('language')
|
||||
: $session->user->profileField('language');
|
||||
my @lang_loop = ();
|
||||
foreach my $language ( keys %$languages ) {
|
||||
my $isCurrentLanguage = $currentLanguage eq $language ? 1 : 0;
|
||||
push @lang_loop, {
|
||||
language_url => '?op=setLanguage;language=' . $language,
|
||||
language_lang => $i18n->getLanguage($language , 'label'),
|
||||
language_langAbbr => $i18n->getLanguage($language, 'languageAbbreviation'),
|
||||
language_langAbbrLoc => $i18n->getLanguage($language, 'locale'),
|
||||
language_langEng => $language,
|
||||
language_isCurrent => $isCurrentLanguage,
|
||||
};
|
||||
}
|
||||
my %vars = (
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use WebGUI::Exception;
|
|||
use Scalar::Util ();
|
||||
use Try::Tiny;
|
||||
use namespace::clean;
|
||||
use Scalar::Util qw( weaken );
|
||||
|
||||
=head1 NAME
|
||||
|
||||
|
|
|
|||
|
|
@ -447,13 +447,10 @@ sub search {
|
|||
if ( ! eval { WebGUI::Pluggable::load($className) } ) {
|
||||
$self->session->errorHandler->fatal($@);
|
||||
}
|
||||
foreach my $definition (@{$className->definition($self->session)}) {
|
||||
unless ($definition->{tableName} eq "asset") {
|
||||
my $tableName = $definition->{tableName};
|
||||
push @$join,
|
||||
"left join $tableName on assetData.assetId=".$tableName.".assetId and assetData.revisionDate=".$tableName.".revisionDate";
|
||||
}
|
||||
last;
|
||||
TABLE: foreach my $tableName ($className->meta->get_tables) {
|
||||
next TABLE if $tableName eq 'assetData';
|
||||
push @{ $join },
|
||||
"left join $tableName on assetData.assetId=".$tableName.".assetId and assetData.revisionDate=".$tableName.".revisionDate";
|
||||
}
|
||||
}
|
||||
# Get only the latest revision
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use 5.010;
|
|||
|
||||
use CHI;
|
||||
use File::Temp qw( tempdir );
|
||||
use Scalar::Util qw( weaken );
|
||||
use WebGUI::Config;
|
||||
use WebGUI::SQL;
|
||||
use WebGUI::User;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use DateTime;
|
|||
use DateTime::Format::Strptime;
|
||||
use DateTime::Format::Mail;
|
||||
use DateTime::TimeZone;
|
||||
use Scalar::Util qw( weaken );
|
||||
use Tie::IxHash;
|
||||
use WebGUI::International;
|
||||
use WebGUI::Utility qw(round isIn);
|
||||
|
|
|
|||
|
|
@ -292,4 +292,3 @@ sub warn {
|
|||
}
|
||||
|
||||
1;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use WebGUI::International;
|
|||
use Tie::IxHash;
|
||||
use Scalar::Util qw(weaken);
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Package WebGUI::Session::Icon
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package WebGUI::Session::Id;
|
|||
|
||||
use strict;
|
||||
use Digest::MD5 ();
|
||||
use Scalar::Util qw( weaken );
|
||||
use Time::HiRes qw( gettimeofday usleep );
|
||||
use MIME::Base64 qw(encode_base64 decode_base64);
|
||||
use Scalar::Util qw(weaken);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ package WebGUI::Session::Privilege;
|
|||
=cut
|
||||
|
||||
use strict;
|
||||
use Scalar::Util qw( weaken );
|
||||
use WebGUI::International;
|
||||
use WebGUI::Operation::Auth;
|
||||
use Scalar::Util qw(weaken);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ package WebGUI::Session::Style;
|
|||
|
||||
|
||||
use strict;
|
||||
use Tie::CPHash;
|
||||
use Scalar::Util qw( weaken );
|
||||
use WebGUI::International;
|
||||
use WebGUI::Macro;
|
||||
require WebGUI::Asset;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package WebGUI::Session::Url;
|
|||
use strict;
|
||||
use URI;
|
||||
use URI::Escape;
|
||||
use Scalar::Util qw( weaken );
|
||||
use WebGUI::International;
|
||||
use WebGUI::Utility;
|
||||
use Scalar::Util qw(weaken);
|
||||
|
|
|
|||
|
|
@ -905,6 +905,38 @@ sub www_ajaxSetCartItemShippingId {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_checkout ( )
|
||||
|
||||
All checks and work for checking out are contained in here.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_checkout {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
##Setting a shipping address greatly simplifies the Transaction
|
||||
if (! $self->requiresShipping && ! $self->get('shippingAddressId')) {
|
||||
$self->update({shippingAddressId => $self->get('billingAddressId')});
|
||||
}
|
||||
if ($self->readyForCheckout()) {
|
||||
my $total = $self->calculateTotal;
|
||||
##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, {cart => $self});
|
||||
$transaction->completePurchase('zero', 'success', 'success');
|
||||
$self->onCompletePurchase;
|
||||
$transaction->sendNotifications();
|
||||
return $transaction->thankYou();
|
||||
}
|
||||
my $gateway = $self->getPaymentGateway;
|
||||
return $gateway->www_getCredentials;
|
||||
}
|
||||
return $self->www_view;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_lookupPosUser ( )
|
||||
|
||||
Adds a Point of Sale user to the cart.
|
||||
|
|
@ -950,24 +982,8 @@ sub www_update {
|
|||
return undef;
|
||||
}
|
||||
elsif ($session->form->get('checkout')) {
|
||||
##Setting a shipping address greatly simplifies the Transaction
|
||||
if (! $self->requiresShipping && ! $self->get('shippingAddressId')) {
|
||||
$self->update({shippingAddressId => $self->get('billingAddressId')});
|
||||
}
|
||||
if ($self->readyForCheckout()) {
|
||||
my $total = $self->calculateTotal;
|
||||
##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, {cart => $self});
|
||||
$transaction->completePurchase('zero', 'success', 'success');
|
||||
$self->onCompletePurchase;
|
||||
$transaction->sendNotifications();
|
||||
return $transaction->thankYou();
|
||||
}
|
||||
my $gateway = $self->getPaymentGateway;
|
||||
return $gateway->www_getCredentials;
|
||||
}
|
||||
##Shortcut method for checkout, so that the cart form contents don't get lost.
|
||||
return $self->www_checkout();
|
||||
}
|
||||
return $self->www_view;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use WebGUI::Workflow::Instance;
|
|||
use JSON ();
|
||||
use WebGUI::ProfileField;
|
||||
use Tie::CPHash;
|
||||
use Scalar::Util qw( weaken );
|
||||
|
||||
=head1 NAME
|
||||
|
||||
|
|
@ -1070,6 +1071,7 @@ sub new {
|
|||
my $self = $session->cache->get("user_" . $userId) || {};
|
||||
bless $self, $class;
|
||||
$self->{_session} = $session;
|
||||
weaken( $self->{_session} );
|
||||
unless ($self->{_userId} && $self->{_user}{username}) {
|
||||
my %user;
|
||||
tie %user, 'Tie::CPHash';
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ sub www_pickStyle {
|
|||
my @styles;
|
||||
for my $styleId ( @styleIds ) {
|
||||
next if grep { $_ eq $styleId } @skipStyleIds;
|
||||
my $style = WebGUI::Asset->newByDynamicClass( $session, $styleId );
|
||||
my $style = WebGUI::Asset->newById( $session, $styleId );
|
||||
push @styles, $style;
|
||||
}
|
||||
|
||||
|
|
@ -256,10 +256,16 @@ sub www_chooseContentSave {
|
|||
|
||||
# update default site style
|
||||
$session->setting->set( "userFunctionStyleId", $self->get('styleTemplateId') );
|
||||
foreach my $asset ( @{ $home->getLineage( [ "self", "descendants" ], { returnObjects => 1 } ) } ) {
|
||||
if ( defined $asset ) {
|
||||
$asset->update( { styleTemplateId => $self->get("styleTemplateId") } );
|
||||
my $assetIter = $home->getLineageIterator( [ "self", "descendants" ] );
|
||||
while ( 1 ) {
|
||||
my $asset;
|
||||
eval { $asset = $assetIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $asset;
|
||||
$asset->update( { styleTemplateId => $self->get("styleTemplateId") } );
|
||||
}
|
||||
|
||||
# add new pages
|
||||
|
|
|
|||
|
|
@ -363,7 +363,15 @@ sub www_defaultStyleSave {
|
|||
# update default site style
|
||||
$session->setting->set( "userFunctionStyleId", $self->get('styleTemplateId') );
|
||||
my $home = WebGUI::Asset->getDefault( $session );
|
||||
foreach my $asset ( @{ $home->getLineage( [ "self", "descendants" ], { returnObjects => 1 } ) } ) {
|
||||
my $assetIter = $home->getLineageIterator( [ "self", "descendants" ] );
|
||||
while ( 1 ) {
|
||||
my $asset;
|
||||
eval { $asset = $assetIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $asset;
|
||||
if ( defined $asset ) {
|
||||
$asset->update( { styleTemplateId => $self->get("styleTemplateId") } );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,26 +72,39 @@ sub execute {
|
|||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $epoch = time();
|
||||
my $expireTime = $epoch + $self->getTTL();
|
||||
my $getAnArchive = WebGUI::Asset::Wobject::StoryArchive->getIsa($session);
|
||||
ARCHIVE: while (my $archive = $getAnArchive->()) {
|
||||
next ARCHIVE unless $archive && $archive->get("archiveAfter");
|
||||
my $archiveDate = $epoch - $archive->get("archiveAfter");
|
||||
my $folders = $archive->getLineage(
|
||||
my $folderIter = $archive->getLineageIterator(
|
||||
['children'],
|
||||
{
|
||||
statusToInclude => ['approved'],
|
||||
whereClause => 'creationDate < '.$session->db->quote($archiveDate),
|
||||
returnObjects => 1,
|
||||
},
|
||||
);
|
||||
FOLDER: foreach my $folder (@{ $folders }) {
|
||||
next FOLDER unless $folder;
|
||||
my $stories = $folder->getLineage(
|
||||
['children'], { returnObjects => 1, },
|
||||
);
|
||||
STORY: foreach my $story (@{ $stories }) {
|
||||
next STORY unless $story;
|
||||
FOLDER: while ( 1 ) {
|
||||
my $folder;
|
||||
eval { $folder = $folderIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $folder;
|
||||
my $storyIter = $folder->getLineageIterator( ['children'] );
|
||||
STORY: while ( 1 ) {
|
||||
my $story;
|
||||
eval { $story = $storyIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $story;
|
||||
$story->update({ status => 'archived' });
|
||||
if (time() > $expireTime) {
|
||||
return $self->WAITING(1);
|
||||
}
|
||||
}
|
||||
$folder->update({ status => 'archived' });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,19 +107,25 @@ sub execute {
|
|||
|
||||
# kill temporary assets
|
||||
my $tempspace = WebGUI::Asset->getTempspace($self->session);
|
||||
my $children = $tempspace->getLineage(["children"], {
|
||||
returnObjects => 1,
|
||||
my $childIter = $tempspace->getLineageIterator(["children"], {
|
||||
statesToInclude => [qw(trash clipboard published)],
|
||||
statusToInclude => [qw(pending archived approved)],
|
||||
});
|
||||
foreach my $asset (@{$children}) {
|
||||
if (time() - $asset->get("revisionDate") > $self->get("storageTimeout")) {
|
||||
unless ($asset->purge) {
|
||||
while ( 1 ) {
|
||||
my $child;
|
||||
eval { $child = $childIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$self->session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $child;
|
||||
if (time() - $child->get("revisionDate") > $self->get("storageTimeout")) {
|
||||
unless ($child->purge) {
|
||||
return $self->ERROR;
|
||||
}
|
||||
}
|
||||
# taking too long, give up
|
||||
return $self->WAITING(1) if (time() - $start > 50);
|
||||
return $self->WAITING(1) if (time() - $start > $self->getTTL);
|
||||
}
|
||||
|
||||
# kill temporary files
|
||||
|
|
|
|||
|
|
@ -76,13 +76,20 @@ sub execute {
|
|||
# keep track of how much time it's taking
|
||||
my $start = time;
|
||||
my $limit = 2_500;
|
||||
my $timeLimit = 60;
|
||||
my $timeLimit = $self->getTTL;
|
||||
|
||||
my $list = $root->getLineage( ['descendants'], { returnObjects => 1,
|
||||
my $emsFormIter = $root->getLineageIterator( ['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::EMSSubmissionForm'],
|
||||
} );
|
||||
|
||||
for my $emsForm ( @$list ) {
|
||||
while ( 1 ) {
|
||||
my $emsForm;
|
||||
eval { $emsForm = $emsFormIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $emsForm;
|
||||
my $daysBeforeCleanup = $emsForm->get('daysBeforeCleanup') ;
|
||||
next if ! $daysBeforeCleanup;
|
||||
my $whereClause = q{ submissionStatus='denied' };
|
||||
|
|
@ -91,12 +98,19 @@ sub execute {
|
|||
}
|
||||
my $checkDate = time - ( 60*60*24* $daysBeforeCleanup );
|
||||
$whereClause .= q{ and assetData.lastModified < } . $checkDate;
|
||||
my $res = $emsForm->getLineage(['children'],{ returnObjects => 1,
|
||||
my $submissionIter = $emsForm->getLineageIterator(['children'],{
|
||||
joinClass => 'WebGUI::Asset::EMSSubmission',
|
||||
includeOnlyClasses => ['WebGUI::Asset::EMSSubmission'],
|
||||
whereClause => $whereClause,
|
||||
} );
|
||||
for my $submission ( @$res ) {
|
||||
while ( 1 ) {
|
||||
my $submission;
|
||||
eval { $submission = $submissionIter->() };
|
||||
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
||||
$session->log->error($x->full_message);
|
||||
next;
|
||||
}
|
||||
last unless $submission;
|
||||
$submission->purge;
|
||||
$limit--;
|
||||
return $self->WAITING(1) if ! $limit or time > $start + $timeLimit;
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ sub execute {
|
|||
}
|
||||
}
|
||||
my $sth = $self->session->db->read("select groupId,deleteOffset,groupCacheTimeout from groups");
|
||||
my $expireTime = time() + $self->getTTL();
|
||||
while (my $data = $sth->hashRef) {
|
||||
if ($data->{groupCacheTimeout} > 0) {
|
||||
# there is no need to wait deleteOffset days for expired external group cache data
|
||||
|
|
@ -94,6 +95,10 @@ sub execute {
|
|||
} else {
|
||||
$self->session->db->write("delete from groupings where groupId=? and expireDate < ?", [$data->{groupId}, time()-$data->{deleteOffset}]);
|
||||
}
|
||||
if (time() > $expireTime) {
|
||||
$sth->finish;
|
||||
return $self->WAITING(1);
|
||||
}
|
||||
}
|
||||
return $self->COMPLETE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,8 +78,9 @@ sub execute {
|
|||
my $limit = 2_500;
|
||||
my $timeLimit = 60;
|
||||
|
||||
my $list = $root->getLineage( ['descendants'], { returnObjects => 1,
|
||||
my $list = $root->getLineage( ['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::EMSSubmissionForm'],
|
||||
returnObjects => 1,
|
||||
} );
|
||||
|
||||
for my $emsForm ( @$list ) {
|
||||
|
|
@ -88,6 +89,7 @@ sub execute {
|
|||
joinClass => 'WebGUI::Asset::EMSSubmission',
|
||||
includeOnlyClasses => ['WebGUI::Asset::EMSSubmission'],
|
||||
whereClause => $whereClause,
|
||||
returnObjects => 1,
|
||||
} );
|
||||
for my $submission ( @$res ) {
|
||||
my $properties = { className => 'WebGUI::Asset::Sku::EMSTicket' };
|
||||
|
|
|
|||
|
|
@ -1271,6 +1271,12 @@ Couldn't open %-s because %-s <br />
|
|||
context => q{Error message in Asset.pm},
|
||||
},
|
||||
|
||||
'clear package flag' => {
|
||||
message => q{Clear package flag},
|
||||
lastUpdate => 1275419384,
|
||||
context => q{Package import option in admin console},
|
||||
},
|
||||
|
||||
'need a userId parameter' => {
|
||||
message => q{need a userId parameter},
|
||||
lastUpdated => 0,
|
||||
|
|
|
|||
|
|
@ -419,6 +419,11 @@ our $I18N = {
|
|||
message => 'Search by keyword.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar searchForm_location' => {
|
||||
message => 'Search by location.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar searchForm_className' => {
|
||||
message => 'Search by class name.',
|
||||
|
|
@ -616,6 +621,12 @@ our $I18N = {
|
|||
lastUpdated => 0,
|
||||
context => "Label for the 'Keywords' input for the search form. 'Tags' is used because Keywords may be confused with the generic, all-inclusive search box.",
|
||||
},
|
||||
|
||||
'template search field location' => {
|
||||
message => "Location",
|
||||
lastUpdated => 0,
|
||||
context => "Label for the 'Location' input for the search form.",
|
||||
},
|
||||
|
||||
'template search field className' => {
|
||||
message => "Search Type",
|
||||
|
|
|
|||
|
|
@ -88,17 +88,17 @@ our $I18N = {
|
|||
},
|
||||
|
||||
'helpvar isNewPhoto' => {
|
||||
message => 'This variable is true if the user is adding a new Photo',
|
||||
message => 'This variable is true if the user is adding a new Photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar commentForm_start' => {
|
||||
message => 'Begin the comment form',
|
||||
message => 'Begin the comment form.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar commentForm_end' => {
|
||||
message => 'End the comment form',
|
||||
message => 'End the comment form.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
|
|
@ -108,37 +108,52 @@ our $I18N = {
|
|||
},
|
||||
|
||||
'helpvar commentForm_submit' => {
|
||||
message => 'Submit the comment form',
|
||||
message => 'Submit the comment form.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar canComment' => {
|
||||
message => 'This is true if the current user can comment on this photo',
|
||||
message => 'This is true if the current user can comment on this photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar canEdit' => {
|
||||
message => 'This is true if the current user can edit this photo',
|
||||
message => 'This is true if the current user can edit this photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar fileUrl' => {
|
||||
message => 'The URL to the normal-sized photo',
|
||||
message => 'The URL to the normal-sized photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar numberOfComments' => {
|
||||
message => 'The total number of comments on this photo',
|
||||
message => 'The total number of comments on this photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar ownerUsername' => {
|
||||
message => 'The username of the user who posted this photo',
|
||||
message => 'The username of the user who posted this photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar ownerAlias' => {
|
||||
message => 'The alias of the user who posted this photo. Defaults to the username if not available.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar ownerId' => {
|
||||
message => 'The Id of the user who posted this photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar ownerProfileUrl' => {
|
||||
message => 'The URL to the profile of the user who posted this photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar thumbnailUrl' => {
|
||||
message => 'The URL to the thumbnail of this photo',
|
||||
message => 'The URL to the thumbnail of this photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
|
|
@ -148,12 +163,12 @@ our $I18N = {
|
|||
},
|
||||
|
||||
'helpvar url_demote' => {
|
||||
message => 'The URL to demote this photo in rank. Will return the user directly to the parent GalleryAlbum edit form',
|
||||
message => 'The URL to demote this photo in rank. Will return the user directly to the parent GalleryAlbum edit form.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar url_edit' => {
|
||||
message => 'The URL to edit this photo',
|
||||
message => 'The URL to edit this photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
|
|
@ -168,12 +183,12 @@ our $I18N = {
|
|||
},
|
||||
|
||||
'helpvar url_listFilesForOwner' => {
|
||||
message => 'The URL to list files and albums posted by the owner of this photo',
|
||||
message => 'The URL to list files and albums posted by the owner of this photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar url_promote' => {
|
||||
message => 'The URL to promote this photo in rank. Will return the user directly to the parent GalleryAlbum edit form',
|
||||
message => 'The URL to promote this photo in rank. Will return the user directly to the parent GalleryAlbum edit form.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
|
|
@ -193,22 +208,22 @@ our $I18N = {
|
|||
},
|
||||
|
||||
'helpvar exifLoop' => {
|
||||
message => 'A loop of EXIF tags',
|
||||
message => 'A loop of EXIF tags.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar exifLoop tag' => {
|
||||
message => 'The name of the EXIF tag',
|
||||
message => 'The name of the EXIF tag.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar exifLoop value' => {
|
||||
message => 'The value of the EXIF tag',
|
||||
message => 'The value of the EXIF tag.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar url_addArchive' => {
|
||||
message => 'The URL to add an archive to the parent Album',
|
||||
message => 'The URL to add an archive to the parent Album.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
|
|
@ -263,7 +278,7 @@ our $I18N = {
|
|||
},
|
||||
|
||||
'helpvar commentLoop' => {
|
||||
message => 'Loop over a page of comments to this photo',
|
||||
message => 'Loop over a page of comments to this photo.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
|
|
@ -278,12 +293,12 @@ our $I18N = {
|
|||
},
|
||||
|
||||
'helpvar commentLoop creationDate' => {
|
||||
message => 'The creation date of the comment',
|
||||
message => 'The creation date of the comment.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'helpvar commentLoop bodyText' => {
|
||||
message => 'The body of the comment',
|
||||
message => 'The body of the comment.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
|
|
@ -298,7 +313,7 @@ our $I18N = {
|
|||
},
|
||||
|
||||
'helpvar commentLoop_pageBar' => {
|
||||
message => 'The bar to navigate through pages of comments',
|
||||
message => 'The bar to navigate through pages of comments.',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
|
|
@ -370,13 +385,13 @@ our $I18N = {
|
|||
'template view title' => {
|
||||
message => 'Photo Details',
|
||||
lastUpdated => 0,
|
||||
context => 'The title of the default view of Photo assets',
|
||||
context => 'The title of the default view of Photo assets.',
|
||||
},
|
||||
|
||||
'template view details' => {
|
||||
message => 'Details',
|
||||
lastUpdated => 0,
|
||||
context => 'List of information about the photo',
|
||||
context => 'List of information about the photo.',
|
||||
},
|
||||
|
||||
'more details' => {
|
||||
|
|
@ -492,6 +507,12 @@ our $I18N = {
|
|||
lastUpdated => 0,
|
||||
context => 'Label for photos that are not friends only',
|
||||
},
|
||||
|
||||
'template filesForUser' => {
|
||||
message => 'more photos',
|
||||
lastUpdated => 0,
|
||||
context => 'Label for the link to the users\' photos.',
|
||||
},
|
||||
|
||||
'template assetName' => {
|
||||
message => 'Photo',
|
||||
|
|
|
|||
|
|
@ -280,48 +280,48 @@ Feed Order: Items will be in the order they appeared in the feed}
|
|||
},
|
||||
|
||||
'descriptionFirst100words' => {
|
||||
message => q{The first 100 words of the description.},
|
||||
lastUpdated => 0,
|
||||
message => q{The first 100 words of the description, with all HTML removed.},
|
||||
lastUpdated => 1274815483,
|
||||
},
|
||||
'descriptionFirst75words' => {
|
||||
message => q{The first 75 words of the description.},
|
||||
lastUpdated => 0,
|
||||
message => q{The first 75 words of the description, with all HTML removed.},
|
||||
lastUpdated => 1274815485,
|
||||
},
|
||||
'descriptionFirst50words' => {
|
||||
message => q{The first 50 words of the description.},
|
||||
lastUpdated => 0,
|
||||
message => q{The first 50 words of the description, with all HTML removed.},
|
||||
lastUpdated => 1274815486,
|
||||
},
|
||||
'descriptionFirst25words' => {
|
||||
message => q{The first 25 words of the description.},
|
||||
lastUpdated => 0,
|
||||
message => q{The first 25 words of the description, with all HTML removed.},
|
||||
lastUpdated => 1274815488,
|
||||
},
|
||||
'descriptionFirst10words' => {
|
||||
message => q{The first 10 words of the description.},
|
||||
lastUpdated => 0,
|
||||
message => q{The first 10 words of the description, with all HTML removed.},
|
||||
lastUpdated => 1274815490,
|
||||
},
|
||||
'descriptionFirst2paragraphs' => {
|
||||
message => q{The first 2 paragraphs of the description.},
|
||||
message => q{The first 2 paragraphs of the description, with all HTML removed.},
|
||||
lastUpdated => 0,
|
||||
},
|
||||
'descriptionFirstParagraph' => {
|
||||
message => q{The first paragraph of the description.},
|
||||
message => q{The first paragraph of the description, with all HTML removed.},
|
||||
lastUpdated => 0,
|
||||
},
|
||||
'descriptionFirst4sentences' => {
|
||||
message => q{The first 4 sentences of the description.},
|
||||
lastUpdated => 0,
|
||||
message => q{The first 4 sentences of the description, with all HTML removed.},
|
||||
lastUpdated => 1274816277,
|
||||
},
|
||||
'descriptionFirst3sentences' => {
|
||||
message => q{The first 3 sentences of the description.},
|
||||
lastUpdated => 0,
|
||||
message => q{The first 3 sentences of the description, with all HTML removed.},
|
||||
lastUpdated => 1274816276,
|
||||
},
|
||||
'descriptionFirst2sentences' => {
|
||||
message => q{The first 2 sentences of the description.},
|
||||
lastUpdated => 0,
|
||||
message => q{The first 2 sentences of the description, with all HTML removed.},
|
||||
lastUpdated => 1274816274,
|
||||
},
|
||||
'descriptionFirstSentence' => {
|
||||
message => q{The first sentence of the description.},
|
||||
lastUpdated => 0,
|
||||
message => q{The first sentence of the description, with all HTML removed.},
|
||||
lastUpdated => 1274816273,
|
||||
},
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,7 +34,12 @@ our $I18N = { ##hashref of hashes
|
|||
message => q|The English name of the language.|,
|
||||
lastUpdated => 1131394072,
|
||||
context => q|A label of the language to use in the template|
|
||||
},
|
||||
},
|
||||
'language_isCurrent' => {
|
||||
message => q|A boolean which is true if this language is the current language.|,
|
||||
lastUpdated => 1131394072,
|
||||
context => q|A label of the language to use in the template|
|
||||
},
|
||||
'language_url' => {
|
||||
message => q|The url that sets the WebGUI language to the selected language.|,
|
||||
lastUpdated => 1131394072,
|
||||
|
|
|
|||
265
sbin/findBrokenAssets.pl
Normal file
265
sbin/findBrokenAssets.pl
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# WebGUI is Copyright 2001-2009 Plain Black Corporation.
|
||||
#-------------------------------------------------------------------
|
||||
# Please read the legal notices (docs/legal.txt) and the license
|
||||
# (docs/license.txt) that came with this distribution before using
|
||||
# this software.
|
||||
#-------------------------------------------------------------------
|
||||
# http://www.plainblack.com info@plainblack.com
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use File::Basename ();
|
||||
use File::Spec;
|
||||
|
||||
my $webguiRoot;
|
||||
|
||||
BEGIN {
|
||||
$webguiRoot = File::Spec->rel2abs( File::Spec->catdir( File::Basename::dirname(__FILE__), File::Spec->updir ) );
|
||||
unshift @INC, File::Spec->catdir( $webguiRoot, 'lib' );
|
||||
}
|
||||
|
||||
$|++; # disable output buffering
|
||||
|
||||
our ( $configFile, $help, $man, $fix, $delete );
|
||||
use Pod::Usage;
|
||||
use Getopt::Long;
|
||||
use WebGUI::Session;
|
||||
|
||||
# Get parameters here, including $help
|
||||
GetOptions(
|
||||
'configFile=s' => \$configFile,
|
||||
'help' => \$help,
|
||||
'man' => \$man,
|
||||
'fix' => \$fix,
|
||||
'delete' => \$delete,
|
||||
);
|
||||
|
||||
pod2usage( verbose => 1 ) if $help;
|
||||
pod2usage( verbose => 2 ) if $man;
|
||||
pod2usage( msg => "Must specify a config file!" ) unless $configFile;
|
||||
|
||||
my $session = start( $webguiRoot, $configFile );
|
||||
|
||||
sub progress {
|
||||
my ( $total, $current ) = @_;
|
||||
local $| = 1;
|
||||
my $done = int( ( ( $current / $total ) * 100 ) / 2 );
|
||||
$done &&= $done - 1; # Fit the >
|
||||
my $space = 49 - $done;
|
||||
print "\r[", '=' x $done, '>', ' ' x $space, ']';
|
||||
printf ' (%d/%d)', $current, $total;
|
||||
}
|
||||
|
||||
my $totalAsset = $session->db->quickScalar('SELECT COUNT(*) FROM asset');
|
||||
my $totalAssetData = $session->db->quickScalar('SELECT COUNT( DISTINCT( assetId ) ) FROM assetData' );
|
||||
my $total = $totalAsset >= $totalAssetData ? $totalAsset : $totalAssetData;
|
||||
|
||||
# Order by to put corrupt parents before corrupt children
|
||||
# Join assetData to get all asset and assetData
|
||||
my $sql = "SELECT * FROM asset LEFT JOIN assetData USING ( assetId ) GROUP BY assetId ORDER BY lineage ASC";
|
||||
my $sth = $session->db->read($sql);
|
||||
|
||||
my $count = 1;
|
||||
my %classTables; # Cache definition lookups
|
||||
while ( my %row = $sth->hash ) {
|
||||
eval { WebGUI::Asset->newPending( $session, $row{assetId} ) };
|
||||
if ( $@ ) {
|
||||
|
||||
# Replace the progress bar with a message
|
||||
printf "\r%-68s", "-- Corrupt: $row{assetId}";
|
||||
|
||||
# Should we do something?
|
||||
if ($fix) {
|
||||
my $classTables = $classTables{ $row{className} } ||= do {
|
||||
eval "require $row{className}";
|
||||
[ map { $_->{tableName} } reverse @{ $row{className}->definition($session) } ];
|
||||
};
|
||||
$row{revisionDate} ||= time;
|
||||
|
||||
for my $table ( @{$classTables} ) {
|
||||
my $sqlFind = "SELECT * FROM $table WHERE assetId=? ORDER BY revisionDate DESC";
|
||||
my @params = @row{qw( assetId )};
|
||||
my $insertRow = $session->db->quickHashRef( $sqlFind, \@params ) || {};
|
||||
if ( $row{revisionDate} != $insertRow->{revisionDate} ) {
|
||||
$insertRow->{ assetId } = $row{assetId};
|
||||
$insertRow->{ revisionDate } = $row{revisionDate};
|
||||
my $cols = join ",", keys %$insertRow;
|
||||
my @values = values %$insertRow;
|
||||
my $places = join ",", ('?') x @values;
|
||||
my $sqlFix = "INSERT INTO $table ($cols) VALUES ($places)";
|
||||
$session->db->write( $sqlFix, \@values );
|
||||
}
|
||||
}
|
||||
print "Fixed.\n";
|
||||
|
||||
# Make sure we have a valid parent
|
||||
unless ( WebGUI::Asset->newByDynamicClass( $session, $row{parentId} ) ) {
|
||||
my $asset = WebGUI::Asset->newByDynamicClass( $session, $row{assetId} );
|
||||
$asset->setParent( WebGUI::Asset->getImportNode( $session ) );
|
||||
print "\tNOTE: Invalid parent. Asset moved to Import Node\n";
|
||||
}
|
||||
|
||||
} ## end if ($fix)
|
||||
elsif ($delete) {
|
||||
my $classTables = $classTables{ $row{className} } ||= do {
|
||||
eval "require $row{className}";
|
||||
[ map { $_->{tableName} } reverse @{ $row{className}->definition($session) } ];
|
||||
};
|
||||
|
||||
my @params = @row{qw( assetId revisionDate )};
|
||||
for my $table ( @{$classTables} ) {
|
||||
my $sqlDelete = "DELETE FROM $table WHERE assetId=? AND revisionDate=?";
|
||||
$session->db->write( $sqlDelete, \@params );
|
||||
}
|
||||
$session->db->write( "DELETE FROM asset WHERE assetId=?", [$row{assetId}] );
|
||||
|
||||
print "Deleted.\n";
|
||||
} ## end elsif ($delete)
|
||||
else { # report
|
||||
print "\n";
|
||||
if ( $row{revisionDate} ) {
|
||||
printf "%10s: %s\n", "revised", scalar( localtime $row{revisionDate} );
|
||||
}
|
||||
|
||||
# Parent
|
||||
if ( my $parent = WebGUI::Asset->newByDynamicClass( $session, $row{parentId} ) ) {
|
||||
printf "%10s: %s (%s)\n", "parent", $parent->getTitle, $parent->getId;
|
||||
}
|
||||
elsif ( $session->db->quickScalar( "SELECT * FROM asset WHERE assetId=?", [$row{parentId}] ) ) {
|
||||
print "Parent corrupt ($row{parentId}).\n";
|
||||
}
|
||||
else {
|
||||
print "Parent missing ($row{parentId}).\n";
|
||||
}
|
||||
|
||||
# More properties
|
||||
if ( $row{revisionDate} ) {
|
||||
my %assetData = $session->db->quickHash( "SELECT * FROM assetData WHERE assetId=? AND revisionDate=?",
|
||||
[ @row{ "assetId", "revisionDate" } ] );
|
||||
for my $key (qw( title url )) {
|
||||
printf "%10s: %s\n", $key, $assetData{$key};
|
||||
}
|
||||
}
|
||||
else {
|
||||
print "No current asset data.\n";
|
||||
}
|
||||
|
||||
# Previous revisions
|
||||
my %lastRev
|
||||
= $session->db->quickHash(
|
||||
"SELECT * FROM assetData WHERE assetId=? AND revisionDate != ? ORDER BY revisionDate DESC",
|
||||
[ $row{assetId}, $row{revisionDate} ]
|
||||
);
|
||||
if ( $lastRev{assetId} ) {
|
||||
print "Previous revision:\n";
|
||||
for my $key (qw( title url )) {
|
||||
printf "%10s: %s\n", $key, $lastRev{$key};
|
||||
}
|
||||
}
|
||||
else {
|
||||
print "No previous revisions.\n";
|
||||
}
|
||||
|
||||
|
||||
# Asset History
|
||||
my $history = $session->db->buildArrayRefOfHashRefs(
|
||||
"SELECT * FROM assetHistory LEFT JOIN users USING (userId) WHERE assetId=? ORDER BY dateStamp DESC",
|
||||
[ $row{assetId} ],
|
||||
);
|
||||
if ( $history->[0] ) {
|
||||
my $username = $history->[0]{username} || "<Unknown User>";
|
||||
printf "Last action '%s'\n\tby %s\n\ton %s\n",
|
||||
$history->[0]{actionTaken},
|
||||
$username,
|
||||
scalar( localtime $history->[0]{dateStamp} ),
|
||||
;
|
||||
}
|
||||
} ## end else [ if ($fix) ]
|
||||
|
||||
} ## end if ( !$asset )
|
||||
progress( $total, $count++ );
|
||||
} ## end while ( my %row = $sth->hash)
|
||||
|
||||
finish($session);
|
||||
print "\n";
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Your sub here
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub start {
|
||||
my $webguiRoot = shift;
|
||||
my $configFile = shift;
|
||||
my $session = WebGUI::Session->open( $webguiRoot, $configFile );
|
||||
$session->user( { userId => 3 } );
|
||||
return $session;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub finish {
|
||||
my $session = shift;
|
||||
$session->var->end;
|
||||
$session->close;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
findBrokenAssets.pl -- Find and fix broken assets
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
findBrokenAssets.pl --configFile config.conf [--fix|--delete]
|
||||
|
||||
utility --help
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This utility will find any broken assets that cannot be instantiated and are
|
||||
causing undesired operation of your website.
|
||||
|
||||
It can also automatically delete them or fix them so you can restore missing data.
|
||||
|
||||
=head1 ARGUMENTS
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over
|
||||
|
||||
=item B<--configFile config.conf>
|
||||
|
||||
The WebGUI config file to use. Only the file name needs to be specified,
|
||||
since it will be looked up inside WebGUI's configuration directory.
|
||||
This parameter is required.
|
||||
|
||||
=item B<--delete>
|
||||
|
||||
Delete any corrupted assets.
|
||||
|
||||
=item B<--fix>
|
||||
|
||||
Try to fix any corrupted assets.
|
||||
|
||||
=item B<--help>
|
||||
|
||||
Shows a short summary and usage
|
||||
|
||||
=item B<--man>
|
||||
|
||||
Shows this document
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2001-2009 Plain Black Corporation.
|
||||
|
||||
=cut
|
||||
|
||||
#vim:ft=perl
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ use WebGUI::VersionTag;
|
|||
|
||||
use Test::More; # increment this value for each test you create
|
||||
use Test::MockObject;
|
||||
plan tests => 14;
|
||||
plan tests => 16;
|
||||
|
||||
my $session = WebGUI::Test->session;
|
||||
$session->user({userId => 3});
|
||||
|
|
@ -127,6 +127,30 @@ cmp_ok( $updatedSnippet->get('revisionDate'), '>', $snippetRev->get('revisionDat
|
|||
my $lastTag = WebGUI::VersionTag->getWorking($session);
|
||||
WebGUI::Test->addToCleanup($lastTag);
|
||||
|
||||
{
|
||||
# Test clearPackageFlag
|
||||
my $flagTag = WebGUI::VersionTag->create($session);
|
||||
WebGUI::Test->addToCleanup($flagTag);
|
||||
$flagTag->setWorking;
|
||||
my $tempspace = WebGUI::Asset->getTempspace($session);
|
||||
my $snippet = $tempspace->addChild(
|
||||
{ url => 'pflagt',
|
||||
title => 'package flag test',
|
||||
menuTitle => 'package flag test',
|
||||
className => 'WebGUI::Asset::Snippet',
|
||||
snippet => 'This is a test asset',
|
||||
isPackage => 1,
|
||||
}
|
||||
);
|
||||
my $storage = $snippet->exportPackage;
|
||||
WebGUI::Test->addToCleanup($storage);
|
||||
my $without = $tempspace->importPackage($storage);
|
||||
ok $without->get('isPackage'), 'has flag with no option';
|
||||
my $with = $tempspace->importPackage($storage, { clearPackageFlag => 1 });
|
||||
ok !$with->get('isPackage'), 'no flag with option';
|
||||
}
|
||||
|
||||
|
||||
TODO: {
|
||||
local $TODO = "Tests to make later";
|
||||
ok(0, 'Check package deployment with 2-level package and look for new style templates propagating down the tree');
|
||||
|
|
|
|||
|
|
@ -24,15 +24,20 @@ use WebGUI::Asset::File::GalleryFile::Photo;
|
|||
#----------------------------------------------------------------------------
|
||||
# Init
|
||||
my $session = WebGUI::Test->session;
|
||||
my $user = WebGUI::User->new( $session, 3 );
|
||||
my $node = WebGUI::Asset->getImportNode($session);
|
||||
my $versionTag = WebGUI::VersionTag->getWorking($session);
|
||||
|
||||
$versionTag->set({name=>"Photo Test"});
|
||||
addToCleanup($versionTag);
|
||||
|
||||
my $gallery
|
||||
= $node->addChild({
|
||||
className => "WebGUI::Asset::Wobject::Gallery",
|
||||
groupIdAddComment => 7, # Everyone
|
||||
groupIdAddFile => 2, # Registered Users
|
||||
});
|
||||
|
||||
my $album
|
||||
= $gallery->addChild({
|
||||
className => "WebGUI::Asset::Wobject::GalleryAlbum",
|
||||
|
|
@ -42,36 +47,40 @@ my $album
|
|||
{
|
||||
skipAutoCommitWorkflows => 1,
|
||||
});
|
||||
|
||||
my $previousPhoto
|
||||
= $album->addChild({
|
||||
className => "WebGUI::Asset::File::GalleryFile::Photo",
|
||||
ownerUserId => 3,
|
||||
ownerUserId => $user->getId,
|
||||
},
|
||||
undef,
|
||||
undef,
|
||||
{
|
||||
skipAutoCommitWorkflows => 1,
|
||||
});
|
||||
|
||||
my $photo
|
||||
= $album->addChild({
|
||||
className => "WebGUI::Asset::File::GalleryFile::Photo",
|
||||
ownerUserId => 3,
|
||||
ownerUserId => $user->getId,
|
||||
},
|
||||
undef,
|
||||
undef,
|
||||
{
|
||||
skipAutoCommitWorkflows => 1,
|
||||
});
|
||||
|
||||
my $nextPhoto
|
||||
= $album->addChild({
|
||||
className => "WebGUI::Asset::File::GalleryFile::Photo",
|
||||
ownerUserId => 3,
|
||||
ownerUserId => $user->getId,
|
||||
},
|
||||
undef,
|
||||
undef,
|
||||
{
|
||||
skipAutoCommitWorkflows => 1,
|
||||
});
|
||||
|
||||
$versionTag->commit;
|
||||
foreach my $asset ($gallery, $album, $photo) {
|
||||
$asset = $asset->cloneFromDb;
|
||||
|
|
@ -91,7 +100,10 @@ my $testTemplateVars = {
|
|||
synopsis => '', # Synopsis is not undef, is changed to empty string
|
||||
canComment => bool( 1 ),
|
||||
canEdit => bool( 0 ),
|
||||
ownerUsername => WebGUI::User->new( $session, 3 )->username,
|
||||
ownerUsername => $user->get("username"),
|
||||
ownerAlias => $user->get("alias") || $user->get("username"),
|
||||
ownerId => $user->getId,
|
||||
ownerProfileUrl => $user->getProfileUrl,
|
||||
synopsis_textonly => WebGUI::HTML::filter( $photo->get('synopsis'), "all" ),
|
||||
url => $photo->getUrl,
|
||||
url_addArchive => $album->getUrl('func=addArchive'),
|
||||
|
|
|
|||
|
|
@ -275,8 +275,10 @@ cmp_deeply(
|
|||
title => 'Story 1',
|
||||
description => 'WebGUI was originally called Web Done Right.',
|
||||
'link' => re('story-1$'),
|
||||
guid => re('story-1$'),
|
||||
author => 'JT Smith',
|
||||
date => $story->lastModified,
|
||||
pubDate => $session->datetime->epochToMail($story->creationDate),
|
||||
},
|
||||
'getRssData: returns correct data'
|
||||
);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ my $template3 = $importNode->addChild({
|
|||
className => "WebGUI::Asset::Template",
|
||||
title => 'headBlock test',
|
||||
template => "this is a template",
|
||||
});
|
||||
}, undef, time()-5);
|
||||
|
||||
my @atts = (
|
||||
{type => 'headScript', sequence => 1, url => 'bar'},
|
||||
|
|
@ -97,7 +97,7 @@ ok(exists $session->style->{_javascript}->{$_}, "$_ in style") for qw(foo bar bo
|
|||
# revision-ness of attachments
|
||||
|
||||
# sleep so the revisiondate isn't duplicated
|
||||
sleep 1;
|
||||
#sleep 1;
|
||||
|
||||
my $template3dup = $template3->duplicate;
|
||||
my @atts3dup = map { delete @{ $_ }{qw/attachId templateId revisionDate/}; $_; } @{ $template3dup->getAttachments };
|
||||
|
|
|
|||
318
t/Asset/Wobject/Gallery/search.t
Normal file
318
t/Asset/Wobject/Gallery/search.t
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
#-------------------------------------------------------------------
|
||||
# WebGUI is Copyright 2001-2009 Plain Black Corporation.
|
||||
#-------------------------------------------------------------------
|
||||
# Please read the legal notices (docs/legal.txt) and the license
|
||||
# (docs/license.txt) that came with this distribution before using
|
||||
# this software.
|
||||
#-------------------------------------------------------------------
|
||||
# http://www.plainblack.com info@plainblack.com
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
use FindBin;
|
||||
use strict;
|
||||
use lib "$FindBin::Bin/../../../lib";
|
||||
|
||||
# Test of the Gallery basic and advanced search. In non-live tests, the Gallery
|
||||
# search is accessed via the "search" method. Form parameters are passed in via
|
||||
# the pseudo request object of the test session.
|
||||
|
||||
use Test::More;
|
||||
use Test::Deep;
|
||||
|
||||
use WebGUI::Test; # Must use this before any other WebGUI modules
|
||||
use WebGUI::Asset::Wobject::Gallery;
|
||||
use WebGUI::Asset::Wobject::GalleryAlbum;
|
||||
use WebGUI::Asset::File::GalleryFile::Photo;
|
||||
use WebGUI::DateTime;
|
||||
use WebGUI::Session;
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Init
|
||||
my $session = WebGUI::Test->session;
|
||||
my $node = WebGUI::Asset->getImportNode($session);
|
||||
my $versionTag = WebGUI::VersionTag->getWorking($session);
|
||||
|
||||
$versionTag->set( { name=>"Gallery Search Test" } );
|
||||
addToCleanup( $versionTag );
|
||||
|
||||
# Create gallery and a single album
|
||||
my $gallery
|
||||
= $node->addChild({
|
||||
className => "WebGUI::Asset::Wobject::Gallery",
|
||||
},
|
||||
undef,
|
||||
undef,
|
||||
{
|
||||
skipAutoCommitWorkflows => 1,
|
||||
});
|
||||
|
||||
my $album
|
||||
= $gallery->addChild({
|
||||
className => "WebGUI::Asset::Wobject::GalleryAlbum",
|
||||
title => "album",
|
||||
synopsis => "synopsis2",
|
||||
keywords => "group2",
|
||||
},
|
||||
undef,
|
||||
undef,
|
||||
{
|
||||
skipAutoCommitWorkflows => 1,
|
||||
});
|
||||
my $albumId = $album->getId;
|
||||
|
||||
# Populate album with different photos
|
||||
my $photo1
|
||||
= $album->addChild({
|
||||
className => "WebGUI::Asset::File::GalleryFile::Photo",
|
||||
title => "photo1",
|
||||
synopsis => "synopsis1",
|
||||
keywords => "group1",
|
||||
location => "Heidelberg",
|
||||
},
|
||||
undef,
|
||||
undef,
|
||||
{
|
||||
skipAutoCommitWorkflows => 1,
|
||||
});
|
||||
my $id1 = $photo1->getId;
|
||||
|
||||
my $photo2
|
||||
= $album->addChild({
|
||||
className => "WebGUI::Asset::File::GalleryFile::Photo",
|
||||
title => "photo2",
|
||||
synopsis => "synopsis2",
|
||||
keywords => "group1",
|
||||
location => "Mannheim",
|
||||
},
|
||||
undef,
|
||||
undef,
|
||||
{
|
||||
skipAutoCommitWorkflows => 1,
|
||||
});
|
||||
my $id2 = $photo2->getId;
|
||||
|
||||
my $photo3
|
||||
= $album->addChild({
|
||||
className => "WebGUI::Asset::File::GalleryFile::Photo",
|
||||
title => "photo3",
|
||||
synopsis => "synopsis1",
|
||||
keywords => "group2",
|
||||
location => "Mannheim",
|
||||
},
|
||||
undef,
|
||||
undef,
|
||||
{
|
||||
skipAutoCommitWorkflows => 1,
|
||||
});
|
||||
my $id3 = $photo3->getId;
|
||||
|
||||
# Commit all changes
|
||||
$versionTag->commit;
|
||||
|
||||
# Make gallery default asset
|
||||
$session->asset( $gallery );
|
||||
|
||||
# Define some general variables
|
||||
my $result;
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Tests
|
||||
plan tests => 32;
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Basic search
|
||||
|
||||
note( "Basic gallery search" );
|
||||
|
||||
# Search by title
|
||||
|
||||
my $hits = search( { basicSearch => "album" } );
|
||||
# Basic search will behave differently from advanced search. The album and all
|
||||
# photos of the album will be returned, since the name of the album is added to
|
||||
# index keywords of photos.
|
||||
cmp_bag( $hits, [ $albumId, $id1, $id2, $id3 ], "Search for album entitled 'album' (basic search)" );
|
||||
|
||||
my $hits = search( { basicSearch => "photo1" } );
|
||||
cmp_bag( $hits, [ $id1 ], "Search for photo entitled 'photo1' (basic search)" );
|
||||
|
||||
my $hits = search( { title => "photo4" } );
|
||||
cmp_bag( $hits, [ ], "Search for non-existing photo entitled 'photo4' (basic search)" );
|
||||
|
||||
# Search by keywords
|
||||
|
||||
my $hits = search( { basicSearch => "group1" } );
|
||||
cmp_bag( $hits, [ $id1, $id2 ], "Search for albums/photos with keywords 'group1' (basic search)" );
|
||||
|
||||
my $hits = search( { basicSearch => "group2" } );
|
||||
cmp_bag( $hits, [ $albumId, $id3 ], "Search for albums/photos with keywords 'group2' (basic search)" );
|
||||
|
||||
# Search by description
|
||||
|
||||
my $hits = search( { basicSearch => "synopsis1" } );
|
||||
cmp_bag( $hits, [ $id1, $id3 ], "Search for albums/photos with synopsis 'synopsis1' (basic search)" );
|
||||
|
||||
my $hits = search( { basicSearch => "synopsis2" } );
|
||||
cmp_bag( $hits, [ $albumId, $id2 ], "Search for albums/photos with synopsis 'synopsis2' (basic search)" );
|
||||
|
||||
|
||||
# Warning: Tried to use 'here' and 'there' as locations for the following test.
|
||||
# For unknown reasons the test failed. It seems that these and possibly other
|
||||
# keywords are either filtered out by MySQL and/or are reserved words. Needs to
|
||||
# be checked!!!
|
||||
|
||||
my $hits = search( { basicSearch => "Mannheim" } );
|
||||
cmp_bag( $hits, [ $id2, $id3 ], "Search for photos taken at location 'Mannheim' (basic search)" );
|
||||
|
||||
my $hits = search( { basicSearch => "Heidelberg" } );
|
||||
cmp_bag( $hits, [ $id1 ], "Search for photos taken at location 'Heidelberg' (basic search)" );
|
||||
|
||||
# Search by multiple criteria
|
||||
|
||||
my $hits = search({ basicSearch => "group1 synopsis1" });
|
||||
cmp_bag( $hits, [ $id1 ], "Search for photo with keywords 'group1' and synopsis 'synopsis1' (basic search)" );
|
||||
|
||||
my $hits = search({ basicSearch => "group2 Mannheim" });
|
||||
cmp_bag( $hits, [ $id3 ], "Search for photo with keywords 'group2' and location 'Mannheim' (basic search)" );
|
||||
|
||||
my $hits = search({ basicSearch => "synopsis1 Mannheim" });
|
||||
cmp_bag( $hits, [ $id3 ], "Search for photo with synopsis 'synopsis1' and location 'Mannheim' (basic search)" );
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Advanced search
|
||||
|
||||
note( "Advanced gallery search" );
|
||||
|
||||
my $hits = search( { } );
|
||||
cmp_bag( $hits, [ ], "Empty search (advanced search)" );
|
||||
|
||||
# Search by class
|
||||
|
||||
my $hits = search( { className => "WebGUI::Asset::File::GalleryFile::Photo" } );
|
||||
cmp_bag( $hits, [ $id1, $id2, $id3 ], "Search for all photos (advanced search)" );
|
||||
|
||||
my $hits = search( { className => "WebGUI::Asset::Wobject::GalleryAlbum" } );
|
||||
cmp_bag( $hits, [ $albumId ], "Search for all albums (advanced search)" );
|
||||
|
||||
# Search by date
|
||||
|
||||
my $oneYearAgo = WebGUI::DateTime->new( $session, time )->add( years => -1 )->epoch;
|
||||
my $hits
|
||||
= search({
|
||||
creationDate_after => $oneYearAgo,
|
||||
creationDate_before => time(),
|
||||
});
|
||||
cmp_bag( $hits, [ $albumId, $id1, $id2, $id3 ], "Search by date, all included (advanced search)" );
|
||||
|
||||
my $hits
|
||||
= search({
|
||||
creationDate_after => time() + 1,
|
||||
creationDate_before => time() + 1,
|
||||
});
|
||||
cmp_bag( $hits, [ ], "Search by date, all excluded (advanced search)" );
|
||||
|
||||
# Search by title
|
||||
|
||||
my $hits = search( { title => "album" } );
|
||||
cmp_bag( $hits, [ $albumId ], "Search for album entitled 'album' (advanced search)" );
|
||||
|
||||
my $hits = search( { title => "photo1" } );
|
||||
cmp_bag( $hits, [ $id1 ], "Search for photo entitled 'photo1' (advanced search)" );
|
||||
|
||||
my $hits = search( { title => "photo4" } );
|
||||
cmp_bag( $hits, [ ], "Search for non-existing photo entitled 'photo4' (advanced search)" );
|
||||
|
||||
# Search by keywords
|
||||
|
||||
my $hits = search( { keywords => "group1" } );
|
||||
cmp_bag( $hits, [ $id1, $id2 ], "Search for albums/photos with keywords 'group1' (advanced search)" );
|
||||
|
||||
my $hits = search( { keywords => "group2" } );
|
||||
cmp_bag( $hits, [ $albumId, $id3 ], "Search for albums/photos with keywords 'group2' (advanced search)" );
|
||||
|
||||
my $hits = search( { keywords => "group3" } );
|
||||
cmp_bag( $hits, [ ], "Search for non-existing albums/photos with keywords 'group3' (advanced search)" );
|
||||
|
||||
# Search by description
|
||||
|
||||
my $hits = search( { description => "synopsis1" } );
|
||||
cmp_bag( $hits, [ $id1, $id3 ], "Search for albums/photos with synopsis 'synopsis1' (advanced search)" );
|
||||
|
||||
my $hits = search( { description => "synopsis2" } );
|
||||
cmp_bag( $hits, [ $albumId, $id2 ], "Search for albums/photos with synopsis 'synopsis2' (advanced search)" );
|
||||
|
||||
my $hits = search( { description => "synopsis3" } );
|
||||
cmp_bag( $hits, [ ], "Search for non-existing albums/photos with synopsis 'synopsis3' (advanced search)" );
|
||||
|
||||
# Search by location
|
||||
# Warning: Tried to use 'here' and 'there' as locations for the following test.
|
||||
# For unknown reasons the test failed. It seems that these and possibly other
|
||||
# keywords are either filtered out by MySQL and/or are reserved words. Needs to
|
||||
# be checked!!!
|
||||
|
||||
my $hits = search( { location => "Mannheim" } );
|
||||
cmp_bag( $hits, [ $id2, $id3 ], "Search for photos taken at location 'Mannheim' (advanced search)" );
|
||||
|
||||
my $hits = search( { location => "Heidelberg" } );
|
||||
cmp_bag( $hits, [ $id1 ], "Search for photos taken at location 'Heidelberg' (advanced search)" );
|
||||
|
||||
my $hits = search( { location => "Frankfurt" } );
|
||||
cmp_bag( $hits, [ ], "Search for non-existing photos taken at location 'Frankfurt' (advanced search)" );
|
||||
|
||||
# Search by multiple criteria
|
||||
|
||||
my $hits
|
||||
= search({
|
||||
keywords => "group1",
|
||||
description => "synopsis1",
|
||||
});
|
||||
cmp_bag( $hits, [ $id1 ], "Search for photo with keywords 'group1' and synopsis 'synopsis1' (advanced search)" );
|
||||
|
||||
my $hits
|
||||
= search({
|
||||
keywords => "group2",
|
||||
location => "Mannheim",
|
||||
});
|
||||
cmp_bag( $hits, [ $id3 ], "Search for photo with keywords 'group2' and location 'Mannheim' (advanced search)" );
|
||||
|
||||
my $hits
|
||||
= search({
|
||||
description => "synopsis1",
|
||||
location => "Mannheim",
|
||||
});
|
||||
cmp_bag( $hits, [ $id3 ], "Search for photo with synopsis 'synopsis1' and location 'Mannheim' (advanced search)" );
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# search( formParams )
|
||||
# Execute a search for photos and albums in the test gallery.
|
||||
#
|
||||
# Accepts a hash ref as single parameter. All key/value pairs in the hash are
|
||||
# added as form parameters to the pseudo request object before the search is
|
||||
# executed. See the Gallery search method for valid form fields.
|
||||
#
|
||||
# Returns a reference pointing an array containg the asset Ids of all hits.
|
||||
|
||||
sub search {
|
||||
my $formParams = shift;
|
||||
my $hits = [];
|
||||
|
||||
# Setup the mock request object
|
||||
$session->request->method( 'GET' );
|
||||
$session->request->setup_param( $formParams );
|
||||
|
||||
# Call gallery search function
|
||||
my ( $paginator, $keywords ) = $gallery->search;
|
||||
# Return ref to empty array if search could not be executed
|
||||
return $hits unless $paginator;
|
||||
|
||||
# Extract asset Ids from search results and compile array.
|
||||
for ( my $i = 1; $i <= $paginator->getNumberOfPages; $i++ ) {
|
||||
for my $result ( @{ $paginator->getPageData( $i ) } ) {
|
||||
push @{ $hits }, $result->{ assetId };
|
||||
}
|
||||
}
|
||||
return $hits;
|
||||
}
|
||||
|
|
@ -544,6 +544,8 @@ cmp_deeply(
|
|||
description => ignore(),
|
||||
'link' => ignore(),
|
||||
date => ignore(),
|
||||
guid => ignore(),
|
||||
pubDate => ignore(),
|
||||
author => ignore(),
|
||||
},
|
||||
{
|
||||
|
|
@ -552,6 +554,8 @@ cmp_deeply(
|
|||
'link' => ignore(),
|
||||
date => ignore(),
|
||||
author => ignore(),
|
||||
guid => ignore(),
|
||||
pubDate => ignore(),
|
||||
},
|
||||
{
|
||||
title => 'Story 3',
|
||||
|
|
@ -559,6 +563,8 @@ cmp_deeply(
|
|||
'link' => ignore(),
|
||||
date => ignore(),
|
||||
author => ignore(),
|
||||
guid => ignore(),
|
||||
pubDate => ignore(),
|
||||
},
|
||||
],
|
||||
'rssFeedItems'
|
||||
|
|
|
|||
|
|
@ -297,6 +297,8 @@ cmp_deeply(
|
|||
'link' => ignore(),
|
||||
date => ignore(),
|
||||
author => ignore(),
|
||||
guid => ignore(),
|
||||
pubDate => ignore(),
|
||||
},
|
||||
{
|
||||
title => 'red',
|
||||
|
|
@ -304,6 +306,8 @@ cmp_deeply(
|
|||
'link' => ignore(),
|
||||
date => ignore(),
|
||||
author => ignore(),
|
||||
guid => ignore(),
|
||||
pubDate => ignore(),
|
||||
},
|
||||
{
|
||||
title => 'brooks',
|
||||
|
|
@ -311,6 +315,8 @@ cmp_deeply(
|
|||
'link' => ignore(),
|
||||
date => ignore(),
|
||||
author => ignore(),
|
||||
guid => ignore(),
|
||||
pubDate => ignore(),
|
||||
},
|
||||
],
|
||||
'rssFeedItems'
|
||||
|
|
|
|||
|
|
@ -276,37 +276,37 @@ cmp_deeply(
|
|||
[
|
||||
{
|
||||
'extras' => undef,
|
||||
'url' => '/home?func=edit',
|
||||
'url' => re('func=edit$'),
|
||||
'label' => 'Edit'
|
||||
},
|
||||
{
|
||||
'extras' => undef,
|
||||
'url' => '/home?func=editSurvey',
|
||||
'url' => re('func=editSurvey$'),
|
||||
'label' => 'Edit Survey'
|
||||
},
|
||||
{
|
||||
'extras' => undef,
|
||||
'url' => '/home?func=takeSurvey',
|
||||
'url' => re('func=takeSurvey$'),
|
||||
'label' => 'Take Survey'
|
||||
},
|
||||
{
|
||||
'extras' => undef,
|
||||
'url' => '/home?func=graph',
|
||||
'url' => re('func=graph$'),
|
||||
'label' => 'Visualize'
|
||||
},
|
||||
{
|
||||
'extras' => undef,
|
||||
'url' => '/home?func=editTestSuite',
|
||||
'url' => re('func=editTestSuite$'),
|
||||
'label' => 'Test Suite'
|
||||
},
|
||||
{
|
||||
'extras' => undef,
|
||||
'url' => '/home?func=runTests',
|
||||
'url' => re('func=runTests$'),
|
||||
'label' => 'Run All Tests'
|
||||
},
|
||||
{
|
||||
'extras' => undef,
|
||||
'url' => '/home?func=runTests;format=tap',
|
||||
'url' => re('func=runTests;format=tap$'),
|
||||
'label' => 'Run All Tests (TAP)'
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use Data::Dumper;
|
|||
|
||||
use WebGUI::Test;
|
||||
use WebGUI::Session;
|
||||
use Test::More tests => 27; # increment this value for each test you create
|
||||
use Test::More tests => 29; # increment this value for each test you create
|
||||
use Test::Deep;
|
||||
use WebGUI::Asset::Wobject::SyndicatedContent;
|
||||
use XML::FeedPP;
|
||||
|
|
@ -175,7 +175,14 @@ is $vars->{item_loop}->[0]->{descriptionFirstParagraph},
|
|||
'... 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';
|
||||
'... first two paragraphs, when HTML is used';
|
||||
is $vars->{item_loop}->[0]->{descriptionFirst10words},
|
||||
"In the attached feed, there is a hidden return line ",
|
||||
'... first 10 words, with HTML stripped';
|
||||
is $vars->{item_loop}->[0]->{descriptionFirstSentence},
|
||||
"In the attached feed, there is a hidden return line character from the
|
||||
Rich Text editor in the first sentence of the description.",
|
||||
'... first sentence, with HTML stripped';
|
||||
|
||||
####################################################################
|
||||
#
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ foreach my $idx (0..$#ldapTests) {
|
|||
});
|
||||
}
|
||||
|
||||
WebGUI::Test->usersToDelete(@shawshank);
|
||||
WebGUI::Test->addToCleanup(@shawshank);
|
||||
|
||||
my $lGroup = WebGUI::Group->new($session, 'new');
|
||||
|
||||
|
|
@ -504,8 +504,7 @@ cmp_bag(
|
|||
$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
|
||||
$session->cache->remove("isInGroup"); #Delete stow so we get a good test
|
||||
|
||||
is_deeply(
|
||||
[ (map { $gY->hasDatabaseUser($_->getId) } @mob) ],
|
||||
|
|
@ -637,8 +636,7 @@ 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");
|
||||
$session->cache->remove("isInGroup");
|
||||
|
||||
#hasScratchUser test
|
||||
foreach my $scratchTest (@scratchTests) {
|
||||
|
|
|
|||
|
|
@ -49,11 +49,12 @@ $templateMock->mock('process', sub { $templateVars = $_[1]; } );
|
|||
$templateVars,
|
||||
{
|
||||
lang_loop => [
|
||||
{ 'language_url' => '?op=setLanguage;language=English',
|
||||
'language_lang' => 'English',
|
||||
{ 'language_url' => '?op=setLanguage;language=English',
|
||||
'language_lang' => 'English',
|
||||
'language_langAbbr' => 'en',
|
||||
'language_langAbbrLoc' => 'US',
|
||||
'language_langEng' => 'English',
|
||||
'language_langEng' => 'English',
|
||||
'language_isCurrent' => 1,
|
||||
},
|
||||
],
|
||||
delete_url => '?op=setLanguage;language=delete;',
|
||||
|
|
@ -82,6 +83,7 @@ $templateMock->mock('process', sub { $templateVars = $_[1]; } );
|
|||
'language_langAbbr' => 'en',
|
||||
'language_langAbbrLoc' => 'US',
|
||||
'language_langEng' => 'English',
|
||||
'language_isCurrent' => 1,
|
||||
},
|
||||
],
|
||||
delete_url => '?op=setLanguage;language=delete;',
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ cmp_deeply (
|
|||
{
|
||||
assetId => $article->getId,
|
||||
title => $article->get('title'),
|
||||
synopsis => '' . $article->get('synopsis'),
|
||||
synopsis => $article->get('synopsis') || '',
|
||||
url => $article->get('url'),
|
||||
revisionDate => $article->get('revisionDate'),
|
||||
creationDate => $article->get('creationDate'),
|
||||
|
|
|
|||
|
|
@ -1,155 +0,0 @@
|
|||
function emailCheck (emailStr) {
|
||||
|
||||
/* The following variable tells the rest of the function whether or not
|
||||
to verify that the address ends in a two-letter country or well-known
|
||||
TLD. 1 means check it, 0 means don't. */
|
||||
|
||||
var checkTLD=1;
|
||||
|
||||
/* The following is the list of known TLDs that an e-mail address must end with. */
|
||||
|
||||
var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/i;
|
||||
|
||||
/* The following pattern is used to check if the entered e-mail address
|
||||
fits the user@domain format. It also is used to separate the username
|
||||
from the domain. */
|
||||
|
||||
var emailPat=/^(.+)@(.+)$/;
|
||||
|
||||
/* The following string represents the pattern for matching all special
|
||||
characters. We don't want to allow special characters in the address.
|
||||
These characters include ( ) < > @ , ; : \ " . [ ] */
|
||||
|
||||
var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";
|
||||
|
||||
/* The following string represents the range of characters allowed in a
|
||||
username or domainname. It really states which chars aren't allowed.*/
|
||||
|
||||
var validChars="\[^\\s" + specialChars + "\]";
|
||||
|
||||
/* The following pattern applies if the "user" is a quoted string (in
|
||||
which case, there are no rules about which characters are allowed
|
||||
and which aren't; anything goes). E.g. "jiminy cricket"@disney.com
|
||||
is a legal e-mail address. */
|
||||
|
||||
var quotedUser="(\"[^\"]*\")";
|
||||
|
||||
/* The following pattern applies for domains that are IP addresses,
|
||||
rather than symbolic names. E.g. joe@[123.124.233.4] is a legal
|
||||
e-mail address. NOTE: The square brackets are required. */
|
||||
|
||||
var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
|
||||
|
||||
/* The following string represents an atom (basically a series of non-special characters.) */
|
||||
|
||||
var atom=validChars + '+';
|
||||
|
||||
/* The following string represents one word in the typical username.
|
||||
For example, in john.doe@somewhere.com, john and doe are words.
|
||||
Basically, a word is either an atom or quoted string. */
|
||||
|
||||
var word="(" + atom + "|" + quotedUser + ")";
|
||||
|
||||
// The following pattern describes the structure of the user
|
||||
|
||||
var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
|
||||
|
||||
/* The following pattern describes the structure of a normal symbolic
|
||||
domain, as opposed to ipDomainPat, shown above. */
|
||||
|
||||
var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");
|
||||
|
||||
/* Finally, let's start trying to figure out if the supplied address is valid. */
|
||||
|
||||
/* Begin with the coarse pattern to simply break up user@domain into
|
||||
different pieces that are easy to analyze. */
|
||||
|
||||
var matchArray=emailStr.match(emailPat);
|
||||
|
||||
if (matchArray==null) {
|
||||
|
||||
/* Too many/few @'s or something; basically, this address doesn't
|
||||
even fit the general mould of a valid e-mail address. */
|
||||
|
||||
alert("Email address seems incorrect (check @ and .'s)");
|
||||
return false;
|
||||
}
|
||||
var user=matchArray[1];
|
||||
var domain=matchArray[2];
|
||||
|
||||
// Start by checking that only basic ASCII characters are in the strings (0-127).
|
||||
|
||||
for (i=0; i<user.length; i++) {
|
||||
if (user.charCodeAt(i)>127) {
|
||||
alert("Ths username contains invalid characters.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (i=0; i<domain.length; i++) {
|
||||
if (domain.charCodeAt(i)>127) {
|
||||
alert("Ths domain name contains invalid characters.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// See if "user" is valid
|
||||
|
||||
if (user.match(userPat)==null) {
|
||||
|
||||
// user is not valid
|
||||
|
||||
alert("The username doesn't seem to be valid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* if the e-mail address is at an IP address (as opposed to a symbolic
|
||||
host name) make sure the IP address is valid. */
|
||||
|
||||
var IPArray=domain.match(ipDomainPat);
|
||||
if (IPArray!=null) {
|
||||
|
||||
// this is an IP address
|
||||
|
||||
for (var i=1;i<=4;i++) {
|
||||
if (IPArray[i]>255) {
|
||||
alert("Destination IP address is invalid!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Domain is symbolic name. Check if it's valid.
|
||||
|
||||
var atomPat=new RegExp("^" + atom + "$");
|
||||
var domArr=domain.split(".");
|
||||
var len=domArr.length;
|
||||
for (i=0;i<len;i++) {
|
||||
if (domArr[i].search(atomPat)==-1) {
|
||||
alert("The domain name does not seem to be valid.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* domain name seems valid, but now make sure that it ends in a
|
||||
known top-level domain (like com, edu, gov) or a two-letter word,
|
||||
representing country (uk, nl), and that there's a hostname preceding
|
||||
the domain or country. */
|
||||
|
||||
if (checkTLD && domArr[domArr.length-1].length!=2 &&
|
||||
domArr[domArr.length-1].search(knownDomsPat)==-1) {
|
||||
alert("The address must end in a well-known domain or two letter " + "country.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure there's a host name preceding the domain.
|
||||
|
||||
if (len<2) {
|
||||
alert("This address is missing a hostname!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we've gotten this far, everything's valid!
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
function fillIn(dom, a) {
|
||||
_.each(a, function (v, k) {
|
||||
if (dom[k]) {
|
||||
dom[k].value = v;
|
||||
dom[k].value = v || '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -60,7 +60,8 @@
|
|||
calculateSummary: function () {
|
||||
var e = this.elements,
|
||||
prices = this.prices,
|
||||
shipping = prices.shipping[e.shipper.value],
|
||||
shipper = e.shipper,
|
||||
shipping = shipper && prices.shipping[shipper.value],
|
||||
shipPrice = (shipping ?
|
||||
(shipping.hasPrice ?
|
||||
parseFloat(shipping.price) :
|
||||
|
|
@ -138,7 +139,7 @@
|
|||
return function () {
|
||||
var address = {},
|
||||
label = e.label.value,
|
||||
copy = o && o.label.value === label,
|
||||
copy = o.label && o.label.value === label,
|
||||
cache = c[label],
|
||||
dirty;
|
||||
|
||||
|
|
@ -147,7 +148,7 @@
|
|||
}
|
||||
|
||||
_.each(e, function (v, k) {
|
||||
v = v.value;
|
||||
v = v.value || '';
|
||||
address[k] = v;
|
||||
if (cache[k] !== v) {
|
||||
dirty = true;
|
||||
|
|
@ -306,7 +307,7 @@
|
|||
|
||||
if (!opt) {
|
||||
opt = document.createElement('option');
|
||||
opt.text = label;
|
||||
opt.innerHTML = label;
|
||||
dropdown.appendChild(opt);
|
||||
}
|
||||
|
||||
|
|
@ -314,14 +315,16 @@
|
|||
}
|
||||
|
||||
updateOne(d.billing);
|
||||
updateOne(d.shipping);
|
||||
if (d.shipping) {
|
||||
updateOne(d.shipping);
|
||||
if (name === 'billing' && self.sameShipping()) {
|
||||
self.copyBilling();
|
||||
}
|
||||
else {
|
||||
self.computePerItemShippingOptions();
|
||||
}
|
||||
}
|
||||
d[name].value = id;
|
||||
if (name === 'billing' && self.sameShipping()) {
|
||||
self.copyBilling();
|
||||
}
|
||||
else {
|
||||
self.computePerItemShippingOptions();
|
||||
}
|
||||
self.updateSummary();
|
||||
});
|
||||
},
|
||||
|
|
@ -335,10 +338,9 @@
|
|||
e = this.elements,
|
||||
tax = e.tax,
|
||||
shipper = e.shipper,
|
||||
selected = shipper.value,
|
||||
d = e.dropdowns,
|
||||
shipping = d.shipping.value,
|
||||
billing = d.billing.value,
|
||||
selected, shipping,
|
||||
params = {
|
||||
shop: 'cart',
|
||||
method: 'ajaxPrices'
|
||||
|
|
@ -348,10 +350,14 @@
|
|||
params.billingId = billing;
|
||||
}
|
||||
|
||||
if (this.sameShipping()) {
|
||||
params.shippingId = params.billingId;
|
||||
} else if (addressIdCounts(shipping)) {
|
||||
params.shippingId = shipping;
|
||||
if (shipper) {
|
||||
selected = shipper.value; // save so we can restore later
|
||||
shipping = d.shipping.value;
|
||||
if (this.sameShipping()) {
|
||||
params.shippingId = params.billingId;
|
||||
} else if (addressIdCounts(shipping)) {
|
||||
params.shippingId = shipping;
|
||||
}
|
||||
}
|
||||
|
||||
this.request('GET', params, function (o) {
|
||||
|
|
@ -360,30 +366,32 @@
|
|||
if (response.error) {
|
||||
return;
|
||||
}
|
||||
if (shipper) {
|
||||
// We need to repopulate the shipper options dropdown
|
||||
// (but only if we have a shipper at all)
|
||||
_(shipper.options).chain().select(function (o) {
|
||||
return o.value;
|
||||
}).each(function (o) {
|
||||
o.parentNode.removeChild(o);
|
||||
});
|
||||
|
||||
_.each(response.shipping, function (o, id) {
|
||||
var opt = document.createElement('option'),
|
||||
label = o.label;
|
||||
|
||||
if (o.hasPrice) {
|
||||
label += ' (' + formatCurrency(o.price) + ')';
|
||||
}
|
||||
|
||||
opt.innerHTML = label;
|
||||
opt.value = id;
|
||||
shipper.appendChild(opt);
|
||||
});
|
||||
|
||||
shipper.value = selected;
|
||||
}
|
||||
self.prices = response;
|
||||
tax.innerHTML = formatCurrency(response.tax);
|
||||
|
||||
_(shipper.options).chain().select(function (o) {
|
||||
return o.value;
|
||||
}).each(function (o) {
|
||||
o.parentNode.removeChild(o);
|
||||
});
|
||||
|
||||
_.each(response.shipping, function (o, id) {
|
||||
var opt = document.createElement('option'),
|
||||
label = o.label;
|
||||
|
||||
if (o.hasPrice) {
|
||||
label += ' (' + formatCurrency(o.price) + ')';
|
||||
}
|
||||
|
||||
opt.innerHTML = label;
|
||||
opt.value = id;
|
||||
shipper.appendChild(opt);
|
||||
});
|
||||
|
||||
shipper.value = selected;
|
||||
self.calculateSummary();
|
||||
});
|
||||
},
|
||||
|
|
@ -405,7 +413,8 @@
|
|||
},
|
||||
|
||||
sameShipping: function () {
|
||||
return this.elements.same.checked;
|
||||
var same = this.elements.same;
|
||||
return same && same.checked;
|
||||
},
|
||||
|
||||
setCartItemShippingId: function (select) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue