Merge commit 'v7.10.15' into 8

Conflicts:
	docs/gotcha.txt
	docs/previousVersion.sql
	docs/templates.txt
	lib/WebGUI.pm
	lib/WebGUI/Asset.pm
	lib/WebGUI/Asset/Event.pm
	lib/WebGUI/Asset/File.pm
	lib/WebGUI/Asset/MapPoint.pm
	lib/WebGUI/Asset/RichEdit.pm
	lib/WebGUI/Asset/Sku/Product.pm
	lib/WebGUI/Asset/Snippet.pm
	lib/WebGUI/Asset/Story.pm
	lib/WebGUI/Asset/Template.pm
	lib/WebGUI/Asset/Template/TemplateToolkit.pm
	lib/WebGUI/Asset/Wobject/Calendar.pm
	lib/WebGUI/Asset/Wobject/Carousel.pm
	lib/WebGUI/Asset/Wobject/Collaboration.pm
	lib/WebGUI/Asset/Wobject/Dashboard.pm
	lib/WebGUI/Asset/Wobject/DataForm.pm
	lib/WebGUI/Asset/Wobject/Folder.pm
	lib/WebGUI/Asset/Wobject/Map.pm
	lib/WebGUI/Asset/Wobject/Search.pm
	lib/WebGUI/Asset/Wobject/Shelf.pm
	lib/WebGUI/Asset/Wobject/StockData.pm
	lib/WebGUI/Asset/Wobject/StoryTopic.pm
	lib/WebGUI/Asset/Wobject/SyndicatedContent.pm
	lib/WebGUI/Asset/Wobject/Thingy.pm
	lib/WebGUI/Asset/Wobject/WeatherData.pm
	lib/WebGUI/AssetClipboard.pm
	lib/WebGUI/AssetCollateral/DataForm/Entry.pm
	lib/WebGUI/AssetExportHtml.pm
	lib/WebGUI/AssetLineage.pm
	lib/WebGUI/AssetMetaData.pm
	lib/WebGUI/AssetTrash.pm
	lib/WebGUI/AssetVersioning.pm
	lib/WebGUI/Auth.pm
	lib/WebGUI/Cache/CHI.pm
	lib/WebGUI/Content/AssetManager.pm
	lib/WebGUI/Fork/ProgressBar.pm
	lib/WebGUI/Form/JsonTable.pm
	lib/WebGUI/Form/TimeField.pm
	lib/WebGUI/Form/Zipcode.pm
	lib/WebGUI/Group.pm
	lib/WebGUI/International.pm
	lib/WebGUI/Macro/AssetProxy.pm
	lib/WebGUI/Macro/FileUrl.pm
	lib/WebGUI/Operation/SSO.pm
	lib/WebGUI/Operation/User.pm
	lib/WebGUI/Role/Asset/Subscribable.pm
	lib/WebGUI/Shop/Cart.pm
	lib/WebGUI/Shop/Transaction.pm
	lib/WebGUI/Shop/TransactionItem.pm
	lib/WebGUI/Test.pm
	lib/WebGUI/URL/Content.pm
	lib/WebGUI/URL/Uploads.pm
	lib/WebGUI/User.pm
	lib/WebGUI/Workflow/Activity/ExtendCalendarRecurrences.pm
	lib/WebGUI/Workflow/Activity/SendNewsletters.pm
	lib/WebGUI/i18n/English/Asset.pm
	lib/WebGUI/i18n/English/WebGUI.pm
	sbin/installClass.pl
	sbin/rebuildLineage.pl
	sbin/search.pl
	sbin/testEnvironment.pl
	t/Asset/Asset.t
	t/Asset/AssetClipboard.t
	t/Asset/AssetLineage.t
	t/Asset/AssetMetaData.t
	t/Asset/Event.t
	t/Asset/File.t
	t/Asset/File/Image.t
	t/Asset/Post/notification.t
	t/Asset/Sku.t
	t/Asset/Story.t
	t/Asset/Template.t
	t/Asset/Wobject/Collaboration/templateVariables.t
	t/Asset/Wobject/Collaboration/unarchiveAll.t
	t/Asset/Wobject/Shelf.t
	t/Auth.t
	t/Macro/EditableToggle.t
	t/Macro/FilePump.t
	t/Shop/Cart.t
	t/Shop/Transaction.t
	t/Storage.t
	t/User.t
	t/Workflow.t
This commit is contained in:
Doug Bell 2011-05-13 18:15:11 -05:00
commit 277faae8a1
783 changed files with 32041 additions and 25495 deletions

View file

@ -17,6 +17,7 @@ use Moose;
use Tie::IxHash;
use WebGUI::Definition::Asset;
extends 'WebGUI::Asset::Wobject';
with 'WebGUI::Role::Asset::JSONCollateral';
define assetName => ['assetName', 'Asset_Calendar'];
define icon => 'calendar.gif';
@ -260,7 +261,7 @@ property icalFeeds => (
label => ['Feed URL','Asset_Calendar'],
},
{
name => 'status',
name => 'lastResult',
type => 'readonly',
label => ['434','WebGUI'],
},
@ -303,6 +304,7 @@ use WebGUI::Search;
use WebGUI::Form;
use WebGUI::HTML;
use WebGUI::DateTime;
use WebGUI::ICal;
use DateTime;
use JSON;
@ -348,10 +350,6 @@ The date this feed was added, or edited last.
The results of what happened the last time this feed was accessed to pull iCal.
=head4 feedType
What kind of feed this is.
=cut
sub addFeed {
@ -860,6 +858,17 @@ override processEditForm => sub {
$self->createSubscriptionGroup();
}
my @feeds = @{ $self->getFeeds };
foreach my $feed (@feeds) {
if ($feed->{lastUpdated} eq 'new') {
$feed->{lastUpdated} = 'never';
}
if ($feed->{lastResult} eq 'new') {
$feed->{lastResult} = '';
}
$self->setFeed($feed->{feedId}, $feed);
}
return;
};
@ -1706,97 +1715,20 @@ sub www_ical {
$dt_end = $dt_start->clone->add( seconds => $self->icalInterval );
}
my $ical = WebGUI::ICal->new();
# Get all the events we're going to display
my @events = $self->getEventsIn($dt_start->toMysql,$dt_end->toMysql);
my $ical = qq{BEGIN:VCALENDAR\r\n}
. qq{PRODID:WebGUI }.$WebGUI::VERSION."-".$WebGUI::STATUS.qq{\r\n}
. qq{VERSION:2.0\r\n};
# VEVENT:
EVENT: for my $event (@events) {
next EVENT unless $event->canView();
$ical .= qq{BEGIN:VEVENT\r\n};
### UID
# Use feed's UID to prevent over-propagation
if ($event->feedUid) {
$ical .= qq{UID:}.$event->feedUid."\r\n";
}
# Create a UID for feeds native to this calendar
else {
my $domain = $session->config->get("sitename")->[0];
$ical .= qq{UID:}.$event->assetId.'@'.$domain."\r\n";
}
# LAST-MODIFIED (revisionDate)
$ical .= qq{LAST-MODIFIED:}
. WebGUI::DateTime->new($self->session, $event->revisionDate)->toIcal
. "\r\n";
# CREATED (creationDate)
$ical .= qq{CREATED:}
. WebGUI::DateTime->new($self->session, $event->creationDate)->toIcal
. "\r\n";
# SEQUENCE
my $sequenceNumber = $event->iCalSequenceNumber;
if (defined $sequenceNumber) {
$ical .= qq{SEQUENCE:}
. $event->iCalSequenceNumber
. "\r\n";
}
# DTSTART
my $eventStart = $event->getIcalStart;
$ical .= 'DTSTART';
if ($eventStart !~ /T/) {
$ical .= ';VALUE=DATE';
}
$ical .= ":$eventStart\r\n";
# DTEND
my $eventEnd = $event->getIcalEnd;
$ical .= 'DTEND';
if ($eventEnd !~ /T/) {
$ical .= ';VALUE=DATE';
}
$ical .= ":$eventEnd\r\n";
# Summary (the title)
# Wrapped at 75 columns
$ical .= $self->wrapIcal("SUMMARY:".$event->title)."\r\n";
# Description (the text)
# Wrapped at 75 columns
$ical .= $self->wrapIcal("DESCRIPTION:".$event->description)."\r\n";
# Location (the text)
# Wrapped at 75 columns
$ical .= $self->wrapIcal("LOCATION:".$event->location)."\r\n";
# X-WEBGUI lines
if ($event->groupIdView) {
$ical .= "X-WEBGUI-GROUPIDVIEW:".$event->groupIdView."\r\n";
}
if ($event->get("groupIdEdit")) {
$ical .= "X-WEBGUI-GROUPIDEDIT:".$event->groupIdEdit."\r\n";
}
$ical .= "X-WEBGUI-URL:".$event->get("url")."\r\n";
$ical .= "X-WEBGUI-MENUTITLE:".$event->menuTitle."\r\n";
$ical .= qq{END:VEVENT\r\n};
$event->add_to_calendar($ical);
}
# ENDVEVENT
$ical .= qq{END:VCALENDAR\r\n};
# Set mime of text/icalendar
$self->session->response->header( 'Content-Disposition' => qq{attachment; filename="feed.ics"});
$self->session->response->content_type("text/calendar");
return $ical;
#$self->session->http->setMimeType("text/plain");
$self->session->http->setFilename("feed.ics","text/calendar");
return $ical->as_string;
}
#----------------------------------------------------------------------------

View file

@ -48,6 +48,20 @@ property items => (
noFormPost => 1,
fieldType => 'text',
);
property autoPlay => (
fieldType => 'yesNo',
defaultValue => 0,
tab => "properties",
hoverHelp => ['carousel autoPlay description', 'Asset_Carousel' ],
label => ['carousel autoPlay label', 'Asset_Carousel' ],
);
property autoPlayInterval => (
fieldType => 'Integer',
defaultValue => 4,
tab => 'properties',
hoverHelp => ['carousel autoPlayInterval description', 'Asset_Carousel'],
label => ['carousel autoPlayInterval label', 'Asset_Carousel'],
);
#-------------------------------------------------------------------
@ -63,16 +77,30 @@ override getEditForm => sub {
my $tabform = super();
my $i18n = WebGUI::International->new($self->session, "Asset_Carousel");
$self->session->style->setScript($self->session->url->extras('yui/build/editor/editor-min.js'));
$self->session->style->setCss($self->session->url->extras('yui/build/editor/assets/skins/sam/editor.css'));
$self->session->style->setScript($self->session->url->extras('wobject/Carousel/carousel.js'));
$self->session->style->setScript($self->session->url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type =>
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/element/element-min.js'), {type =>
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/tabview/tabview-min.js'), {type =>
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/editor/editor-min.js'), {type =>
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/json/json-min.js'), {type =>
'text/javascript'});
$self->session->style->setLink($self->session->url->extras('yui/build/editor/assets/skins/sam/editor.css'), {type
=>'text/css', rel=>'stylesheet'});
$self->session->style->setLink($self->session->url->extras('yui/build/tabview/assets/skins/sam/tabview.css'), {type
=>'text/css', rel=>'stylesheet'});
$self->session->style->setScript($self->session->url->extras('wobject/Carousel/carousel.js'), {type =>
'text/javascript'});
my $tableRowStart =
'<tr id="items_row">'
.' <td class="formDescription" valign="top" style="width: 180px;"><label for="item1">'
.$i18n->get("items label").'</label><div class="wg-hoverhelp">'.$i18n->get("items description").'</div></td>'
.' <td id="items_td" valign="top" class="tableData">'
.' <input type="button" value="Add item" onClick="javascript:addItem()"></input><br />'
.' <input type="hidden" id="items_formId" name="items" />'
.' <input type="button" value="Add item" onclick="window.carouselEditor.addTab()"></input><br />'
." <br />\n";
$tabform->getTab("properties")->addField('ReadOnly', value => $tableRowStart);
@ -122,6 +150,27 @@ onClick='javascript:deleteItem(this.id)'></input>\n"
."</script>\n";
$tabform->getTab("properties")->addField('ReadOnly', value => $itemHTML);
}
$self->session->log->warn('richedit:' .$self->get('richEditor'));
my $richEditId = $self->get('richEditor') || "PBrichedit000000000001";
my $richedit = WebGUI::Asset->newById( $self->session, $richEditId );
my $config = JSON->new->encode( $richedit->getConfig );
my $loadMcePlugins = $richedit->getLoadPlugins;
my $items = $self->get('items') ? JSON->new->decode($self->get('items'))->{items} : [];
$items = JSON->new->encode( $items );
my $i18nJson = JSON->new->encode( { "delete" => $i18n->get("delete") } );
$tabform->getTab('properties')->raw(<<"ENDHTML");
<div id="carouselEditor"></div>
<script type="text/javascript">
$loadMcePlugins
YAHOO.util.Event.onDOMReady( function() {
window.carouselEditor = new WebGUI.Carousel.Editor( "carouselEditor", $config, $items, $i18nJson );
} );
</script>
ENDHTML
my $tableRowEnd = qq|
</td>
</tr>
@ -165,32 +214,9 @@ Used to process properties from the form posted.
override processEditForm => sub {
my $self = shift;
my $form = $self->session->form;
my (@items,$items);
super();
foreach my $param ($form->param) {
if ($param =~ m/^item_/){
my $sequenceNumber = $param;
$sequenceNumber =~ s/^item_//;
if($form->process('itemId_'.$sequenceNumber)){
push(@items,{
sequenceNumber => $sequenceNumber,
text => $form->process($param),
itemId => $form->process('itemId_'.$sequenceNumber),
});
}
}
}
my @sortedItems = sort { $a->{sequenceNumber} cmp $b->{sequenceNumber} } @items;
@items = ();
for (my $i=0; $i<scalar @sortedItems; $i++) {
$sortedItems[$i]->{sequenceNumber} = $i + 1;
push(@items,$sortedItems[$i]);
}
$items = JSON->new->encode({items => \@items});
$self->update({items => $items});
my $items = JSON->new->decode( $form->get("items") );
$self->update({ items => JSON->new->encode({ items => $items }) });
return undef;
};

View file

@ -879,19 +879,19 @@ override commit => sub {
unless (defined $cron) {
$cron = WebGUI::Workflow::Cron->create($self->session, {
title=>$self->getTitle." ".$i18n->get("mail"),
minuteOfHour=>"*/".($self->getMailInterval/60),
className=>(ref $self),
methodName=>"new",
parameters=>$self->getId,
workflowId=>"csworkflow000000000001"
workflowId=>"csworkflow000000000001",
$self->getCronIntervals,
});
$self->update({getMailCronId=>$cron->getId});
}
if ($self->getMail) {
$cron->set({enabled=>1,title=>$self->getTitle." ".$i18n->get("mail"), minuteOfHour=>"*/".($self->getMailInterval/60)});
} else {
$cron->set({enabled=>0,title=>$self->getTitle." ".$i18n->get("mail"), minuteOfHour=>"*/".($self->getMailInterval/60)});
}
$cron->set({
enabled => $self->get('getMail') ? 1 : 0,
title => $self->getTitle." ".$i18n->get("mail"),
$self->getCronIntervals(),
});
};
#-------------------------------------------------------------------
@ -931,11 +931,11 @@ sub duplicate {
my $i18n = WebGUI::International->new($self->session, "Asset_Collaboration");
my $newCron = WebGUI::Workflow::Cron->create($self->session, {
title=>$self->getTitle." ".$i18n->get("mail"),
minuteOfHour=>"*/".($self->get("getMailInterval")/60),
className=>(ref $self),
methodName=>"new",
parameters=>$self->getId,
workflowId=>"csworkflow000000000001"
workflowId=>"csworkflow000000000001",
$self->getCronIntervals(),
});
$newAsset->update({getMailCronId=>$newCron->getId});
$newAsset->incrementReplies('','');
@ -959,6 +959,87 @@ sub duplicateBranch {
#----------------------------------------------------------------------------
=head2 getCronIntervals
Translate the settings for getCsMailInterval into options for Spectre's Cron,
minuteOfHour, hourOfDay and so on.
Returns a hash of those options that can be folded into a hash of property settings for the
Cron job.
=cut
sub getCronIntervals {
my $self = shift;
my $interval = $self->get('getMailInterval');
##My kingdom for a switch statement!
if ($interval eq 'every minute') {
return(
hourOfDay => '*',
minuteOfHour => '*/1',
);
}
elsif ($interval eq 'every other minute') {
return(
hourOfDay => '*',
minuteOfHour => '*/2',
);
}
elsif ($interval eq 'every 5 minutes') {
return(
hourOfDay => '*',
minuteOfHour => '*/5',
);
}
elsif ($interval eq 'every 10 minutes') {
return(
hourOfDay => '*',
minuteOfHour => '*/10',
);
}
elsif ($interval eq 'every 15 minutes') {
return(
hourOfDay => '*',
minuteOfHour => '*/15',
);
}
elsif ($interval eq 'every 20 minutes') {
return(
hourOfDay => '*',
minuteOfHour => '*/20',
);
}
elsif ($interval eq 'every 30 minutes') {
return(
hourOfDay => '*',
minuteOfHour => '*/30',
);
}
elsif ($interval eq 'every hour') {
return(
hourOfDay => '*',
minuteOfHour => '0',
);
}
elsif ($interval eq 'every other hour') {
return(
hourOfDay => '*/2',
minuteOfHour => '0',
);
}
elsif ($interval eq 'once per day') {
return(
hourOfDay => '7',
minuteOfHour => '0',
);
}
return(
minuteOfHour => '*/10',
);
}
#-------------------------------------------------------------------
=head2 getHelpers ( )
Add the collaboration-specific asset helpers
@ -1282,6 +1363,35 @@ sub getViewTemplateVars {
return \%var;
}
#--------------------------------------------------------------------------
=head2 groupIdView ( [newvalue] )
Override the existing accessor to update the subscription group if the value
changes.
=cut
around groupIdView => sub {
my $orig = shift;
my $self = shift;
my ( $newValue ) = @_;
my $oldValue = $self->$orig;
my $return = $self->$orig(@_);
# Update the subscription group so if they can't see the collab, they don't get e-mailed
if ( $newValue && $newValue != $oldValue ) {
my $instance_data = {
workflowId => 'xR-_GRRbjBojgLsFx3dEMA',
className => 'WebGUI::Asset',
methodName => 'newById',
parameters => $self->getId,
};
my $instance = WebGUI::Workflow::Instance->create($self->session, $instance_data);
$instance->start('skipRealtime');
}
return $return;
};
#-------------------------------------------------------------------
=head2 incrementReplies ( lastPostDate, lastPostId )
@ -1586,7 +1696,6 @@ sub unsubscribe {
$group->deleteUsers([$user->userId]);
}
#-------------------------------------------------------------------
=head2 view

View file

@ -320,13 +320,17 @@ override purge => sub {
=head2 view
Render the dashboard.
Render the dashboard. Of all the positions for content, position1 is reserved for hidden content
or content to be placed. Deleting content causes it to go into position1.
=cut
sub view {
my $self = shift;
my $self = shift;
my $session = $self->session;
my %vars = %{$self->get()};
$vars{canEdit} = $self->canEdit;
$vars{fullUrl} = $self->getUrl;
$self->session->style->setScript( $self->session->url->extras('yui/build/utilities/utilities.js'));
@ -356,60 +360,85 @@ sub view {
my @found;
my $newStuff;
my $showPerformance = $self->session->log->performanceLogger();
my $user = $self->session->user;
foreach my $position (@positions) {
my @assets = split(",",$position);
foreach my $asset (@assets) {
foreach my $child (@{$children}) {
CHILD: foreach my $child (@{$children}) {
if ($asset eq $child->getId) {
unless ($asset ~~ @hidden || !$child->canView) {
$self->session->style->setRawHeadTags($child->getExtraHeadTags);
$child->{_properties}{title} = $child->getTitle;
$child->{_properties}{title} = $child->getShortcut->getTitle if (ref $child eq 'WebGUI::Asset::Shortcut');
if ($i == 1 || $i > $numPositions) {
push(@{$vars{"position1_loop"}},{
id=>$child->getId,
content=>'', #so things in the New Content bar don't display.
dashletTitle=>$child->{_properties}{title},
shortcutUrl=>$child->getUrl,
canPersonalize=>$self->canPersonalize,
showReloadIcon=>$child->{_properties}{showReloadIcon},
canEditUserPrefs=>(($self->session->user->isRegistered) && (ref $child eq 'WebGUI::Asset::Shortcut') && (scalar($child->getPrefFieldsToShow) > 0))
});
$newStuff .= 'available_dashlets["'.$child->getId.'"]=\''.$child->getUrl.'\';';
} else {
$child->prepareView;
push(@{$vars{"position".$i."_loop"}},{
id=>$child->getId,
content=>$child->view,
dashletTitle=>$child->{_properties}{title},
shortcutUrl=>$child->getUrl,
canPersonalize=>$self->canPersonalize,
showReloadIcon=>$child->{_properties}{showReloadIcon},
canEditUserPrefs=>(($self->session->user->isRegistered) && (ref $child eq 'WebGUI::Asset::Shortcut') && (scalar($child->getPrefFieldsToShow) > 0))
});
$newStuff .= 'available_dashlets["'.$child->getId.'"]=\''.$child->getUrl.'\';';
}
}
push(@found, $child->getId);
}
##Filter based on visibility
next CHILD unless $child->canView;
next CHILD if isIn($asset, @hidden);
##Detect child types
my $is_shortcut = $child->isa('WebGUI::Asset::Shortcut');
my $is_dashlet = $child->can('getOverrideFormDefinition');
$self->session->style->setRawHeadTags($child->getExtraHeadTags);
##Override the title for shortcuts
if ($is_shortcut) {
$child->{_properties}{title} = $child->getShortcut->getTitle;
}
##Fetch dashlet options from the database
my $options = $session->db->quickHashRef('select * from Dashboard_dashlets where dashboardAssetId=? and dashletAssetId=?', [$self->getId, $child->getId]);
if (!($i == 1 || $i > $numPositions)) {
$child->prepareView;
}
my $spot = $i > $numPositions ? 1 : $i;
my $canMove = $self->canPersonalize && !$options->{isStatic};
my $editFormUrl = ($is_shortcut && $child->getPrefsFieldToShow) ? $child->getUrl('func=getUserPrefsForm')
: ($is_dashlet && $child->getOverrideFormDefinition) ? $self->getUrl('func=customizeDashlet;dashletAssetId='.$child->getId)
: ''
;
my $canEditUserPrefs = $user->isRegistered && $editFormUrl;
push(@{$vars{"position".$spot."_loop"}},{
id => $child->getId,
content => $child->view,
dashletTitle => $child->get('title'),
shortcutUrl => ($is_shortcut ? $child->getUrl : ''),
editFormUrl => $editFormUrl,
dashletUrl => ($is_dashlet ? $child->getUrl : ''),
canDelete => $self->canPersonalize && !$options->{isRequired},
canMove => $canMove,
canPersonalize => $self->canPersonalize,
showReloadIcon => $is_shortcut && $child->get('showReloadIcon'),
canEditUserPrefs => $canEditUserPrefs,
});
if ($canMove) {
$newStuff .= 'available_dashlets["'.$child->getId.'"]=\''.$child->getUrl.'\';';
}
}
}
}
$i++;
}
# deal with unplaced children
# deal with unplaced children, they go into position 1
foreach my $child (@{$children}) {
unless ($child->getId ~~ @found || $child->getId ~~ @hidden) {
if ($child->canView) {
$child->{_properties}{title} = $child->getShortcut->title if (ref $child eq 'WebGUI::Asset::Shortcut');
my $is_shortcut = $child->isa('WebGUI::Asset::Shortcut');
my $is_dashlet = $child->can('getOverrideFormDefinition');
my $title = $child->{_properties}{title} = $is_shortcut ? $child->getShortcut->getTitle : $child->getTitle;
my $options = $session->db->quickHashRef('select * from Dashboard_dashlets where dashboardAssetId=? and dashletAssetId=?', [$self->getId, $child->getId]);
my $canMove = $self->canPersonalize && !$options->{isStatic};
my $editFormUrl = ($is_shortcut && $child->getPrefFieldsToShow) ? $child->getUrl('func=getUserPrefsForm')
: ($is_dashlet && $child->getOverrideFormDefinition) ? $self->getUrl('func=customizeDashlet;dashletAssetId='.$child->getId)
: ''
;
my $canEditUserPrefs = $user->isRegistered && $editFormUrl;
push(@{$vars{"position1_loop"}},{
id=>$child->getId,
content=>'',
dashletTitle=>$child->getTitle,
shortcutUrl=>$child->getUrl,
showReloadIcon=>$child->{_properties}{showReloadIcon},
canPersonalize=>$self->canPersonalize,
canEditUserPrefs=>(($self->session->user->isRegistered) && (ref $child eq 'WebGUI::Asset::Shortcut') && (scalar($child->getPrefFieldsToShow) > 0))
id => $child->getId,
content => '',
dashletTitle => $title,
shortcutUrl => ($is_shortcut ? $child->getUrl : ''),
editFormUrl => $editFormUrl,
dashletUrl => ($is_dashlet ? $child->getUrl : ''),
canDelete => $self->canPersonalize && !$options->{isRequired},
canMove => $canMove,
canPersonalize => $self->canPersonalize,
showReloadIcon => $is_shortcut && $child->{_properties}{showReloadIcon},
canEditUserPrefs => $canEditUserPrefs,
});
$newStuff .= 'available_dashlets["'.$child->getId.'"]=\''.$child->getUrl.'\';';
}
@ -418,9 +447,9 @@ sub view {
$vars{showAdmin} = ($self->session->isAdminOn && $self->canEdit);
$vars{"dragger.init"} = '
<script type="text/javascript">
dragable_init("'.$self->getUrl.'");
var available_dashlets= new Array();
'.$newStuff.'
dragable_init("'.$self->getUrl.'");
</script>
';
return $self->processTemplate(\%vars, $templateId);
@ -428,6 +457,128 @@ sub view {
#-------------------------------------------------------------------
=head2 www_customizeDashlet
Web facing method for saving per dashlet configuration, such as being required, or movable.
=cut
sub www_customizeDashlet {
my $self = shift;
my $session = $self->session;
return $session->privilege->insufficient() unless ($session->user->isRegistered);
my $dashletAssetId = $session->form->get('dashletAssetId');
my $dashlet = WebGUI::Asset->newById($session, $dashletAssetId);
return $session->privilege->insufficient() unless ($dashlet && $dashlet->canView && $dashlet->can('getOverrideFormDefinition'));
my $i18n = WebGUI::International->new($session, 'Asset_Dashboard');
my $form = $session->form;
my $html_form = WebGUI::HTMLForm->new($session, action => $self->getUrl, method => 'POST', );
$html_form->hidden(name => 'func', value => 'customizeDashletSave', );
$html_form->hidden(name => 'dashletAssetId', value => $dashletAssetId, );
$html_form->readOnly(name => $i18n->get(), value => $dashlet->getTitle, );
my $overrides = $dashlet->fetchUserOverrides($self->getId);
my @dashlet_properties = $dashlet->getOverrideFormDefinition;
foreach my $property (@dashlet_properties) {
my %properties = %{ $property };
$properties{value} = $overrides->{$property->{name}} || $dashlet->get($property->{name});
$html_form->dynamicField(%properties);
}
$html_form->submit();
return $html_form->print;
}
#-------------------------------------------------------------------
=head2 www_customizeDashletSave
Web facing method for saving per dashlet configuration, such as being required, or movable.
=cut
sub www_customizeDashletSave {
my $self = shift;
my $session = $self->session;
return $session->privilege->insufficient() unless ($session->user->isRegistered);
my $dashletAssetId = $session->form->get('dashletAssetId');
my $dashlet = WebGUI::Asset->newById($session, $dashletAssetId);
return $session->privilege->insufficient() unless ($dashlet && $dashlet->canView && $dashlet->can('getOverrideFormDefinition'));
my $overrides = {};
my @dashlet_properties = $dashlet->getOverrideFormDefinition;
my $form = $session->form;
foreach my $property (@dashlet_properties) {
my $value = $form->process($property->{name}, $property->{fieldType}, $property->{value});
$overrides->{$property->{name}} = $value;
}
$dashlet->storeUserOverrides($self->getId, $overrides);
return $self->www_view;
}
##-------------------------------------------------------------------
=head2 www_editDashlet
Web facing method for saving per dashlet configuration, such as being required, or movable.
=cut
sub www_editDashlet {
my $self = shift;
my $session = $self->session;
return $session->privilege->insufficient() unless ($self->canEdit);
my $dashletAssetId = $session->form->get('dashletAssetId');
my $dashlet = WebGUI::Asset->newById($session, $dashletAssetId);
return $session->privilege->insufficient() unless ($dashletAssetId);
my $i18n = WebGUI::International->new($session, 'Asset_Dashboard');
my $form = $session->form;
my $html_form = WebGUI::HTMLForm->new($session, action => $self->getUrl, method => 'POST', );
$html_form->hidden(name => 'func', value => 'editDashletSave', );
$html_form->hidden(name => 'dashletAssetId', value => $dashletAssetId, );
$html_form->readOnly(name => $i18n->get(), value => $dashlet->getTitle, );
my $options = $session->db->quickHashRef('select * from Dashboard_dashlets where dashboardAssetId=? and dashletAssetId=?', [$self->getId, $dashletAssetId]);
$html_form->yesNo(
name => 'isStatic',
label => $i18n->get('Is static'),
hoverHelp => $i18n->get('Is static help'),
value => $form->get('isStatic') || $options->{isStatic},
);
$html_form->yesNo(
name => 'isRequired',
label => $i18n->get('Is required'),
hoverHelp => $i18n->get('Is required help'),
value => $form->get('isRequired') || $options->{isRequired},
);
$html_form->submit();
return $html_form->print;
}
#-------------------------------------------------------------------
=head2 www_editDashletSave
Web facing method for saving per dashlet configuration, such as being required, or movable.
=cut
sub www_editDashletSave {
my $self = shift;
my $session = $self->session;
return $session->privilege->insufficient() unless ($self->canEdit);
my $dashletAssetId = $session->form->get('dashletAssetId');
my $isStatic = $session->form->get('isStatic', 'yesNo');
my $isRequired = $session->form->get('isRequired', 'yesNo');
$session->db->write('DELETE FROM Dashboard_dashlets where dashboardAssetId=? and dashletAssetId=?',[$self->getId, $dashletAssetId, ]);
$session->db->write('INSERT INTO Dashboard_dashlets (dashboardAssetId, dashletAssetId, isStatic, isRequired) VALUES (?,?,?,?)', [$self->getId, $dashletAssetId, $isStatic, $isRequired, ]);
return $self->www_view;
}
#-------------------------------------------------------------------
=head2 www_setContentPositions
Web method for saving the positions of dashlets in the dashboard.

View file

@ -320,12 +320,13 @@ sub _fieldAdminIcons {
my $self = shift;
my $fieldName = shift;
my $i18n = WebGUI::International->new($self->session,"Asset_DataForm");
my $mode = ";mode=" . $self->currentView;
my $output;
$output = $self->session->icon->delete('func=deleteFieldConfirm;fieldName='.$fieldName,$self->url,$i18n->get(19))
$output = $self->session->icon->delete('func=deleteFieldConfirm;fieldName='.$fieldName.$mode,$self->get("url"),$i18n->get(19))
unless $self->getFieldConfig($fieldName)->{isMailField};
$output .= $self->session->icon->edit('func=editField;fieldName='.$fieldName,$self->url)
. $self->session->icon->moveUp('func=moveFieldUp;fieldName='.$fieldName,$self->url)
. $self->session->icon->moveDown('func=moveFieldDown;fieldName='.$fieldName,$self->url);
$output .= $self->session->icon->edit('func=editField;fieldName='.$fieldName.$mode,$self->get("url"))
. $self->session->icon->moveUp('func=moveFieldUp;fieldName='.$fieldName.$mode,$self->get("url"))
. $self->session->icon->moveDown('func=moveFieldDown;fieldName='.$fieldName.$mode,$self->get("url"));
return $output;
}
#-------------------------------------------------------------------
@ -784,6 +785,7 @@ sub getListTemplateVars {
'field.label' => $fieldConfig->{$_}{label},
'field.isMailField' => $fieldConfig->{$_}{isMailField},
'field.type' => $fieldConfig->{$_}{type},
"field.controls" => $self->_fieldAdminIcons($fieldConfig->{$_}{name}),
}
} @{ $self->getFieldOrder };
$var->{field_loop} = \@fieldLoop;

View file

@ -103,7 +103,7 @@ Overridden to check the revision dates of children as well
sub getContentLastModified {
my $self = shift;
my $mtime = $self->revisionDate;
my $mtime = $self->get("lastModified");
my $childIter = $self->getLineageIterator(["children"]);
while ( 1 ) {
my $child;
@ -119,6 +119,60 @@ sub getContentLastModified {
return $mtime;
}
#-------------------------------------------------------------------
=head2 getContentLastModifiedBy
Overridden to check the updated dates of children as well
=cut
sub getContentLastModifiedBy {
my $self = shift;
my $mtime = $self->SUPER::getContentLastModified;
my $userId = $self->get('revisedBy');
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;
if ($child_mtime > $mtime) {
$mtime = $child_mtime;
$userId = $child->get("revisedBy");
}
}
return $userId;
}
#-------------------------------------------------------------------
=head2 getEditForm ( )
Returns the TabForm object that will be used in generating the edit page for this asset.
=cut
sub getEditForm {
my $self = shift;
my $tabform = $self->SUPER::getEditForm();
my $i18n = WebGUI::International->new($self->session,"Asset_Folder");
if ($self->get("assetId") eq "new") {
$tabform->getTab("properties")->whatNext(
-options=>{
view=>$i18n->get(823),
"viewParent"=>$i18n->get(847)
},
-value=>"view"
);
}
return $tabform;
}
#----------------------------------------------------------------------------
=head2 getTemplateVars ( )

View file

@ -363,6 +363,36 @@ override getContentLastModified => sub {
#-------------------------------------------------------------------
=head2 getContentLastModifiedBy
Extend the base class to include the userid of the person that made last modification.
=cut
sub getContentLastModifiedBy {
my $self = shift;
my $mtime = $self->SUPER::getContentLastModified;
my $userId = $self->get('revisedBy');
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;
if ($child_mtime > $mtime) {
$mtime = $child_mtime;
$userId = $child->get("revisedBy");
}
}
return $userId;
}
#-------------------------------------------------------------------
=head2 www_view
Extend the base method to handle caching and ad rotation.

View file

@ -371,7 +371,9 @@ sub view {
google.setOnLoadCallback( function() {
var mapId = "%s";
var mapUrl = "%s";
var map = new GMap2( document.getElementById("map_" + mapId) );
var element = document.getElementById("map_" + mapId);
var map = new GMap2( element );
element.mapObject = map;
map.url = mapUrl;
map.assetId = mapId;
map.setCenter(new GLatLng(%s, %s), %s);
@ -379,6 +381,10 @@ sub view {
map.extrasUrl = "%s";
var markermanager = new MarkerManager(map, {trackMarkers: true});
map.markermanager = markermanager;
map.fancyClickHandler = null;
map.panOnClick = true;
map.clickToEdit = false;
ENDHTML
@ -392,9 +398,9 @@ ENDHTML
for my $pointId ( @{$pointIds} ) {
my $point = WebGUI::Asset->newById( $session, $pointId );
next unless $point;
$mapHtml .= sprintf ' points.push(%s);'."\n",
JSON->new->encode($point->getMapInfo),
;
my $buffer = JSON->new->encode( $point->getMapInfo );
$mapHtml .= sprintf ' points.push(%s);'."\n", $buffer;
push @{$var->{ mapPoints }}, $point->getTemplateVars;
}
@ -416,11 +422,11 @@ ENDHTML
}
# Script to control addPoint and setPoint buttons
$mapHtml .= <<'ENDHTML';
$mapHtml .= sprintf <<'ENDHTML', $self->getUrl;
if ( document.getElementById( "setCenter_" + mapId ) ) {
var button = document.getElementById( "setCenter_" + mapId );
GEvent.addDomListener( button, "click", function () {
WebGUI.Map.setCenter( map );
WebGUI.Map.setCenter( map, '%s' );
} );
}
if ( document.getElementById( "addPoint_" + mapId ) ) {

View file

@ -175,30 +175,31 @@ sub view {
);
my @results = ();
foreach my $data (@{$p->getPageData}) {
next unless (
ENTRY: foreach my $data (@{$p->getPageData}) {
next ENTRY unless (
$user->userId eq $data->{ownerUserId}
|| $user->isInGroup($data->{groupIdView})
|| $user->isInGroup($data->{groupIdEdit})
);
my $asset = WebGUI::Asset->newById($session, $data->{assetId});
if (defined $asset) {
my $properties = $asset->get;
if ($self->useContainers) {
$properties->{url} = $asset->isa('WebGUI::Asset::Post::Thread') ? $asset->getCSLinkUrl()
: $asset->getContainer->url;
}
#Add highlighting
$properties->{'title' } = $hl->highlight($properties->{title} || '');
$properties->{'title_nohighlight' } = $properties->{title};
my $synopsis = $data->{'synopsis'} || '';
WebGUI::Macro::process($self->session, \$synopsis);
$properties->{'synopsis' } = $hl->highlight($synopsis);
$properties->{'synopsis_nohighlight'} = $synopsis;
push(@results, $properties);
$var{results_found} = 1;
}
next ENTRY unless defined $asset;
my $properties = $asset->get;
##Overlay the asset properties with the original data to handle sub-entries for assets
$properties = { %{ $properties }, %{ $data} };
if ( $self->get("useContainers") && $asset->getContainer->canView ) {
$properties->{url} = $asset->isa('WebGUI::Asset::Post::Thread') ? $asset->getCSLinkUrl()
: $asset->getContainer->get("url");
}
#Add highlighting
$properties->{'title' } = $hl->highlight($properties->{title} || '');
$properties->{'title_nohighlight' } = $properties->{title};
my $synopsis = $properties->{'synopsis'} || '';
WebGUI::Macro::process($self->session, \$synopsis);
$properties->{'synopsis' } = $hl->highlight($synopsis);
$properties->{'synopsis_nohighlight'} = $synopsis;
push(@results, $properties);
$var{results_found} = 1;
}
$var{result_set} = \@results;

View file

@ -20,6 +20,7 @@ use Number::Format ();
use Moose;
use WebGUI::Definition::Asset;
extends 'WebGUI::Asset::Wobject';
with 'WebGUI::Role::Asset::Dashlet';
define tableName => 'StockData';
define icon => 'stockData.gif';
define assetName => ["assetName", 'Asset_StockData'];
@ -45,6 +46,7 @@ property defaultStocks => (
tab => 'properties',
label => ["default_stock_label", 'Asset_StockData'],
hoverHelp => ["default_stock_label_description", 'Asset_StockData'],
dashletOverridable => 1,
);
property source => (
fieldType => "selectList",
@ -208,9 +210,12 @@ sub _convertToEpoch {
if($time =~ m/pm/i) {
$hour += 12;
}
$hour ||= 0;
$hour = $self->_appendZero($hour);
$minute ||= 0;
$minute = $self->_appendZero($minute);
return $self->session->datetime->humanToEpoch("$year-$month-$day $hour:$minute:00");
my $epoch = eval {$self->session->datetime->humanToEpoch("$year-$month-$day $hour:$minute:00")};
return $epoch;
}
#-------------------------------------------------------------------
@ -226,21 +231,45 @@ List of stock symbols to find passed in as an array reference. Stock symbols sh
=cut
sub _getStocks {
my $self = shift;
my $stocks = $_[0];
my $self = shift;
my $stocks = $_[0];
my $session = $self->session;
# Create a new Finance::Quote object
my $q = Finance::Quote->new;
# Disable failover if specified
unless ($self->failover) {
$q->failover(0);
}
# Create a new Finance::Quote object
my $q = Finance::Quote->new;
# Disable failover if specified
unless ($self->failover) {
$q->failover(0);
}
# Hardcoded timeout for now.
$q->timeout(15);
# Hardcoded timeout for now.
$q->timeout(15);
my $source = $self->source;
my %stocks = ();
my @stocks_to_fetch = ();
STOCK: foreach my $stock (@{$stocks}) {
$stock = uc $stock;
my $value = $session->cache->get( join "", $self->getId, $source, $stock );
if ($value) {
%stocks = (%stocks, %{ $value });
}
else {
push @stocks_to_fetch, $stock;
}
}
# Fetch the stock information and return the results
return $q->fetch($self->source,@{$stocks});
# Fetch the information for uncached stocks, cache them individually, and build the composite data.
my %new_stocks = $q->fetch($source, @stocks_to_fetch);
foreach my $stock (@stocks_to_fetch) {
$stock = uc $stock;
my @stock_keys = grep { /$stock\b/ } keys %new_stocks;
my %slice;
@slice{ @stock_keys } = @new_stocks{ @stock_keys };
$slice{$stock,'last_fetch'} = time();
$session->cache->set( join( "", $self->getId, $source, $stock ), \%slice, $self->get('cacheTimeout') );
%stocks = (%stocks, %slice);
}
return \%stocks;
}
#-------------------------------------------------------------------
@ -330,7 +359,8 @@ sub view {
$var->{'stock.display.url'} = $self->getUrl("func=displayStock;symbol=");
#Build list of stocks as an array
my $defaults = $self->defaultStocks;
my $overrides = $self->fetchUserOverrides($self->getParent->getId);
my $defaults = $overrides->{defaultStocks} || $self->defaultStocks;
#replace any windows newlines
$defaults =~ s/\r//;
my @array = split("\n",$defaults);

View file

@ -171,38 +171,48 @@ sub viewTemplateVariables {
rowsPerPage => $numberOfStories,
});
my $storyIds = $p->getPageData();
$var->{story_loop} = [];
my $icon = $session->icon;
my $userUiLevel = $session->user->get("uiLevel");
my $uiLevels = $session->config->get('assetToolbarUiLevel');
my $i18n = WebGUI::International->new($session);
my $url = $session->url;
##Only build objects for the assets that we need
STORY: foreach my $storyId (@{ $storyIds }) {
my $story = WebGUI::Asset->newById($session, $storyId->{assetId}, $storyId->{revisionDate});
next STORY unless $story;
my $storyVars = {
url => ( $exporting
? $story->getUrl
: $session->url->append($self->getUrl, 'func=viewStory;assetId='.$storyId->{assetId}) ),
title => $story->getTitle,
creationDate => $story->creationDate,
};
if ($story->canEdit && $userUiLevel >= $uiLevels->{delete} && !$exporting) {
$storyVars->{deleteIcon} = $icon->delete('func=delete', $story->url, $i18n->get(43));
$var->{story_loop} = [
map {
my $v = $_->viewTemplateVariables;
if ($exporting) {
$v->{url} = $_->getUrl;
}
else {
my $params = "func=viewStory;assetId=$v->{assetId}";
my $rawUrl = $v->{url};
$v->{url} = $url->append($self->getUrl, $params);
if ($v->{canEdit}) {
if ($userUiLevel >= $uiLevels->{delete}) {
$v->{deleteIcon} = $icon->delete('func=delete', $rawUrl, $i18n->get(43));
}
if ($userUiLevel >= $uiLevels->{edit}) {
$v->{editIcon} = $icon->edit('func=edit', $rawUrl);
}
}
}
$v;
}
if ($story->canEdit && $userUiLevel >= $uiLevels->{edit} && !$exporting) {
$storyVars->{editIcon} = $icon->edit('func=edit', $story->url);
grep { $_ }
map {
WebGUI::Asset->newById( $session, $_->{assetId} )
}
push @{$var->{story_loop}}, $storyVars;
}
@{ $storyIds }
];
if (@{ $storyIds }) {
my $topStoryData = $storyIds->[0];
my $topStoryVars = shift @{ $var->{story_loop} };
##Note, this could have saved from the loop above, but this looks more clean and encapsulated to me.
my $topStory = WebGUI::Asset->newById($session, $topStoryData->{assetId}, $topStoryData->{revisionDate});
$var->{topStory} = $topStoryVars;
$var->{topStoryTitle} = $topStory->getTitle;
$var->{topStorySubtitle} = $topStory->subtitle;
$var->{topStoryUrl} = $session->url->append($self->getUrl, 'func=viewStory;assetId='.$topStoryData->{assetId}),

View file

@ -2336,12 +2336,12 @@ sub www_viewStatisticalOverview {
}
}
else{
my $responses = $db->read('select value,answerComment from Survey_tempReport'
my $responses = $db->read('select answerValue,answerComment from Survey_tempReport'
. ' where sectionNumber=? and questionNumber=?',
[$sectionIndex,$questionIndex]);
while (my $response = $responses->hashRef) {
push @answerloop,{
'answer_value' =>$response->{value},
'answer_value' =>$response->{answerValue},
'answer_comment' =>$response->{answerComment}
};
}

View file

@ -97,6 +97,7 @@ has '+uiLevel' => (
with 'WebGUI::Role::Asset::RssFeed';
use WebGUI::Macro;
use XML::FeedPP;
use XML::FeedPP::MediaRSS;
=head1 NAME
@ -252,6 +253,7 @@ A reference to an XML::FeedPP object.
sub getTemplateVariables {
my ($self, $feed) = @_;
my $media = XML::FeedPP::MediaRSS->new($feed);
my @items = $feed->get_item;
my %var;
$var{channel_title} = WebGUI::HTML::filter(scalar $feed->title, 'javascript');
@ -268,6 +270,7 @@ sub getTemplateVariables {
$var{channel_image_height} = WebGUI::HTML::filter($image[5], 'javascript');
foreach my $object (@items) {
my %item;
$item{media} = [ map { { %$_ } } $media->for_item($object) ];
$item{title} = WebGUI::HTML::filter(scalar $object->title, 'javascript');
$item{date} = WebGUI::HTML::filter(scalar $object->get_pubDate_epoch, 'javascript');
$item{category} = WebGUI::HTML::filter(scalar $object->category, 'javascript');

View file

@ -260,6 +260,24 @@ sub badOtherThing {
#-------------------------------------------------------------------
=head2 deleteThingIndex ( $thingId )
Remove the entry about this Thing from the database, and for any rows for it that are indexed as well.
=head3 $thingId
The GUID of the Thing, used to pick out this record in the database.
=cut
sub deleteThingIndex {
my $self = shift;
my $thingId = shift;
$self->session->db->write(q|delete from assetIndex where assetId=? and subId like CONCAT(?,'%')|,[$self->getId, $thingId]);
}
#-------------------------------------------------------------------
=head2 duplicate ( )
Duplicates a Thingy, including the definitions of the Things in this Thingy and their fields.
@ -346,6 +364,8 @@ sub duplicateThing {
$self->addField($field,0);
}
$thingProperties->{thingId} = $newThingId;
$self->indexThing($thingProperties);
return $newThingId;
}
@ -397,6 +417,7 @@ sub deleteField {
$db->write("ALTER TABLE ".$db->quote_identifier("Thingy_".$thingId)." DROP "
.$db->quote_identifier("field_".$fieldId));
}
$self->reindexThings;
$log->info("Deleted field: $fieldId in thing: $thingId.");
return undef;
}
@ -433,7 +454,7 @@ sub copyThingData {
my @storage_field_ids = ();
##Check to see if any of them are File or Image
foreach my $field (@{ $fields }) {
if ($field->{fieldType} eq 'File' or $field->{fieldType} eq 'Image') {
if ($self->field_isa($field->{fieldType}, 'WebGUI::Form::File')) {
push @storage_field_ids, $field->{fieldId};
}
}
@ -447,6 +468,7 @@ sub copyThingData {
}
##Update the copy
$self->setCollateral("Thingy_".$thingId, "thingDataId", $origCollateral, 0, 0);
$self->indexThingData($thingId, $origCollateral);
return undef;
}
@ -491,7 +513,7 @@ sub deleteThingData {
my @storage_field_ids = ();
##Check to see if any of them are File or Image
foreach my $field (@{ $fields }) {
if ($field->{fieldType} eq 'File' or $field->{fieldType} eq 'Image') {
if ($self->field_isa($field->{fieldType}, 'WebGUI::Form::File')) {
push @storage_field_ids, $field->{fieldId};
}
}
@ -501,11 +523,30 @@ sub deleteThingData {
$storage->delete;
}
$self->deleteThingDataIndex($thingDataId);
return undef;
}
#-------------------------------------------------------------------
=head2 deleteThingDataIndex ( $thingDataId )
Remove the entry about this Thing from the database, and for any rows for it that are indexed as well.
=head3 $thingDataId
The GUID of the thingData to remove, used to pick out this record in the database.
=cut
sub deleteThingDataIndex {
my $self = shift;
my $thingDataId = shift;
$self->session->db->write(q|delete from assetIndex where assetId=? and subId like CONCAT('%-',?)|,[$self->getId, $thingDataId]);
}
#-------------------------------------------------------------------
=head2 deleteThing ( thingId )
Deletes a Thing and its fields from Collateral and drops the things table.
@ -528,6 +569,7 @@ sub deleteThing {
$session->db->write("drop table if exists ".$session->db->quote_identifier("Thingy_".$thingId));
$log->info("Deleted thing: $thingId.");
$self->deleteThingIndex($thingId);
return undef;
}
@ -535,7 +577,9 @@ sub deleteThing {
=head2 editThingDataSave ( )
Saves a row of thing data and triggers the appropriate workflow triggers.
Saves a row of thing data and triggers the appropriate workflow triggers. Returns the id of the row created in
the database, and an array reference of errors from required fields and other sources. In there are errors, no data
is saved in the database, and the id returned in the empty string.
=head3 thingId
@ -579,8 +623,7 @@ sub editThingDataSave {
lastUpDated=>time(),
);
$fields = $session->db->read('select * from Thingy_fields where assetId = ? and thingId = ? order by sequenceNumber',
[$self->getId,$thingId]);
$fields = $self->getFields($thingId);
while (my $field = $fields->hashRef) {
my $fieldName = 'field_'.$field->{fieldId};
my $fieldValue;
@ -589,7 +632,7 @@ sub editThingDataSave {
$fieldType = "" if ($fieldType =~ m/^otherThing/x);
# Modify the defaultValue for certain field types. For most types we want to use
# the default in the database, for these we want the last known value for this thingData
if ( $fieldType eq "File" || $fieldType eq "Image" ) {
if ($self->field_isa($fieldType, 'WebGUI::Form::File')) {
$field->{ defaultValue } = $thingData{ "field_" . $field->{ fieldId } };
}
$fieldValue = $thingData->{$fieldName} || $session->form->process($fieldName,$fieldType,$field->{defaultValue},$field);
@ -598,7 +641,6 @@ sub editThingDataSave {
push (@errors,{
"error_message"=>$field->{label}." ".$i18n->get('is required error').".",
});
#$hadErrors = 1;
}
if ($field->{status} eq "hidden") {
$fieldValue = $field->{defaultValue};
@ -611,7 +653,11 @@ sub editThingDataSave {
$thingData{$fieldName} = $fieldValue;
}
if (@errors) {
return ('', \@errors);
}
$newThingDataId = $self->setCollateral("Thingy_".$thingId,"thingDataId",\%thingData,0,0);
$self->indexThingData($thingId, \%thingData);
# trigger workflow
if($thingDataId eq "new"){
@ -653,6 +699,33 @@ override exportAssetData => sub {
#-------------------------------------------------------------------
=head2 field_isa ( $fieldType, $isa )
Builds a form field and does an isa check on it.
=head2 $fieldType
This is the type of a field to build. It will have 'WebGUI::Form' prepended to it to form
a complete classname.
=head2 $isa
This is the class name to check against.
=cut
sub field_isa {
my $self = shift;
my $session = $self->session;
my $fieldType = shift;
my $isa = shift;
$fieldType = ucfirst $fieldType;
my $control = eval { WebGUI::Pluggable::instanciate("WebGUI::Form::".$fieldType, "new", [ $session, () ]) };
return ($control && $control->isa($isa));
}
#-------------------------------------------------------------------
=head2 _getDbDataType ( fieldType )
returns the database data type for a field based on the fieldType.
@ -905,6 +978,23 @@ sub getEditFieldForm {
#-------------------------------------------------------------------
=head2 getFields ( $thingId )
Returns a result set with all the fields in a thing in this Thingy.
=head3 $thingId
The GUID for a thing
=cut
sub getFields {
my ($self, $thingId) = @_;
return $self->session->db->read("select * from Thingy_fields where assetId=? and thingId=? order by sequenceNumber",[$self->getId, $thingId]);
}
#-------------------------------------------------------------------
=head2 getFieldValue ( value, field )
Processes the field value for date(Time) fields and Other Thing fields.
@ -1153,6 +1243,29 @@ sub getThing {
#-------------------------------------------------------------------
=head2 getThingUrl ( thingData )
Returns a the URL to view a Thing in this Thingy
=head3 thingData
A hashref of properties for the Thing, as returned by getThing. This is needed to extract the defaultView,
to get the right func, and the thingId.
=cut
sub getThingUrl {
my ($self, $thing) = @_;
if ($thing->{defaultView} eq "addThing") {
return 'func=editThingData;thingId='.$thing->{thingId}.';thingDataId=new';
}
else{
return 'func=search;thingId='.$thing->{thingId};
}
}
#-------------------------------------------------------------------
=head2 getViewThingVars ( )
Returns the field values of a thing instance and the title for its view screen in a tmpl var hashref.
@ -1171,8 +1284,7 @@ sub getViewThingVars {
." where thingDataId = ?",[$thingDataId]);
if (%thingData) {
my $fields = $db->read('select * from Thingy_fields where assetId = ? and thingId = ? order by sequenceNumber',
[$self->getId,$thingId]);
my $fields = $self->getFields($thingId);
while (my %field = $fields->hash) {
next unless ($field{display} eq '1');
my $hidden = ($field{status} eq "hidden" && !$self->session->isAdminOn);
@ -1207,6 +1319,7 @@ sub getViewThingVars {
);
push(@viewScreenTitleFields,$value) if ($field{viewScreenTitle});
push(@field_loop, { map {("field_".$_ => $fieldProperties{$_})} keys(%fieldProperties) });
$var->{ $field{label} } = $value;
}
$var->{viewScreenTitle} = join(" ",@viewScreenTitleFields);
$var->{field_loop} = \@field_loop;
@ -1314,7 +1427,7 @@ sub importAssetCollateralData {
push(@importThings,$thing->{thingId});
my ($thingIdExists) = $session->db->quickArray("select thingId from Thingy_things where thingId = ?",
[$thing->{thingId}]);
if ($assetExists && $thingIdExists){
if ($thingIdExists){
# update existing thing
$log->info("Updating Thing, label: ".$thing->{label}.", id: ".$thing->{thingId});
$self->setCollateral("Thingy_things","thingId",$thing,0,0);
@ -1323,6 +1436,7 @@ sub importAssetCollateralData {
# add new thing
$self->addThing($thing,1);
}
$self->indexThing($thing);
}
# delete deleted things
my $thingsInDatabase = $self->getThings;
@ -1338,7 +1452,7 @@ sub importAssetCollateralData {
push(@importFields,$field->{fieldId});
my $dbDataType = $self->_getDbDataType($field->{fieldType});
my ($fieldIdExists) = $session->db->quickArray("select fieldId from Thingy_fields where fieldId = ? and thingId = ? ",[$field->{fieldId},$field->{thingId}]);
if ($assetExists && $fieldIdExists){
if ($fieldIdExists){
# update existing field
$log->info("Updating Field, label: ".$field->{label}.", id: ".$field->{fieldId}.",seq :"
.$field->{sequenceNumber});
@ -1364,6 +1478,126 @@ sub importAssetCollateralData {
}
#-------------------------------------------------------------------
=head2 indexContent ( )
Extend the base class to handle reindexing every Thing, and every row in every Thing. We have
to do a complete rework because the URL may have changed, and that affects everything that has
been inserted into the AssetIndex.
=cut
sub indexContent {
my ($self) = @_;
my $session = $self->session;
$self->SUPER::indexContent();
$self->reindexThings;
}
#-------------------------------------------------------------------
=head2 indexThing ( $thing )
Add an entry about this Thing into the AssetIndex so it can be found for searches.
=head3 $thing
A hashref of Thing properties, as returned by getThing
=cut
sub indexThing {
my ($self, $thing) = @_;
return unless $thing;
my $index = WebGUI::Search::Index->new($self);
$index->addRecord(
url => $self->getUrl($self->getThingUrl($thing)),
groupIdView => $thing->{groupIdView},
title => $thing->{label},
subId => $thing->{thingId},
keywords => join(' ', @{$thing}{qw/label editScreenTitle editInstructions searchScreenTitle searchDescription/}),
);
##Easy update of all thingData fields for this thing. This is in lieu of deleting all records
##And rebuilding them all.
$self->session->db->write(q|update assetIndex set title=?, groupIdView=? where assetId=? and subId like CONCAT(?, '%')|, [$thing->{label}, $thing->{groupIdView}, $self->getId, $thing->{thingId}]);
}
#-------------------------------------------------------------------
=head2 indexThingData ( $thingId, $thingData )
Add an entry about a row from this Thing into the AssetIndex so it can be found for searches.
=head3 $thingId
The GUID for a Thing.
=head3 $thingData
A hashref of ThingData properties
=cut
sub indexThingData {
my ($self, $thingId, $thingData) = @_;
my $session = $self->session;
return unless $thingId;
my $thing = $self->getThing($thingId);
my $index = WebGUI::Search::Index->new($self);
my $keywords;
##Get the Thingy's fields
my $fields = $session->db->read('select * from Thingy_fields where assetId = ? and thingId = ?',
[$self->getId, $thingId]);
##Walk the fields
my @viewScreenTitleFields = ();
FIELD: while (my %field = $fields->hash) {
my $fieldName = 'field_'.$field{fieldId};
$field{value} = $thingData->{$fieldName} || $field{defaultValue};
my $subkeywords = '';
my $value = '';
if ($self->field_isa($field{fieldType}, 'WebGUI::Form::File')) {
my $storage = WebGUI::Storage->get($session, $field{value});
if ($storage) {
foreach my $file (@{$storage->getFiles()}) {
$subkeywords = $index->getKeywordsForFile($storage->getPath($file));
}
}
}
else {
$value = $self->getFieldValue($field{value}, \%field);
##If it's a file type, then get keywords from the file.
##Accumulate keywords
$subkeywords = $value;
}
if ($value && $field{viewScreenTitle}) {
push @viewScreenTitleFields, $value;
}
##We don't index date fields, since they're unix epochs and they'd be different for everyone based on timezone.
next FIELD if $field{fieldType} eq 'date'
|| $field{fieldType} eq 'datetime'
|| $field{fieldType} eq 'time';
##Don't show what shouldn't be shown
next FIELD unless $field{displayInSearch};
$keywords = join ' ', $keywords, $subkeywords;
}
return unless $keywords; ##No sense indexing nothing;
my $title = join('', @viewScreenTitleFields)
|| $thing->{label}
|| $self->getTitle;
$index->addRecord(
assetId => $self->getId,
url => $self->getUrl('func=viewThingData;thingId='. $thing->{thingId} . ';thingDataId='. $thingData->{thingDataId}),
groupIdView => $thing->{groupIdView},
title => $title,
subId => $thing->{thingId} . '-' . $thingData->{thingDataId},
keywords => $keywords,
);
}
#-------------------------------------------------------------------
=head2 prepareView ( )
@ -1412,6 +1646,30 @@ override purge => sub {
return super();
};
#-------------------------------------------------------------------
=head2 reindexThings ( )
Reindex every Thing, and every row in every Thing.
=cut
sub reindexThings {
my ($self) = @_;
my $session = $self->session;
my $things = $self->getThings;
THING: while (my $thing = $things->hashRef) {
$self->deleteThingIndex($thing->{thingId});
$self->indexThing($thing);
my $sth = $session->db->read('select * from '. $session->db->dbh->quote_identifier('Thingy_'.$thing->{thingId}));
while (my $thingData = $sth->hashRef) {
$self->indexThingData($thing->{thingId}, $thingData);
}
$sth->finish;
}
}
#-------------------------------------------------------------------
=head2 triggerWorkflow ( workflowId, thingId, thingDataId )
@ -1734,7 +1992,7 @@ sub www_editThing {
exportMetaData=>undef,
maxEntriesPerUser=>undef,
);
$thingId = $self->addThing(\%properties,0);
$thingId = "new";
}
else{
%properties = %{$self->getThing($thingId)};
@ -1834,15 +2092,15 @@ sub www_editThing {
." <td class='formDescription'>".$i18n->get('sort by label')."</td>\n"
."</tr>\n";
$fields = $self->session->db->read('select * from Thingy_fields where assetId = '.$self->session->db->quote($self->getId).' and thingId = '.$self->session->db->quote($thingId).' order by sequenceNumber');
$fields = $self->getFields($thingId);
while (my $field = $fields->hashRef) {
my $formElement;
if ($field->{fieldType} eq "File"){
$formElement = "<input type='file' name='file'>";
}
if ($field->{fieldType} eq "Image"){
if ($self->field_isa($field->{fieldType}, 'WebGUI::Form::Image')) {
$formElement = "<input type='file' name='image'>";
}
elsif ($self->field_isa($field->{fieldType}, 'WebGUI::Form::File')) {
$formElement = "<input type='file' name='file'>";
}
else{
$formElement = $self->getFormElement($field);
}
@ -1857,11 +2115,12 @@ sub www_editThing {
."\n<table>\n<tr>\n"
." <td style='width:100px;' valign='top' class='formDescription'>".$field->{label}."</td>\n"
." <td style='width:370px;'>".$formElement."</td>\n"
." <td style='width:120px;' valign='top'> <input onClick=\"editListItem('".$self->session->url->page()
."?func=editField;fieldId=".$field->{fieldId}.";thingId=".$thingId."','".$field->{fieldId}."')\" value='Edit' type='button'>"
." <input onClick=\"editListItem('".$self->session->url->page()
."?func=editField;copy=1;fieldId=".$field->{fieldId}.";thingId=".$thingId."','".$field->{fieldId}
."','copy')\" value='Copy' type='button'>"
." <td style='width:120px;' valign='top'> <input onClick=\"editListItem('"
.$self->getUrl('func=editField;fieldId='.$field->{fieldId}.';thingId='.$thingId)
."','".$field->{fieldId}."')\" value='".$i18n->get('Edit','Icon')."' type='button'>"
." <input onClick=\"editListItem('"
.$self->getUrl('func=editField;copy=1;fieldId='.$field->{fieldId}.';thingId='.$thingId)
."','".$field->{fieldId}."','copy')\" value='".$i18n->get('Copy','Icon')."' type='button'>"
."<input onClick=\"deleteListItem('".$self->session->url->page()."','".$field->{fieldId}."','".$thingId."')\" "
."value='".$i18n->get('Delete','Icon')."' type='button'></td>\n</tr>\n</table>\n</li>\n";
@ -2138,50 +2397,47 @@ database immediately.
=cut
sub www_editThingSave {
my $self = shift;
return $self->session->privilege->insufficient() unless $self->canEdit;
my $form = $self->session->form;
my ($thingId, $fields);
$thingId = $self->session->form->process("thingId");
my $form = $self->session->form;
my $thingId = $self->session->form->process("thingId");
my $fields = $self->getFields($thingId);
$fields = $self->session->db->read('select * from Thingy_fields where assetId = '.$self->session->db->quote($self->getId).' and thingId = '.$self->session->db->quote($thingId).' order by sequenceNumber');
$self->setCollateral("Thingy_things","thingId",{
thingId=>$thingId,
label=>$form->process("label"),
editScreenTitle=>$form->process("editScreenTitle"),
editInstructions=>$form->process("editInstructions"),
groupIdAdd=>$form->process("groupIdAdd"),
groupIdEdit=>$form->process("groupIdEdit"),
saveButtonLabel=>$form->process("saveButtonLabel"),
afterSave=>$form->process("afterSave"),
editTemplateId=>$form->process("editTemplateId") || 1,
onAddWorkflowId=>$form->process("onAddWorkflowId"),
onEditWorkflowId=>$form->process("onEditWorkflowId"),
onDeleteWorkflowId=>$form->process("onDeleteWorkflowId"),
groupIdView=>$form->process("groupIdView"),
viewTemplateId=>$form->process("viewTemplateId") || 1,
defaultView=>$form->process("defaultView"),
searchScreenTitle=>$form->process("searchScreenTitle"),
searchDescription=>$form->process("searchDescription"),
groupIdSearch=>$form->process("groupIdSearch"),
groupIdImport=>$form->process("groupIdImport"),
groupIdExport=>$form->process("groupIdExport"),
searchTemplateId=>$form->process("searchTemplateId") || 1,
thingsPerPage=>$form->process("thingsPerPage") || 25,
sortBy=>$form->process("sortBy") || '',
exportMetaData=>$form->process("exportMetaData") || '',
maxEntriesPerUser=>$form->process("maxEntriesPerUser") || '',
},0,1);
my $thing = {
thingId => $thingId,
label => $form->process("label"),
editScreenTitle => $form->process("editScreenTitle"),
editInstructions => $form->process("editInstructions"),
groupIdAdd => $form->process("groupIdAdd"),
groupIdEdit => $form->process("groupIdEdit"),
saveButtonLabel => $form->process("saveButtonLabel"),
afterSave => $form->process("afterSave"),
editTemplateId => $form->process("editTemplateId") || 1,
onAddWorkflowId => $form->process("onAddWorkflowId"),
onEditWorkflowId => $form->process("onEditWorkflowId"),
onDeleteWorkflowId => $form->process("onDeleteWorkflowId"),
groupIdView => $form->process("groupIdView"),
viewTemplateId => $form->process("viewTemplateId") || 1,
defaultView => $form->process("defaultView"),
searchScreenTitle => $form->process("searchScreenTitle"),
searchDescription => $form->process("searchDescription"),
groupIdSearch => $form->process("groupIdSearch"),
groupIdImport => $form->process("groupIdImport"),
groupIdExport => $form->process("groupIdExport"),
searchTemplateId => $form->process("searchTemplateId") || 1,
thingsPerPage => $form->process("thingsPerPage") || 25,
sortBy => $form->process("sortBy") || '',
exportMetaData => $form->process("exportMetaData") || '',
maxEntriesPerUser => $form->process("maxEntriesPerUser") || '',
};
$self->setCollateral("Thingy_things", "thingId", $thing, 0, 1);
if($fields->rows < 1){
$self->session->log->warn("Thing failed to create because it had no fields");
my $i18n = WebGUI::International->new($self->session, "Asset_Thingy");
return $self->www_editThing($i18n->get("thing must have fields"));
}
while (my $field = $fields->hashRef) {
my $display = $self->session->form->process("display_".$field->{fieldId}) || 0;
my $viewScreenTitle = $self->session->form->process("viewScreenTitle_".$field->{fieldId}) || 0;
@ -2190,6 +2446,7 @@ sub www_editThingSave {
$self->session->db->write("update Thingy_fields set display = ?, viewScreenTitle = ?, displayinSearch = ?, searchIn = ? where fieldId = ? and thingId = ?",[$display, $viewScreenTitle, $displayInSearch, $searchIn, $field->{fieldId}, $thingId]);
}
$self->indexThing($thing);
return $self->www_manage;
}
#-------------------------------------------------------------------
@ -2208,6 +2465,7 @@ sub www_editField {
return $session->privilege->insufficient() unless $self->canEdit;
$fieldId = $session->form->process("fieldId");
$thingId = $session->form->process("thingId");
%properties = $session->db->quickHash("select * from Thingy_fields where thingId=? and fieldId=? and assetId=?",
[$thingId,$fieldId,$self->getId]);
if($session->form->process("copy")){
@ -2248,6 +2506,8 @@ sub www_editFieldSave {
if ($fieldType =~ m/^otherThing/){
$defaultValue = $session->form->process("defaultFieldInThing");
}
$thingId = $self->addThing({ thingId => 'new' },0) if $thingId eq 'new';
$fieldId = $session->form->process("fieldId");
%properties = (
@ -2285,12 +2545,12 @@ sub www_editFieldSave {
$newFieldId = $self->setCollateral("Thingy_fields","fieldId",\%properties,1,1,"thingId",$thingId);
}
if ($properties{fieldType} eq "File"){
$formElement = "<input type='file' name='file'>";
}
elsif ($properties{fieldType} eq "Image"){
if ($self->field_isa($properties{fieldType}, 'WebGUI::Form::Image')) {
$formElement = "<input type='file' name='image'>";
}
elsif ($self->field_isa($properties{fieldType}, 'WebGUI::Form::File')) {
$formElement = "<input type='file' name='file'>";
}
else{
$formElement = $self->getFormElement(\%properties);
}
@ -2303,15 +2563,16 @@ sub www_editFieldSave {
$listItemHTML = "<table>\n<tr>\n<td style='width:100px;' valign='top' class='formDescription'>".$label."</td>\n"
."<td style='width:370px;'>".$formElement."</td>\n"
."<td style='width:120px;' valign='top'> <input onClick=\"editListItem('".$session->url->page()
."?func=editField;fieldId=".$newFieldId.";thingId=".$properties{thingId}."','".$newFieldId."')\" value='".$i18n->get('Edit','Icon')."' type='button'>"
."<td style='width:120px;' valign='top'> <input onClick=\"editListItem('"
.$self->getUrl('func=editField;fieldId='.$newFieldId.';thingId='.$properties{thingId})
."','".$newFieldId."')\" value='".$i18n->get('Edit','Icon')."' type='button'>"
."<input onClick=\"deleteListItem('".$session->url->page()."','".$newFieldId
."','".$properties{thingId}."')\" value='".$i18n->get('Delete','Icon')."' type='button'></td>\n</tr>\n</table>";
# Make sure we send debug information along with the field.
$log->preventDebugOutput;
$session->output->print($newFieldId.$listItemHTML);
$session->output->print($thingId.$newFieldId.$listItemHTML);
return "chunked";
}
@ -2493,8 +2754,7 @@ sub editThingData {
." where thingDataId = ?",[$thingDataId]);
}
$fields = $session->db->read('select * from Thingy_fields where assetId = ? and thingId = ? order by sequenceNumber'
,[$self->getId,$thingId]);
$fields = $self->getFields($thingId);
while (my %field = $fields->hash) {
my $fieldName = 'field_'.$field{fieldId};
$fieldValue = undef;
@ -2656,13 +2916,13 @@ sub www_editThingDataSaveViaAjax {
#-------------------------------------------------------------------
=head2 www_export ( )
=head2 www_exportThing ( )
Exports search results as csv.
Exports one entire Thing as CSV.
=cut
sub www_export {
sub www_exportThing {
my $self = shift;
my $session = $self->session;
my ($query,$sth,$out,$fields,@fields,$fileName,@fieldLabels);
@ -2676,30 +2936,29 @@ sub www_export {
$pb->start($i18n->get('export label').' '.$thingProperties->{label}, $session->url->extras('assets/thingy.gif'));
$pb->update($i18n->get('Creating column headers'));
my $tempStorage = WebGUI::Storage->createTemp($session);
$fields = $session->db->read('select * from Thingy_fields where assetId =? and thingId = ? order by sequenceNumber',
[$self->getId,$thingId]);
$fields = $self->getFields($thingId);
while (my $field = $fields->hashRef) {
if ($field->{displayInSearch}){
push(@fields, {
fieldId => $field->{fieldId},
properties => $field,
});
push(@fieldLabels,$field->{label});
}
push(@fields, {
fieldId => $field->{fieldId},
properties => $field,
});
push(@fieldLabels,$field->{label});
}
my @metaDataFields = ('thingDataId','dateCreated','createdById','updatedById','updatedByName','lastUpdated','ipAddress');
if ($thingProperties->{exportMetaData}){
push(@fieldLabels,@metaDataFields)
}
$query = $session->cache->get("query_".$thingId);
$query = 'select * from '.$session->db->dbh->quote_identifier("Thingy_".$thingId);
$sth = $session->db->read($query);
### Loop through the returned structure and put it through Text::CSV
# Column heads
$self->session->log->warn("field labels: ". join ' ', @fieldLabels);
my $csv_filename = 'export_'.$thingProperties->{label}.'.csv';
$tempStorage->addFileFromScalar($csv_filename, WebGUI::Text::joinCSV(@fieldLabels));
open my $CSV, '>', $tempStorage->getPath($csv_filename);
print $CSV WebGUI::Text::joinCSV( @fieldLabels );
# Data lines
$pb->update($i18n->get('Writing data'));
@ -2712,11 +2971,11 @@ sub www_export {
my $value = $self->getFieldValue($data->{"field_".$fieldId},$field->{properties},"%y-%m-%d","%y-%m-%d %j:%n:%s");
push(@fieldValues, $value);
}
if ($thingProperties->{exportMetaData}) {
foreach my $metaDataField (@metaDataFields){
push(@fieldValues,$data->{$metaDataField});
}
}
if ($thingProperties->{exportMetaData}) {
push(@fieldValues, @{$data}{@metaDataFields});
}
print $CSV "\n".WebGUI::Text::joinCSV( @fieldValues );
#if (! ++$rowCounter % 25) {
$pb->update($i18n->get('Writing data'));
@ -2724,7 +2983,7 @@ sub www_export {
}
close $CSV;
$pb->update(sprintf q|<a href="%s">%s</a>|, $self->getUrl, sprintf($i18n->get('Return to %s'), $thingProperties->{label}));
$pb->update(sprintf q|<a href="%s">%s</a>|, $self->getUrl($self->getThingUrl($thingProperties)), sprintf($i18n->get('Return to %s'), $thingProperties->{label}));
return $pb->finish($tempStorage->getUrl($csv_filename));
}
@ -2758,8 +3017,7 @@ sub www_getThingViaAjax {
$thingProperties->{groupIdView});
my @field_loop;
my $fields = $session->db->read('select * from Thingy_fields where assetId=? and thingId=? order by sequenceNumber'
,[$self->getId,$thingId]);
my $fields = $self->getFields($thingId);
while (my $field = $fields->hashRef) {
$field->{formElement} = $self->getFormElement($field);
push(@field_loop,$field);
@ -2992,8 +3250,7 @@ sub www_importForm {
." <td>".$i18n->get("check duplicates label")."</td>"
."</tr>";
$fields = $db->read('select label, fieldId from Thingy_fields where assetId =? and thingId = ? order by sequenceNumber',
[$self->getId,$thingId]);
$fields = $self->getFields($thingId);
while (my $field = $fields->hashRef) {
$fieldOptions .= "<tr><td>".$field->{label}."</td><td>";
$fieldOptions .= WebGUI::Form::Checkbox->new($self->session, {
@ -3059,13 +3316,7 @@ sub www_manage {
'thing_searchUrl' => $session->url->append($url, 'func=search;thingId='.$thing->{thingId}),
);
# set the url for the view icon to the things default view
my $viewParams;
if ($thing->{defaultView} eq "addThing") {
$viewParams = 'func=editThingData;thingId='.$thing->{thingId}.';thingDataId=new';
}
else{
$viewParams = 'func=search;thingId='.$thing->{thingId};
}
my $viewParams = $self->getThingUrl($thing);
$templateVars{'thing_viewIcon'} = $session->icon->view($viewParams);
push (@things_loop, \%templateVars);
}
@ -3240,13 +3491,12 @@ sub getSearchTemplateVars {
my $session = $self->session;
my $dbh = $session->db->dbh;
my $i18n = WebGUI::International->new($self->session,"Asset_Thingy");
my ($var,$url,$orderBy);
my ($fields,@searchFields_loop,@displayInSearchFields_loop,$query,@constraints);
my (@searchResult_loop,$searchResults,@searchResults,@displayInSearchFields,$paginatePage,$currentUrl,$p);
my (@searchResult_loop,$searchResults,@searchResults,@displayInSearchFields,$paginatePage,$p);
$orderBy = $session->form->process("orderBy") || $thingProperties->{sortBy};
$var = $self->get;
$url = $self->getUrl;
my $orderBy = $session->form->process("orderBy") || $thingProperties->{sortBy};
my $var = $self->get;
my $url = $self->getUrl;
$var->{canEditThings} = $self->canEdit;
$var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new');
@ -3254,7 +3504,7 @@ sub getSearchTemplateVars {
$var->{"thing_label"} = $thingProperties->{label};
if ($self->hasPrivileges($thingProperties->{groupIdExport})){
$var->{"export_url"} = $session->url->append($url, 'func=export;thingId='.$thingId);
$var->{"export_url"} = $session->url->append($url, 'func=exportThing;thingId='.$thingId);
}
if ($self->hasPrivileges($thingProperties->{groupIdImport})){
$var->{"import_url"} = $session->url->append($url, 'func=importForm;thingId='.$thingId);
@ -3265,21 +3515,17 @@ sub getSearchTemplateVars {
$var->{searchScreenTitle} = $thingProperties->{searchScreenTitle};
$var->{searchDescription} = $thingProperties->{searchDescription};
$currentUrl = $self->getUrl();
foreach ($self->session->form->param) {
# if we just saved data from an edit, we do not want to keep any of the params
last if $_ eq 'func' and $self->session->form->process($_) eq 'editThingDataSave';
unless ($_ eq "pn" || $_ eq "op" || $_ =~ /identifier/xi || $_ =~ /password/xi || $_ eq "orderBy" ||
$self->session->form->process($_) eq "") {
$currentUrl = $self->session->url->append($currentUrl,$self->session->url->escape($_)
.'='.$self->session->url->escape($self->session->form->process($_)));
}
my $currentUrl;
my $func = $session->form->process('func');
$func = 'search' if $func eq 'editThingDataSave';
$currentUrl = $self->getUrl('func='.$func.';thingId='.$thingId);
##Instead of blacklisting query params, they are whitelisted. List is currently empty.
FORM: foreach my $form (qw//) {
my $param = $session->form->process($form);
next FORM unless defined $param;
$currentUrl = $session->url->append($currentUrl, $form.'='.$param);
}
$fields = $session->db->read('select * from Thingy_fields where assetId =
'.$session->db->quote($self->getId).' and thingId = '.$session->db->quote($thingId).' order by
sequenceNumber');
$fields = $self->getFields($thingId);
while (my $field = $fields->hashRef) {
if ($field->{searchIn}){
my $searchForm = $self->getFormPlugin($field, 1);
@ -3332,7 +3578,8 @@ sequenceNumber');
}
$query .= join(", ",map {$dbh->quote_identifier('field_'.$_->{fieldId})} @displayInSearchFields);
$query .= " from ".$dbh->quote_identifier("Thingy_".$thingId);
if($session->form->process('func') eq 'search'){
my $func = $session->form->process('func');
if( $func eq 'search' || $func eq 'searchViaAjax' ){
# Don't add constraints when the search screen is displayed as an 'after save' option.
$query .= " where ".join(" and ",@constraints) if (scalar(@constraints) > 0);
}
@ -3345,9 +3592,6 @@ sequenceNumber');
$noFields = 1;
}
# store query in cache for thirty minutes
$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;
@ -3355,7 +3599,7 @@ sequenceNumber');
my @visibleResults;
if (! $noFields) {
my $sth = $self->session->db->read($query) if ! $noFields;
my $sth = $self->session->db->read($query);
while (my $result = $sth->hashRef){
if ($self->canViewThingData($thingId,$result->{thingDataId})){
push(@visibleResults,$result);
@ -3532,6 +3776,11 @@ The unique id of a thing.
The unique id of a row of thing data.
=head3 templateId
Optional. The unique id or url of the template to be used. When specified, the style template is not used.
If omitted, the thing data view template and style will be used.
=cut
sub www_viewThingData {
@ -3540,7 +3789,7 @@ sub www_viewThingData {
my $session = $self->session;
my $thingId = shift || $session->form->process('thingId');
my $thingDataId = shift || $session->form->process('thingDataId');
my $templateId = shift || $session->form->process('templateId');
my $var = $self->get;
my $url = $self->getUrl;
my $i18n = WebGUI::International->new($self->session, "Asset_Thingy");
@ -3570,9 +3819,19 @@ sub www_viewThingData {
$self->getViewThingVars($thingId,$thingDataId,$var);
$self->appendThingsVars($var, $thingId);
my $template;
if( $templateId )
{
$template = WebGUI::Asset::Template->newByUrl( $session, $templateId ) ||
WebGUI::Asset::Template->newById( $session, $templateId );
}
return $self->processStyle(
$self->processTemplate($var,$thingProperties->{viewTemplateId})
);
$self->processTemplate($var,$thingProperties->{viewTemplateId})
) if !$template;
return $self->processTemplate($var,$template->getId,$template);
}
#-------------------------------------------------------------------

View file

@ -20,6 +20,7 @@ use WebGUI::International;
use Moose;
use WebGUI::Definition::Asset;
extends 'WebGUI::Asset::Wobject';
with 'WebGUI::Role::Asset::Dashlet';
define tableName => 'WeatherData';
define assetName => ["assetName", 'Asset_WeatherData'];
define icon => 'weatherData.gif';
@ -57,6 +58,7 @@ property locations => (
tab => "properties",
hoverHelp => ["Your list of default weather locations", 'Asset_WeatherData'],
label => ["Default Locations", 'Asset_WeatherData'],
dashletOverridable => 1,
);
#-------------------------------------------------------------------
@ -93,49 +95,70 @@ to be displayed within the page style
sub view {
my $self = shift;
my $session = $self->session;
my %var;
my $url = $self->session->url;
if ($self->partnerId ne "" && $self->licenseKey ne "") {
foreach my $location (split("\n", $self->locations)) {
my $weather = Weather::Com::Finder->new({
'partner_id' => $self->partnerId,
'license' => $self->licenseKey,
'cache' => '/tmp',
});
next unless defined $weather;
my $overrides = $self->fetchUserOverrides($self->getParent->getId);
my $locations = $overrides->{locations} || $self->locations;
foreach my $location (split("\n", $locations)) {
my $loop_data;
my $link_data = [];
my $cached_data = $session->cache->get( join "", $self->getId, $location );
if ($cached_data) {
$loop_data = $cached_data->{locations};
$link_data = $cached_data->{links} || [];
}
else {
my $weather = Weather::Com::Finder->new({
'partner_id' => $self->partnerId,
'license' => $self->licenseKey,
'cache' => '/tmp',
});
next unless defined $weather;
foreach my $foundLocation(@{$weather->find($location)}) {
my $current_conditions = $foundLocation->current_conditions;
my $conditions = $current_conditions->description;
$conditions =~ s/\b(\w)/uc($1)/eg;
my $tempC = $current_conditions->temperature;
my $tempF;
$tempF = sprintf("%.0f",(((9/5)*$tempC) + 32)) if($tempC);
my $icon = $current_conditions->icon || "na";
foreach my $foundLocation(@{$weather->find($location)}) {
my $current_conditions = $foundLocation->current_conditions;
my $conditions = $current_conditions->description;
$conditions =~ s/\b(\w)/uc($1)/eg;
my $tempC = $current_conditions->temperature;
my $tempF;
$tempF = sprintf("%.0f",(((9/5)*$tempC) + 32)) if($tempC);
my $icon = $current_conditions->icon || "na";
push(@{$var{'ourLocations.loop'}}, {
query => $location,
cityState => $foundLocation->name || $location,
sky => $conditions || 'N/A',
tempF => (defined $tempF)?$tempF:'N/A',
tempC => (defined $tempC)?$tempC:'N/A',
smallIcon => $url->extras("wobject/WeatherData/small_icons/".$icon.".png"),
mediumIcon => $url->extras("wobject/WeatherData/medium_icons/".$icon.".png"),
largeIcon => $url->extras("wobject/WeatherData/large_icons/".$icon.".png"),
iconUrl => $url->extras("wobject/WeatherData/medium_icons/".$icon.".png"),
iconAlt => $conditions,
});
if (!$var{links_loop}) {
$var{links_loop} = [];
push @{$loop_data}, {
query => $location,
cityState => $foundLocation->name || $location,
sky => $conditions || 'N/A',
tempF => (defined $tempF)?$tempF:'N/A',
tempC => (defined $tempC)?$tempC:'N/A',
smallIcon => $url->extras("wobject/WeatherData/small_icons/".$icon.".png"),
mediumIcon => $url->extras("wobject/WeatherData/medium_icons/".$icon.".png"),
largeIcon => $url->extras("wobject/WeatherData/large_icons/".$icon.".png"),
iconUrl => $url->extras("wobject/WeatherData/medium_icons/".$icon.".png"),
iconAlt => $conditions,
last_fetch => time(),
};
for my $lnk (@{$foundLocation->current_conditions->{WEATHER}{lnks}{link}} ) {
push @{$var{links_loop}}, {
link_url => $lnk->{l},
link_title => $lnk->{t},
};
if (! $link_data) {
push @{ $link_data }, {
link_url => $lnk->{l},
link_title => $lnk->{t},
};
}
}
}
}
my $cached_data = {
locations => $loop_data,
links => $link_data,
};
$session->cache->set( join( "", $self->getId, $location ), $cached_data, $self->get('cacheTimeout'));
}
push @{$var{'ourLocations.loop'}}, @{ $loop_data };
if (!$var{links_loop}) {
$var{links_loop} = $link_data;
}
}
}
return $self->processTemplate(\%var, undef, $self->{_viewTemplate});

View file

@ -869,6 +869,8 @@ Return search results that match the keyword from the form variable C<keyword>.
sub www_byKeyword {
my $self = shift;
my $check = $self->checkView;
return $self->session->privilege->noAccess() unless $self->canView;
my $session = $self->session;
my $keyword = $session->form->process("keyword");
@ -980,6 +982,8 @@ Render a search form and process the contents, returning the results.
sub www_search {
my $self = shift;
my $check = $self->checkView;
return $self->session->privilege->noAccess() unless $self->canView;
my $i18n = WebGUI::International->new($self->session, "Asset_WikiMaster");
my $queryString = $self->session->form->process('query', 'text');
my $var = {