merge to 10219
This commit is contained in:
parent
ae28bf79c8
commit
4c1307e3d0
194 changed files with 8203 additions and 2134 deletions
|
|
@ -1,3 +1,44 @@
|
|||
7.7.3
|
||||
- fixed #10094: double explanation in thread help
|
||||
- rfe #9612: Carousel Wobject (was Widget Wobject) (SDH Consulting Group)
|
||||
- Survey summaries now added. In the Survey edit, select quiz mode, and a summary will be shown to the user at the end of the survey.
|
||||
7.7.2
|
||||
- fixed #10056: YUI javascripts included while adminOff (BNC)
|
||||
- fixed a bug that required you to hit "update cart" before the checkout
|
||||
button would appear
|
||||
- fixed #9955: Matrix alpha sort is backwards
|
||||
- fixed #9934: Matrix 2.0 - Products should be listed alphabetically
|
||||
- fixed #9865: Matrix: Later added attributes are not detected in older listings
|
||||
- added: Sku's now have a getAddToCartForm method, which is used by the Shelf
|
||||
to place a small form next to each Sku that displays. Sku's with complex
|
||||
forms (like the EMS sku's), simply display a button to take the user to the
|
||||
sku's view screen for the whole form. [TEMPLATE]
|
||||
- fixed #9933: Matrix 2.0 - Unable to view/edit product maintainer account
|
||||
- fixed #9951: Matrix 2.0: Median not calculated correctly
|
||||
- added new AssetAspect::RssFeed (Matthew Wilson) - to convert an asset to use it (see
|
||||
Collaboration.pm as an example), inherit from Class::C3 as in Collaboration
|
||||
and you'll need to remove all your ->SUPER::xxxxx invocations - usually replace it
|
||||
with ->next::method, but when your SUPER was previously calling a method with
|
||||
a name different from your current method, you'll need to specify the parent/super
|
||||
module name explicity (e.g. ->WebGUI::Asset::Wobject::canEdit()). You'll also
|
||||
need to implement the getRssFeedItems method as explained in AssetAspect/RssFeed.pm
|
||||
- Survey now shows warnings if bad goto, bad gotoExpressions, no question text, survey looping,
|
||||
or no question answers are found.
|
||||
- fixed: Gateway problem with VendorPayout.
|
||||
- fixed #9976: carts not cleaned up
|
||||
- fixed Problems with displaying the wrong name and/or creation in the Account, and all plugins.
|
||||
|
||||
7.7.1
|
||||
- the AdSku project: create a Sku that allows buyers to purchase advertising in select AdSpaces at selected priorities
|
||||
- rfe #9353: Welcome message template (SDH Consulting Group)
|
||||
- rfe #10007: New Month and Year question type. If required, Month must be selected and a 4 digit year must be entered.
|
||||
- fixed #10011: Wrong spelling of "Descendant" in Navigation Asset Help function (Rob Schipper/NFIA India)
|
||||
- rfe #9098: Thingy Thing-copy function (SDH Consulting Group)
|
||||
- rfe #9099: Thingy field-copy function (SDH Consulting Group)
|
||||
- Keywords are now comma separated rather than space separated.
|
||||
- added Keywords form control with autocomplete
|
||||
- Survey: Moved multiple choice questions to the data base, and they can now be edited globally from the Survey editor
|
||||
|
||||
7.7.0
|
||||
- fixed #9913: New Content Side Bar missing in Asset window
|
||||
- fixed: New Mail macro never returns any messages
|
||||
|
|
@ -18,6 +59,19 @@
|
|||
- fixed #9956: Product Import
|
||||
- added Survey now has a loading mask on Survey edit ajax calls.
|
||||
- fixed: Sliders fixed. Improved algorithm for determining pixel step size.
|
||||
- rfe #9355: Password Recovery email subject (SDH Consulting Group)
|
||||
- added: Users can now set a minimum cart amount required for checkout. ( Martin Kamerbeek / Oqapi )
|
||||
- fixed validation issue in the donation asset ( Martin kamerbeek / Oqapi )
|
||||
- rfe #9354: Account activation email template (SDH Consulting Group)
|
||||
- rfe #9233: Survey branching expressions (Patrick Donelan, SDH Consulting Group)
|
||||
- rfe #9202: Survey Jump-to combo box (Patrick Donelan, SDH Consulting Group)
|
||||
- rfe #9201: Make Survey TextAreas YUI resizable (SDH Consulting Group)
|
||||
- rfe #9200: Survey Text/TextArea handling (SDH Consulting Group)
|
||||
- rfe #9199: Survey final page detection (SDH Consulting Group)
|
||||
- rfe #9198: Turn Survey Edit Section/Question/Answer fields into RTEs (SDH Consulting Group)
|
||||
- rfe #9197: Survey timeout handling (SDH Consulting Group)
|
||||
- rfe #8862: Passive Analytics (SDH Consulting Group)
|
||||
- fixed #9979: i18n labels for Gallery (Knowmad Technologies)
|
||||
|
||||
7.6.14
|
||||
- fixed: IE6 shows Admin Bar over Asset Manager
|
||||
|
|
|
|||
172
docs/create.sql
172
docs/create.sql
File diff suppressed because one or more lines are too long
|
|
@ -7,6 +7,25 @@ upgrading from one version to the next, or even between multiple
|
|||
versions. Be sure to heed the warnings contained herein as they will
|
||||
save you many hours of grief.
|
||||
|
||||
7.7.2
|
||||
--------------------------------------------------------------------
|
||||
* WebGUI now requires Clone version 0.31 or greater.
|
||||
* You must upgrade to WebGUI 7.7.2 before going on to higher versions of WebGUI due
|
||||
to changes in the database table for the Cart.
|
||||
|
||||
* The RSSCapable class and RSSFromParent asset have been removed.
|
||||
Any custom assets using those are recommended to switch to the new
|
||||
RssFeed AssetAspect. If not used by custom assets, the tables
|
||||
used by them will be removed from the database.
|
||||
|
||||
7.7.1
|
||||
--------------------------------------------------------------------
|
||||
* Keywords are now comma separated rather than space separated. Quotes are
|
||||
no longer treated specially and will become part of keywords. Keywords
|
||||
cannot contain commas. Keyword searching is still case insensitive, but
|
||||
keyword will preserve the case of what is entered.
|
||||
|
||||
|
||||
7.7.0
|
||||
--------------------------------------------------------------------
|
||||
* WebGUI now requires Params::Validate version 0.81 or greater.
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -60,21 +60,19 @@ sub addPackage {
|
|||
# Import the package into the import node
|
||||
my $package = WebGUI::Asset->getImportNode($session)->importPackage( $storage );
|
||||
|
||||
# Make the package not a package anymore
|
||||
$package->update({ isPackage => 0 });
|
||||
|
||||
# Set the default flag for templates added
|
||||
my $assetIds
|
||||
= $package->getLineage( ['self','descendants'], {
|
||||
includeOnlyClasses => [ 'WebGUI::Asset::Template' ],
|
||||
} );
|
||||
# Turn off the package flag, and set the default flag for templates added
|
||||
my $assetIds = $package->getLineage( ['self','descendants'] );
|
||||
for my $assetId ( @{ $assetIds } ) {
|
||||
my $asset = WebGUI::Asset->newByDynamicClass( $session, $assetId );
|
||||
if ( !$asset ) {
|
||||
print "Couldn't instantiate asset with ID '$assetId'. Please check package '$file' for corruption.\n";
|
||||
next;
|
||||
}
|
||||
$asset->update( { isDefault => 1 } );
|
||||
my $properties = { isPackage => 0 };
|
||||
if ($asset->isa('WebGUI::Asset::Template')) {
|
||||
$properties->{isDefault} = 1;
|
||||
}
|
||||
$asset->update( $properties );
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
BIN
docs/upgrades/packages-7.7.1/image3.wgpkg
Normal file
BIN
docs/upgrades/packages-7.7.1/image3.wgpkg
Normal file
Binary file not shown.
BIN
docs/upgrades/packages-7.7.1/root_import_ad-sku.wgpkg
Normal file
BIN
docs/upgrades/packages-7.7.1/root_import_ad-sku.wgpkg
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
docs/upgrades/packages-7.7.1/templates_thingy-default.wgpkg
Normal file
BIN
docs/upgrades/packages-7.7.1/templates_thingy-default.wgpkg
Normal file
Binary file not shown.
Binary file not shown.
BIN
docs/upgrades/packages-7.7.2/root_import_shelf-default.wgpkg
Normal file
BIN
docs/upgrades/packages-7.7.2/root_import_shelf-default.wgpkg
Normal file
Binary file not shown.
Binary file not shown.
BIN
docs/upgrades/packages-7.7.3/root_import_carousel.wgpkg
Normal file
BIN
docs/upgrades/packages-7.7.3/root_import_carousel.wgpkg
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -32,17 +32,14 @@ my $quiet; # this line required
|
|||
my $session = start(); # this line required
|
||||
|
||||
# upgrade functions go here
|
||||
addAccountActivationTemplateToSettings( $session );
|
||||
addGroupToAddToMatrix( $session );
|
||||
addScreenshotTemplatesToMatrix( $session );
|
||||
surveyDoAfterTimeLimit($session);
|
||||
surveyRemoveResponseTemplate($session);
|
||||
surveyEndWorkflow($session);
|
||||
installAssetHistory($session);
|
||||
|
||||
# Story Manager
|
||||
installStoryManagerTables($session);
|
||||
sm_upgradeConfigFiles($session);
|
||||
sm_updateDailyWorkflow($session);
|
||||
addMinimumCartCheckoutSetting( $session );
|
||||
|
||||
# Passive Analytics
|
||||
pa_installLoggingTables($session);
|
||||
|
|
@ -58,6 +55,16 @@ createShopAcccountPluginSettings( $session );
|
|||
|
||||
finish($session); # this line required
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addAccountActivationTemplateToSettings {
|
||||
my $session = shift;
|
||||
print "\tAdding account activation template to settings \n" unless $quiet;
|
||||
|
||||
$session->db->write("insert into settings (name, value) values ('webguiAccountActivationTemplate','PBtmpl0000000000000016')");
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addGroupToAddToMatrix {
|
||||
my $session = shift;
|
||||
|
|
@ -115,7 +122,7 @@ sub installAssetHistory {
|
|||
print "\tAdding Asset History content handler... \n" unless $quiet;
|
||||
##Content Handler
|
||||
my $contentHandlers = $session->config->get('contentHandlers');
|
||||
if (! isIn('WebGUI::Content::Handler', @{ $contentHandlers }) ) {
|
||||
if (! isIn('WebGUI::Content::AssetHistory', @{ $contentHandlers }) ) {
|
||||
my @newHandlers = ();
|
||||
foreach my $handler (@{ $contentHandlers }) {
|
||||
push @newHandlers, $handler;
|
||||
|
|
@ -307,13 +314,23 @@ sub addTransactionItemFlags {
|
|||
#----------------------------------------------------------------------------
|
||||
sub createShopAcccountPluginSettings {
|
||||
my $session = shift;
|
||||
print "Creating default settings for the account plugin..." unless $quiet;
|
||||
print "\tCreating default settings for the account plugin..." unless $quiet;
|
||||
|
||||
$session->setting->add('shopMySalesTemplateId', '-zxyB-O50W8YnL39Ouoc4Q');
|
||||
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addMinimumCartCheckoutSetting {
|
||||
my $session = shift;
|
||||
print "\tAdding setting for minimum cart checkout..." unless $quiet;
|
||||
|
||||
$session->setting->add( 'shopCartCheckoutMinimum', '0.00' );
|
||||
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Describe what our function does
|
||||
#sub exampleFunction {
|
||||
|
|
@ -323,97 +340,6 @@ sub createShopAcccountPluginSettings {
|
|||
# print "DONE!\n" unless $quiet;
|
||||
#}
|
||||
|
||||
sub installStoryManagerTables {
|
||||
my ($session) = @_;
|
||||
print "\tAdding Story Manager tables... " unless $quiet;
|
||||
my $db = $session->db;
|
||||
$db->write(<<EOSTORY);
|
||||
CREATE TABLE Story (
|
||||
assetId CHAR(22) BINARY NOT NULL,
|
||||
revisionDate BIGINT NOT NULL,
|
||||
headline CHAR(255),
|
||||
subtitle CHAR(255),
|
||||
byline CHAR(255),
|
||||
location CHAR(255),
|
||||
highlights TEXT,
|
||||
story MEDIUMTEXT,
|
||||
photo LONGTEXT,
|
||||
PRIMARY KEY ( assetId, revisionDate )
|
||||
)
|
||||
EOSTORY
|
||||
|
||||
$db->write(<<EOARCHIVE);
|
||||
CREATE TABLE StoryArchive (
|
||||
assetId CHAR(22) BINARY NOT NULL,
|
||||
revisionDate BIGINT NOT NULL,
|
||||
storiesPerFeed INTEGER,
|
||||
storiesPerPage INTEGER,
|
||||
groupToPost CHAR(22) BINARY,
|
||||
templateId CHAR(22) BINARY,
|
||||
storyTemplateId CHAR(22) BINARY,
|
||||
editStoryTemplateId CHAR(22) BINARY,
|
||||
archiveAfter INT(11),
|
||||
richEditorId CHAR(22) BINARY,
|
||||
approvalWorkflowId CHAR(22) BINARY DEFAULT 'pbworkflow000000000003',
|
||||
PRIMARY KEY ( assetId, revisionDate )
|
||||
)
|
||||
EOARCHIVE
|
||||
|
||||
$db->write(<<EOTOPIC);
|
||||
CREATE TABLE StoryTopic (
|
||||
assetId CHAR(22) BINARY NOT NULL,
|
||||
revisionDate BIGINT NOT NULL,
|
||||
storiesPer INTEGER,
|
||||
storiesShort INTEGER,
|
||||
templateId CHAR(22) BINARY,
|
||||
storyTemplateId CHAR(22) BINARY,
|
||||
PRIMARY KEY ( assetId, revisionDate )
|
||||
)
|
||||
EOTOPIC
|
||||
|
||||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
sub sm_upgradeConfigFiles {
|
||||
my ($session) = @_;
|
||||
print "\tAdding Story Manager to config file... " unless $quiet;
|
||||
my $config = $session->config;
|
||||
$config->addToHash(
|
||||
'assets',
|
||||
'WebGUI::Asset::Wobject::StoryTopic' => {
|
||||
'category' => 'community'
|
||||
},
|
||||
);
|
||||
$config->addToHash(
|
||||
'assets',
|
||||
"WebGUI::Asset::Wobject::StoryArchive" => {
|
||||
"isContainer" => 1,
|
||||
"category" => "community"
|
||||
},
|
||||
);
|
||||
my $activities = $config->get('workflowActivities');
|
||||
my $none = $activities->{None};
|
||||
if (!isIn('WebGUI::Workflow::Activity::ArchiveOldStories', @{ $none })) {
|
||||
unshift @{ $none }, 'WebGUI::Workflow::Activity::ArchiveOldStories';
|
||||
}
|
||||
$config->set('workflowActivities', $activities);
|
||||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
sub sm_updateDailyWorkflow {
|
||||
my ($session) = @_;
|
||||
print "\tAdding Archive Old Stories to Daily Workflow... " unless $quiet;
|
||||
my $workflow = WebGUI::Workflow->new($session, 'pbworkflow000000000001');
|
||||
foreach my $activity (@{ $workflow->getActivities }) {
|
||||
return if $activity->getName() eq 'WebGUI::Workflow::Activity::ArchiveOldStories';
|
||||
}
|
||||
my $activity = $workflow->addActivity('WebGUI::Workflow::Activity::ArchiveOldStories');
|
||||
$activity->set('title', 'Archive Old Stories');
|
||||
$activity->set('description', 'Archive old stories, based on the settings of the Story Archives that own them');
|
||||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
|
||||
|
||||
|
|
|
|||
237
docs/upgrades/upgrade_7.7.0-7.7.1.pl
Normal file
237
docs/upgrades/upgrade_7.7.0-7.7.1.pl
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
#!/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.7.1';
|
||||
my $quiet; # this line required
|
||||
|
||||
|
||||
my $session = start(); # this line required
|
||||
|
||||
# upgrade functions go here
|
||||
adSkuInstall($session);
|
||||
addWelcomeMessageTemplateToSettings( $session );
|
||||
addStatisticsCacheTimeoutToMatrix( $session );
|
||||
removeOldSettings( $session );
|
||||
|
||||
#add Survey table
|
||||
addSurveyQuestionTypes($session);
|
||||
|
||||
# image mods
|
||||
addImageAnnotation($session);
|
||||
|
||||
# rss mods
|
||||
addRssLimit($session);
|
||||
|
||||
finish($session); # this line required
|
||||
|
||||
# remove old settings that aren't used any more
|
||||
sub removeOldSettings {
|
||||
my $session = shift;
|
||||
print "\tRemoving old, unused settings... " unless $quiet;
|
||||
my $setting = $session->setting;
|
||||
|
||||
$setting->remove('commerceCheckoutCanceledTemplateId');
|
||||
$setting->remove('commerceConfirmCheckoutTemplateId');
|
||||
$setting->remove('commerceEnableSalesTax');
|
||||
$setting->remove('commercePaymentPlugin');
|
||||
$setting->remove('commercePurchaseHistoryTemplateId');
|
||||
$setting->remove('commerceSelectPaymentGatewayTemplateId');
|
||||
$setting->remove('commerceSelectShippingMethodTemplateId');
|
||||
$setting->remove('commerceSendDailyReportTo');
|
||||
$setting->remove('commerceViewShoppingCartTemplateId');
|
||||
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
sub addSurveyQuestionTypes{
|
||||
my $session = shift;
|
||||
print "\tAdding new survey table Survey_questionTypes... " unless $quiet;
|
||||
$session->db->write("
|
||||
CREATE TABLE `Survey_questionTypes` (
|
||||
`questionType` varchar(56) NOT NULL,
|
||||
`answers` text NOT NULL,
|
||||
PRIMARY KEY (`questionType`))
|
||||
");
|
||||
$session->db->write(q{
|
||||
INSERT INTO `Survey_questionTypes` VALUES ('Scale',''),('Gender','Male,Female'),('Education','Elementary or some high school,High school/GED,Some college/vocational school,College graduate,Some graduate work,Master\\'s degree,Doctorate (of any type),Other degree (verbatim)'),('Importance','Not at all important,,,,,,,,,,Extremely important'),('Yes/No','Yes,No'),('Confidence','Not at all confident,,,,,,,,,,Extremely confident'),('Effectiveness','Not at all effective,,,,,,,,,,Extremely effective'),('Oppose/Support','Strongly oppose,,,,,,Strongly support'),('Certainty','Not at all certain,,,,,,,,,,Extremely certain'),('True/False','True,False'),('Concern','Not at all concerned,,,,,,,,,,Extremely concerned'),('Ideology','Strongly liberal,Liberal,Somewhat liberal,Middle of the road,Slightly conservative,Conservative,Strongly conservative'),('Security','Not at all secure,,,,,,,,,,Extremely secure'),('Risk','No risk,,,,,,,,,,Extreme risk'),('Agree/Disagree','Strongly disagree,,,,,,Strongly agree'),('Race','American Indian,Asian,Black,Hispanic,White non-Hispanic,Something else (verbatim)'),('Threat','No threat,,,,,,,,,,Extreme threat'),('Party','Democratic party,Republican party (or GOP),Independent party,Other party (verbatim)'),('Likelihood','Not at all likely,,,,,,,,,,Extremely likely'),('Multiple Choice',''),('Satisfaction','Not at all satisfied,,,,,,,,,,Extremely satisfied')
|
||||
});
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
sub addWelcomeMessageTemplateToSettings {
|
||||
my $session = shift;
|
||||
print "\tAdding welcome message template to settings... " unless $quiet;
|
||||
|
||||
$session->db->write("insert into settings values ('webguiWelcomeMessageTemplate', 'PBtmpl0000000000000015');");
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addRssLimit {
|
||||
my $session = shift;
|
||||
print "\tAdding rssLimit to RSSCapable table, if needed... " unless $quiet;
|
||||
my $sth = $session->db->read('describe RSSCapable rssCapableRssLimit');
|
||||
if (! defined $sth->hashRef) {
|
||||
$session->db->write("alter table RSSCapable add column rssCapableRssLimit integer");
|
||||
}
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addImageAnnotation {
|
||||
my $session = shift;
|
||||
print "\tAdding annotations to ImageAsset table, if needed... " unless $quiet;
|
||||
my $sth = $session->db->read('describe ImageAsset annotations');
|
||||
if (! defined $sth->hashRef) {
|
||||
$session->db->write("alter table ImageAsset add column annotations mediumtext");
|
||||
}
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addStatisticsCacheTimeoutToMatrix{
|
||||
my $session = shift;
|
||||
print "\tAdding statisticsCacheTimeout setting to Matrix table... " unless $quiet;
|
||||
$session->db->write("alter table Matrix add statisticsCacheTimeout int(11) not null default 3600");
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Describe what our function does
|
||||
sub adSkuInstall {
|
||||
my $session = shift;
|
||||
print "\tInstalling the AdSku Asset...\n" unless $quiet;
|
||||
print "\t\tCreate AdSku database table.\n" unless $quiet;
|
||||
$session->db->write("CREATE TABLE AdSku (
|
||||
assetId VARCHAR(22) BINARY NOT NULL,
|
||||
revisionDate BIGINT NOT NULL,
|
||||
purchaseTemplate VARCHAR(22) BINARY NOT NULL,
|
||||
manageTemplate VARCHAR(22) BINARY NOT NULL,
|
||||
adSpace VARCHAR(22) BINARY NOT NULL,
|
||||
priority INTEGER DEFAULT '1',
|
||||
pricePerClick Float DEFAULT '0',
|
||||
pricePerImpression Float DEFAULT '0',
|
||||
clickDiscounts VARCHAR(1024) default '',
|
||||
impressionDiscounts VARCHAR(1024) default '',
|
||||
PRIMARY KEY (assetId,revisionDate)
|
||||
)");
|
||||
print "\t\tCreate Adsku crud table.\n" unless $quiet;
|
||||
use WebGUI::AssetCollateral::Sku::Ad::Ad;
|
||||
WebGUI::AssetCollateral::Sku::Ad::Ad->crud_createTable($session);
|
||||
print "\t\tAdding to config file.\n" unless $quiet;
|
||||
$session->config->addToHash("assets", 'WebGUI::Asset::Sku::Ad' => { category => 'shop' } );
|
||||
print "\tDone.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# 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;
|
||||
#}
|
||||
|
||||
|
||||
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Add a package to the import node
|
||||
sub addPackage {
|
||||
my $session = shift;
|
||||
my $file = shift;
|
||||
|
||||
# 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 = WebGUI::Asset->getImportNode($session)->importPackage( $storage );
|
||||
|
||||
# Make the package not a package anymore
|
||||
$package->update({ isPackage => 0 });
|
||||
|
||||
# Set the default flag for templates added
|
||||
my $assetIds
|
||||
= $package->getLineage( ['self','descendants'], {
|
||||
includeOnlyClasses => [ 'WebGUI::Asset::Template' ],
|
||||
} );
|
||||
for my $assetId ( @{ $assetIds } ) {
|
||||
my $asset = WebGUI::Asset->newByDynamicClass( $session, $assetId );
|
||||
if ( !$asset ) {
|
||||
print "Couldn't instantiate asset with ID '$assetId'. Please check package '$file' for corruption.\n";
|
||||
next;
|
||||
}
|
||||
$asset->update( { isDefault => 1 } );
|
||||
}
|
||||
|
||||
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',".$session->datetime->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
|
||||
284
docs/upgrades/upgrade_7.7.1-7.7.2.pl
Normal file
284
docs/upgrades/upgrade_7.7.1-7.7.2.pl
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
#!/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;
|
||||
use WebGUI::Workflow;
|
||||
use WebGUI::Utility;
|
||||
|
||||
my $toVersion = '7.7.2';
|
||||
my $quiet; # this line required
|
||||
|
||||
|
||||
my $session = start(); # this line required
|
||||
|
||||
# upgrade functions go here
|
||||
|
||||
recalculateMatrixListingMedianValue( $session );
|
||||
addRssFeedAspect($session);
|
||||
addRssFeedAspectToAssets($session);
|
||||
convertCollaborationToRssAspect($session);
|
||||
removeRssCapableAsset($session);
|
||||
addCreationTimeToCart($session);
|
||||
addCartKillerActivityToConfig($session);
|
||||
addCartKillerActivityToWorkflow($session);
|
||||
|
||||
finish($session); # this line required
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub recalculateMatrixListingMedianValue{
|
||||
my $session = shift;
|
||||
print "\tRecalculating median value for Matrix Listing ratings... " unless $quiet;
|
||||
my $matrices = WebGUI::Asset->getRoot($session)->getLineage(['descendants'],
|
||||
{
|
||||
statesToInclude => ['published','trash','clipboard','clipboard-limbo','trash-limbo'],
|
||||
statusToInclude => ['pending','approved','deleted','archived'],
|
||||
includeOnlyClasses => ['WebGUI::Asset::Wobject::Matrix'],
|
||||
returnObjects => 1,
|
||||
});
|
||||
|
||||
for my $matrix (@{$matrices})
|
||||
{
|
||||
next unless defined $matrix;
|
||||
my %categories = keys %{$matrix->getCategories};
|
||||
my $listings = $session->db->read("select distinct listingId from MatrixListing_rating where assetId = ?"
|
||||
,[$matrix->getId]);
|
||||
while (my $listing= $listings->hashRef){
|
||||
foreach my $category (%categories) {
|
||||
my $half = $session->db->quickScalar("select round((select count(*) from MatrixListing_rating where
|
||||
listingId = ? and category = ?)/2)",[$listing->{listingId},$category]);
|
||||
my $medianValue = $session->db->quickScalar("select rating from MatrixListing_rating where listingId =?
|
||||
and category =? order by rating limit $half,1;",[$listing->{listingId},$category]);
|
||||
$session->db->write("update MatrixListing_ratingSummary set medianValue = ? where listingId = ? and
|
||||
category = ?",[$medianValue,$listing->{listingId},$category]);
|
||||
}
|
||||
}
|
||||
}
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addRssFeedAspect {
|
||||
my $session = shift;
|
||||
print "\tAdding RssFeed asset aspect..." unless $quiet;
|
||||
$session->db->write(q{create table assetAspectRssFeed (
|
||||
assetId char(22) binary not null,
|
||||
revisionDate bigint not null,
|
||||
itemsPerFeed int(11) default 25,
|
||||
feedCopyright text,
|
||||
feedTitle text,
|
||||
feedDescription mediumtext,
|
||||
feedImage char(22) binary,
|
||||
feedImageLink text,
|
||||
feedImageDescription mediumtext,
|
||||
feedHeaderLinks char(32) default 'rss\natom',
|
||||
primary key (assetId, revisionDate)
|
||||
)});
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addRssFeedAspectToAssets {
|
||||
my $session = shift;
|
||||
my $db = $session->db;
|
||||
foreach my $asset_class (qw( WikiMaster SyndicatedContent Gallery GalleryAlbum )) {
|
||||
print "\tAdding RssFeed aspect to $asset_class table..." unless $quiet;
|
||||
my $pages = $db->read("select assetId,revisionDate from $asset_class");
|
||||
while (my ($id, $rev) = $pages->array) {
|
||||
$db->write("INSERT INTO assetAspectRssFeed (assetId, revisionDate, itemsPerFeed, feedTitle, feedDescription, feedImage, feedImageLink, feedImageDescription) VALUES (?,?,25,'','',NULL,'','')",[$id,$rev]);
|
||||
}
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub convertCollaborationToRssAspect {
|
||||
my $session = shift;
|
||||
print "\tAdding RssFeed aspect to Collaboration, (porting rssCapableRssLimit to itemsPerFeed)..." unless $quiet;
|
||||
my $db = $session->db;
|
||||
my @rssFromParents;
|
||||
my $pages = $db->read("SELECT Collaboration.assetId, Collaboration.revisionDate, RSSCapable.rssCapableRssLimit, RSSCapable.rssCapableRssFromParentId, RSSCapable.rssCapableRssEnabled FROM Collaboration INNER JOIN RSSCapable ON Collaboration.assetId=RSSCapable.assetId AND Collaboration.revisionDate=RSSCapable.revisionDate");
|
||||
while (my ($id, $rev, $limit, $fromParent, $enabled) = $pages->array) {
|
||||
if ($fromParent) {
|
||||
push @rssFromParents, $fromParent;
|
||||
}
|
||||
my $headerLinks = $enabled ? "rss\natom" : q{};
|
||||
$db->write("INSERT INTO assetAspectRssFeed (assetId, revisionDate, itemsPerFeed, feedTitle, feedDescription, feedImage, feedImageLink, feedImageDescription, feedHeaderLinks) VALUES (?,?,?,'','',NULL,'','',?)",[$id,$rev,$limit || 25, $headerLinks]);
|
||||
}
|
||||
for my $assetId (@rssFromParents) {
|
||||
my $asset = eval { WebGUI::Asset->newPending($session, $assetId) };
|
||||
if ($asset) {
|
||||
$asset->purge;
|
||||
}
|
||||
}
|
||||
$db->write("DELETE FROM RSSCapable WHERE assetId IN (SELECT assetId FROM Collaboration GROUP BY assetId)");
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub removeRssCapableAsset {
|
||||
my $session = shift;
|
||||
print "\tChecking for uses of RSSCapable...\n" unless $quiet;
|
||||
my @rssCapableClasses = $session->db->buildArray('SELECT className FROM RSSCapable INNER JOIN asset ON RSSCapable.assetId=asset.assetId GROUP BY className');
|
||||
if (@rssCapableClasses) {
|
||||
warn "\t\tThis site is using the assets\n\t\t\t" . join(', ', @rssCapableClasses) . "\n\t\twhich use the RSSCapable class! Support RSSCapable has been dropped and it will no longer be maintained.\n";
|
||||
}
|
||||
else {
|
||||
print "\t\tNot used, removing.\n" unless $quiet;
|
||||
$session->db->write("DROP TABLE RSSCapable");
|
||||
$session->db->write("DROP TABLE RSSFromParent");
|
||||
my $rssCapableTemplates = WebGUI::Asset->getRoot($session)->getLineage(['descendants'], {
|
||||
statesToInclude => [qw(published clipboard clipboard-limbo trash-limbo)],
|
||||
statusToInclude => [qw(approved pending archived)],
|
||||
returnObjects => 1,
|
||||
includeOnlyClasses => ['WebGUI::Asset::Template'],
|
||||
joinClass => 'WebGUI::Asset::Template',
|
||||
whereClause => q{template.namespace = 'RSSCapable/RSS'},
|
||||
});
|
||||
for my $template (@{$rssCapableTemplates}) {
|
||||
$template->trash;
|
||||
}
|
||||
}
|
||||
print "\tDone.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addCreationTimeToCart {
|
||||
my $session = shift;
|
||||
print "\tAdding creation time to cart..." unless $quiet;
|
||||
$session->db->write("alter table cart add column creationDate int(20)");
|
||||
$session->db->write('update cart set creationDate=NOW()');
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addCartKillerActivityToConfig {
|
||||
my $session = shift;
|
||||
print "\tAdding Remove Old Carts workflow activity to config files..." unless $quiet;
|
||||
my $activities = $session->config->get('workflowActivities');
|
||||
my $none = $activities->{'None'};
|
||||
if (!isIn('WebGUI::Workflow::Activity::RemoveOldCarts', @{ $none })) {
|
||||
push @{ $none }, 'WebGUI::Workflow::Activity::RemoveOldCarts';
|
||||
}
|
||||
$session->config->set('workflowActivities', $activities);
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addCartKillerActivityToWorkflow {
|
||||
my $session = shift;
|
||||
print "\tAdding Remove Old Carts workflow activity to Daily Workflow..." unless $quiet;
|
||||
my $workflow = WebGUI::Workflow->new($session, 'pbworkflow000000000001');
|
||||
my $removeCarts = $workflow->addActivity('WebGUI::Workflow::Activity::RemoveOldCarts');
|
||||
$removeCarts->set('title', 'Remove old carts');
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# 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;
|
||||
#}
|
||||
|
||||
|
||||
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Add a package to the import node
|
||||
sub addPackage {
|
||||
my $session = shift;
|
||||
my $file = shift;
|
||||
|
||||
# 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 = WebGUI::Asset->getImportNode($session)->importPackage( $storage );
|
||||
|
||||
# Make the package not a package anymore
|
||||
$package->update({ isPackage => 0 });
|
||||
|
||||
# Set the default flag for templates added
|
||||
my $assetIds
|
||||
= $package->getLineage( ['self','descendants'], {
|
||||
includeOnlyClasses => [ 'WebGUI::Asset::Template' ],
|
||||
} );
|
||||
for my $assetId ( @{ $assetIds } ) {
|
||||
my $asset = WebGUI::Asset->newByDynamicClass( $session, $assetId );
|
||||
if ( !$asset ) {
|
||||
print "Couldn't instantiate asset with ID '$assetId'. Please check package '$file' for corruption.\n";
|
||||
next;
|
||||
}
|
||||
$asset->update( { isDefault => 1 } );
|
||||
}
|
||||
|
||||
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',".$session->datetime->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
|
||||
240
docs/upgrades/upgrade_7.7.2-7.7.3.pl
Normal file
240
docs/upgrades/upgrade_7.7.2-7.7.3.pl
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
#!/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;
|
||||
use WebGUI::Utility;
|
||||
|
||||
|
||||
my $toVersion = '7.7.3';
|
||||
my $quiet; # this line required
|
||||
|
||||
|
||||
my $session = start(); # this line required
|
||||
|
||||
# upgrade functions go here
|
||||
|
||||
addSurveyQuizModeColumns($session);
|
||||
addSurveyExpressionEngineConfigFlag($session);
|
||||
|
||||
# Story Manager
|
||||
installStoryManagerTables($session);
|
||||
sm_upgradeConfigFiles($session);
|
||||
sm_updateDailyWorkflow($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;
|
||||
#}
|
||||
|
||||
sub addSurveyQuizModeColumns{
|
||||
my $session = shift;
|
||||
print "\tAdding columns to Survey table... " unless $quiet;
|
||||
$session->db->write("alter table Survey add column `quizModeSummary` TINYINT(3)");
|
||||
$session->db->write("alter table Survey add column `surveySummaryTemplateId` char(22)");
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
sub addSurveyExpressionEngineConfigFlag{
|
||||
my $session = shift;
|
||||
print "\tAdding enableSurveyExpressionEngine config option... " unless $quiet;
|
||||
$session->config->set('enableSurveyExpressionEngine', 0);
|
||||
print "Done.\n" unless $quiet;
|
||||
}
|
||||
|
||||
sub installStoryManagerTables {
|
||||
my ($session) = @_;
|
||||
print "\tAdding Story Manager tables... " unless $quiet;
|
||||
my $db = $session->db;
|
||||
$db->write(<<EOSTORY);
|
||||
CREATE TABLE Story (
|
||||
assetId CHAR(22) BINARY NOT NULL,
|
||||
revisionDate BIGINT NOT NULL,
|
||||
headline CHAR(255),
|
||||
subtitle CHAR(255),
|
||||
byline CHAR(255),
|
||||
location CHAR(255),
|
||||
highlights TEXT,
|
||||
story MEDIUMTEXT,
|
||||
photo LONGTEXT,
|
||||
PRIMARY KEY ( assetId, revisionDate )
|
||||
)
|
||||
EOSTORY
|
||||
|
||||
$db->write(<<EOARCHIVE);
|
||||
CREATE TABLE StoryArchive (
|
||||
assetId CHAR(22) BINARY NOT NULL,
|
||||
revisionDate BIGINT NOT NULL,
|
||||
storiesPerFeed INTEGER,
|
||||
storiesPerPage INTEGER,
|
||||
groupToPost CHAR(22) BINARY,
|
||||
templateId CHAR(22) BINARY,
|
||||
storyTemplateId CHAR(22) BINARY,
|
||||
editStoryTemplateId CHAR(22) BINARY,
|
||||
archiveAfter INT(11),
|
||||
richEditorId CHAR(22) BINARY,
|
||||
approvalWorkflowId CHAR(22) BINARY DEFAULT 'pbworkflow000000000003',
|
||||
PRIMARY KEY ( assetId, revisionDate )
|
||||
)
|
||||
EOARCHIVE
|
||||
|
||||
$db->write(<<EOTOPIC);
|
||||
CREATE TABLE StoryTopic (
|
||||
assetId CHAR(22) BINARY NOT NULL,
|
||||
revisionDate BIGINT NOT NULL,
|
||||
storiesPer INTEGER,
|
||||
storiesShort INTEGER,
|
||||
templateId CHAR(22) BINARY,
|
||||
storyTemplateId CHAR(22) BINARY,
|
||||
PRIMARY KEY ( assetId, revisionDate )
|
||||
)
|
||||
EOTOPIC
|
||||
|
||||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
sub sm_upgradeConfigFiles {
|
||||
my ($session) = @_;
|
||||
print "\tAdding Story Manager to config file... " unless $quiet;
|
||||
my $config = $session->config;
|
||||
$config->addToHash(
|
||||
'assets',
|
||||
'WebGUI::Asset::Wobject::StoryTopic' => {
|
||||
'category' => 'community'
|
||||
},
|
||||
);
|
||||
$config->addToHash(
|
||||
'assets',
|
||||
"WebGUI::Asset::Wobject::StoryArchive" => {
|
||||
"isContainer" => 1,
|
||||
"category" => "community"
|
||||
},
|
||||
);
|
||||
my $activities = $config->get('workflowActivities');
|
||||
my $none = $activities->{None};
|
||||
if (!isIn('WebGUI::Workflow::Activity::ArchiveOldStories', @{ $none })) {
|
||||
unshift @{ $none }, 'WebGUI::Workflow::Activity::ArchiveOldStories';
|
||||
}
|
||||
$config->set('workflowActivities', $activities);
|
||||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
sub sm_updateDailyWorkflow {
|
||||
my ($session) = @_;
|
||||
print "\tAdding Archive Old Stories to Daily Workflow... " unless $quiet;
|
||||
my $workflow = WebGUI::Workflow->new($session, 'pbworkflow000000000001');
|
||||
foreach my $activity (@{ $workflow->getActivities }) {
|
||||
return if $activity->getName() eq 'WebGUI::Workflow::Activity::ArchiveOldStories';
|
||||
}
|
||||
my $activity = $workflow->addActivity('WebGUI::Workflow::Activity::ArchiveOldStories');
|
||||
$activity->set('title', 'Archive Old Stories');
|
||||
$activity->set('description', 'Archive old stories, based on the settings of the Story Archives that own them');
|
||||
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;
|
||||
|
||||
# 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 = WebGUI::Asset->getImportNode($session)->importPackage( $storage );
|
||||
|
||||
# Make the package not a package anymore
|
||||
$package->update({ isPackage => 0 });
|
||||
|
||||
# Set the default flag for templates added
|
||||
my $assetIds
|
||||
= $package->getLineage( ['self','descendants'], {
|
||||
includeOnlyClasses => [ 'WebGUI::Asset::Template' ],
|
||||
} );
|
||||
for my $assetId ( @{ $assetIds } ) {
|
||||
my $asset = WebGUI::Asset->newByDynamicClass( $session, $assetId );
|
||||
if ( !$asset ) {
|
||||
print "Couldn't instantiate asset with ID '$assetId'. Please check package '$file' for corruption.\n";
|
||||
next;
|
||||
}
|
||||
$asset->update( { isDefault => 1 } );
|
||||
}
|
||||
|
||||
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',".$session->datetime->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
|
||||
|
|
@ -493,6 +493,9 @@
|
|||
"WebGUI::Asset::Wobject::DataForm" : {
|
||||
"category" : "basic"
|
||||
},
|
||||
"WebGUI::Asset::Sku::Ad" : {
|
||||
"category" : "shop"
|
||||
},
|
||||
"WebGUI::Asset::Sku::Donation" : {
|
||||
"category" : "shop"
|
||||
},
|
||||
|
|
@ -819,6 +822,7 @@
|
|||
"WebGUI::Workflow::Activity::NotifyAdminsWithOpenVersionTags",
|
||||
"WebGUI::Workflow::Activity::PurgeOldAssetRevisions",
|
||||
"WebGUI::Workflow::Activity::PurgeOldTrash",
|
||||
"WebGUI::Workflow::Activity::RemoveOldCarts",
|
||||
"WebGUI::Workflow::Activity::SendQueuedMailMessages",
|
||||
"WebGUI::Workflow::Activity::SummarizePassiveProfileLog",
|
||||
"WebGUI::Workflow::Activity::SyncProfilesToLdap",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package WebGUI;
|
||||
|
||||
|
||||
our $VERSION = '7.7.0';
|
||||
our $VERSION = '7.7.3';
|
||||
our $STATUS = 'beta';
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ sub appendCommonVars {
|
|||
my $self = shift;
|
||||
my $var = shift;
|
||||
my $session = $self->session;
|
||||
my $user = $session->user;
|
||||
my $user = $self->getUser;
|
||||
|
||||
$var->{'user_full_name' } = $user->getWholeName;
|
||||
$var->{'user_member_since'} = $user->dateCreated;
|
||||
|
|
@ -242,7 +242,9 @@ sub editSettingsFormSave {
|
|||
|
||||
=head2 getLayoutTemplateId ( )
|
||||
|
||||
Override this method to return the template Id for the account layout.
|
||||
Override this method to return the template Id for the account layout. The default
|
||||
account layout draws a tabbed interface to the different account plugins, and displays
|
||||
the content from a particular screen from the account plugin.
|
||||
|
||||
=cut
|
||||
|
||||
|
|
@ -253,9 +255,10 @@ sub getLayoutTemplateId {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getStyleTemplate ( )
|
||||
=head2 getStyleTemplateId ( )
|
||||
|
||||
Override this method to return the template for the main style.
|
||||
Override this method to return the template for the main style. The style would
|
||||
be for the page that the account layout template is embedded in.
|
||||
|
||||
=cut
|
||||
|
||||
|
|
@ -278,8 +281,8 @@ the current module and do values will be used.
|
|||
|
||||
=head3 appendUID
|
||||
|
||||
If this flag is set and uid is passed along the url, the uid passed in will be
|
||||
appended to the end of it to the end of the url
|
||||
If this flag is set and uid is passed as a URL param, that uid will be
|
||||
appended to the end of the url.
|
||||
|
||||
=cut
|
||||
|
||||
|
|
@ -289,8 +292,8 @@ sub getUrl {
|
|||
my $appendUID = shift;
|
||||
|
||||
my $session = $self->session;
|
||||
my $form = $session->form;
|
||||
|
||||
my $uid = $self->uid;
|
||||
if($pairs) {
|
||||
#Append op=account to the url if it doesn't already exist
|
||||
unless ($pairs =~ m/op=account/){
|
||||
|
|
@ -301,7 +304,6 @@ sub getUrl {
|
|||
$pairs = q{op=account;module=}.$self->module.q{;do=}.$self->method;
|
||||
}
|
||||
|
||||
my $uid = $self->uid;
|
||||
$pairs .= ";uid=".$uid if($appendUID && $uid);
|
||||
|
||||
return $session->url->page($pairs);
|
||||
|
|
@ -309,6 +311,25 @@ sub getUrl {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getUser
|
||||
|
||||
Gets the user, either specified by the uid URL parameter, or the
|
||||
session user.
|
||||
|
||||
=cut
|
||||
|
||||
sub getUser {
|
||||
my $self = shift;
|
||||
if ($self->uid) {
|
||||
return WebGUI::User->new($self->session, $self->uid);
|
||||
}
|
||||
else {
|
||||
return $self->session->user;
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 new ( session, module [,method ,uid] )
|
||||
|
||||
Constructor.
|
||||
|
|
|
|||
|
|
@ -226,12 +226,6 @@ sub www_view {
|
|||
$self->appendCommonVars($var);
|
||||
$p->appendTemplateVars($var);
|
||||
|
||||
#Overwrite these
|
||||
my $user = WebGUI::User->new($session,$userId);
|
||||
$var->{'user_full_name' } = $user->getWholeName;
|
||||
$var->{'user_member_since' } = $user->dateCreated;
|
||||
|
||||
|
||||
return $self->processTemplate($var,$self->getViewTemplateId);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ sub getLayoutTemplateId {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getConfirmTemplateId ( )
|
||||
=head2 getRemoveConfirmTemplateId ( )
|
||||
|
||||
This method returns the template ID for the confirmation screen.
|
||||
|
||||
|
|
@ -484,17 +484,13 @@ sub www_view {
|
|||
my $var = {};
|
||||
|
||||
my $uid = $self->uid;
|
||||
my $user = ($uid) ? WebGUI::User->new($session,$uid) : $session->user;
|
||||
my $user = $self->getUser;
|
||||
|
||||
$self->appendCommonVars($var);
|
||||
|
||||
my $displayView = $uid ne "";
|
||||
$var->{'display_message'} = $msg;
|
||||
|
||||
#Override these
|
||||
$var->{'user_full_name' } = $user->getWholeName;
|
||||
$var->{'user_member_since' } = $user->dateCreated;
|
||||
|
||||
unless ($user->profileField('ableToBeFriend') && $user->profileIsViewable($session->user)) {
|
||||
my $i18n = WebGUI::International->new($session,"Account_Friends");
|
||||
my $errorMsg = "";
|
||||
|
|
|
|||
|
|
@ -107,13 +107,13 @@ sub appendCommonVars {
|
|||
my $self = shift;
|
||||
my $var = shift;
|
||||
my $session = $self->session;
|
||||
my $user = $session->user;
|
||||
my $user = $self->getUser;
|
||||
my $pageUrl = $session->url->page;
|
||||
|
||||
$self->SUPER::appendCommonVars($var);
|
||||
|
||||
$var->{'edit_profile_url' } = $self->getUrl("module=profile;do=edit");
|
||||
$var->{'invitations_enabled' } = $session->user->profileField('ableToBeFriend');
|
||||
$var->{'invitations_enabled' } = $user->profileField('ableToBeFriend');
|
||||
$var->{'profile_category_loop'} = [];
|
||||
|
||||
#Append the categories
|
||||
|
|
@ -475,10 +475,6 @@ sub www_view {
|
|||
|
||||
$self->appendCommonVars($var);
|
||||
|
||||
#Overwrite these
|
||||
$var->{'user_full_name' } = $user->getWholeName;
|
||||
$var->{'user_member_since' } = $user->dateCreated;
|
||||
$var->{'profile_user_id' } = $user->userId;
|
||||
$var->{'can_edit_profile' } = $uid eq $session->user->userId;
|
||||
|
||||
#Check user privileges
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ These methods are available from this class:
|
|||
|
||||
=head2 canView ( )
|
||||
|
||||
Returns whether or not the user can view the the tab for this module
|
||||
Returns whether or not the user can view the the tab for this module
|
||||
|
||||
=cut
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ sub canView {
|
|||
|
||||
=head2 editSettingsForm ( )
|
||||
|
||||
Creates form elements for user settings page custom to this account module
|
||||
Creates form elements for user settings page custom to this account module
|
||||
|
||||
=cut
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ sub editSettingsForm {
|
|||
|
||||
=head2 editSettingsFormSave ( )
|
||||
|
||||
Creates form elements for the settings page custom to this account module
|
||||
Save form elements from the settings.
|
||||
|
||||
=cut
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use strict;
|
|||
use WebGUI::AdSpace;
|
||||
use WebGUI::Macro;
|
||||
use WebGUI::Storage;
|
||||
use WebGUI::AssetCollateral::Sku::Ad::Ad;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
|
|
@ -81,6 +82,12 @@ Deletes this ad.
|
|||
|
||||
sub delete {
|
||||
my $self = shift;
|
||||
my $iterator = WebGUI::AssetCollateral::Sku::Ad::Ad->getAllIterator($self->session,{
|
||||
constraints => [ { "adSkuPurchase.adId = ?" => $self->getId } ],
|
||||
});
|
||||
while( my $object = $iterator->() ) {
|
||||
$object->update({'isDeleted' => 1});
|
||||
}
|
||||
my $storage = WebGUI::Storage->get($self->session, $self->get("storageId"));
|
||||
$storage->delete if defined $storage;
|
||||
$self->session->db->deleteRow("advertisement","adId",$self->getId);
|
||||
|
|
|
|||
|
|
@ -930,7 +930,7 @@ sub getEditForm {
|
|||
label => $i18n->get('keywords'),
|
||||
hoverHelp => $i18n->get('keywords help'),
|
||||
value => $self->get('keywords'),
|
||||
fieldType => 'text',
|
||||
fieldType => 'keywords',
|
||||
tab => 'meta',
|
||||
}
|
||||
);
|
||||
|
|
@ -2340,9 +2340,9 @@ sub update {
|
|||
# next unless (exists $properties->{$property} || exists $definition->{properties}{$property}{defaultValue});
|
||||
# skip a property unless it was specified to be set by the properties field
|
||||
next unless (exists $properties->{$property});
|
||||
|
||||
my $propertyDefinition = $definition->{properties}{$property};
|
||||
# skip a property if it has the display only flag set
|
||||
next if ($definition->{properties}{$property}{displayOnly});
|
||||
next if ($propertyDefinition->{displayOnly});
|
||||
|
||||
# skip properties that aren't yet in the table
|
||||
if (!exists $tableFields{$property}) {
|
||||
|
|
@ -2358,14 +2358,16 @@ sub update {
|
|||
}
|
||||
|
||||
# apply filter logic on a property to validate or fix it's value
|
||||
if (exists $definition->{properties}{$property}{filter}) {
|
||||
my $filter = $definition->{properties}{$property}{filter};
|
||||
$value = $self->$filter($value, $property);
|
||||
}
|
||||
if (exists $propertyDefinition->{filter}) {
|
||||
my $filter = $propertyDefinition->{filter};
|
||||
$value = $self->$filter($value, $property);
|
||||
}
|
||||
|
||||
# use the default value because default and update were both undef
|
||||
if ($value eq "" && exists $definition->{properties}{$property}{defaultValue}) {
|
||||
$value = $definition->{properties}{$property}{defaultValue};
|
||||
# if the value is undefined, use the default if possible
|
||||
# unless allowEmpty has been set, do this for empty strings as well
|
||||
if ( ( !defined $value || ( $value eq q{} && ! $propertyDefinition->{allowEmpty} ) )
|
||||
&& exists $propertyDefinition->{defaultValue} ) {
|
||||
$value = $propertyDefinition->{defaultValue};
|
||||
if (ref($value) eq 'ARRAY') {
|
||||
$value = $value->[0];
|
||||
}
|
||||
|
|
@ -2606,6 +2608,11 @@ NOTE: Don't try to override or overload this method. It won't work. What you are
|
|||
|
||||
sub www_editSave {
|
||||
my $self = shift;
|
||||
|
||||
my $annotations = "";
|
||||
if ($self->isa("WebGUI::Asset::File::Image")) {
|
||||
$annotations = $self->get("annotations");
|
||||
}
|
||||
##If this is a new asset (www_add), the parent may be locked. We should still be able to add a new asset.
|
||||
my $isNewAsset = $self->session->form->process("assetId") eq "new" ? 1 : 0;
|
||||
return $self->session->privilege->locked() if (!$self->canEditIfLocked and !$isNewAsset);
|
||||
|
|
@ -2644,6 +2651,12 @@ sub www_editSave {
|
|||
}
|
||||
}
|
||||
|
||||
if ($self->isa("WebGUI::Asset::File::Image")) {
|
||||
$object->update({ annotations => $annotations });
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
$object->updateHistory("edited");
|
||||
|
||||
# we handle auto commit assets here in case they didn't handle it themselves
|
||||
|
|
|
|||
|
|
@ -245,7 +245,6 @@ sub getEditFormUploadControl {
|
|||
return $html;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub getFileUrl {
|
||||
my $self = shift;
|
||||
|
|
@ -559,10 +558,11 @@ sub www_edit {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
|
||||
sub www_view {
|
||||
my $self = shift;
|
||||
return $self->session->privilege->noAccess() unless $self->canView;
|
||||
|
||||
|
||||
# Check to make sure it's not in the trash or some other weird place
|
||||
if ($self->get("state") ne "published") {
|
||||
my $i18n = WebGUI::International->new($self->session,'Asset_File');
|
||||
|
|
|
|||
|
|
@ -112,6 +112,10 @@ sub definition {
|
|||
fieldType => 'textarea',
|
||||
defaultValue => 'style="border-style:none;"',
|
||||
},
|
||||
annotations => {
|
||||
fieldType => 'textarea',
|
||||
defaultValue => '',
|
||||
},
|
||||
},
|
||||
};
|
||||
return $class->SUPER::definition($session,$definition);
|
||||
|
|
@ -236,17 +240,32 @@ sub view {
|
|||
return $out if $out;
|
||||
}
|
||||
my %var = %{$self->get};
|
||||
my ($crop_js, $domMe) = $self->annotate_js({ just_image => 1 });
|
||||
|
||||
if ($crop_js) {
|
||||
my ($style, $url) = $self->session->quick(qw(style url));
|
||||
|
||||
$style->setLink($url->extras('yui/build/fonts/fonts-min.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
$style->setLink($url->extras('yui/container/assets/container.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
$style->setScript($url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/container/container-min.js'), {type=>'text/javascript'});
|
||||
}
|
||||
|
||||
$var{controls} = $self->getToolbar;
|
||||
$var{fileUrl} = $self->getFileUrl;
|
||||
$var{fileIcon} = $self->getFileIconUrl;
|
||||
$var{thumbnail} = $self->getThumbnailUrl;
|
||||
my $out = $self->processTemplate(\%var,undef,$self->{_viewTemplate});
|
||||
$var{annotateJs} = "$crop_js$domMe";
|
||||
$var{parameters} = sprintf("id=%s", $self->getId());
|
||||
my $form = $self->session->form;
|
||||
my $out = $self->processTemplate(\%var,undef,$self->{_viewTemplate});
|
||||
if (!$self->session->var->isAdminOn && $self->get("cacheTimeout") > 10) {
|
||||
WebGUI::Cache->new($self->session,"view_".$self->getId)->set($out,$self->get("cacheTimeout"));
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 setFile ( filename )
|
||||
|
|
@ -268,6 +287,10 @@ sub www_edit {
|
|||
return $self->session->privilege->locked() unless $self->canEditIfLocked;
|
||||
my $i18n = WebGUI::International->new($self->session, 'Asset_Image');
|
||||
$self->getAdminConsole->addSubmenuItem($self->getUrl('func=resize'),$i18n->get("resize image")) if ($self->get("filename"));
|
||||
$self->getAdminConsole->addSubmenuItem($self->getUrl('func=rotate'),$i18n->get("rotate image")) if ($self->get("filename"));
|
||||
$self->getAdminConsole->addSubmenuItem($self->getUrl('func=crop'),$i18n->get("crop image")) if ($self->get("filename"));
|
||||
$self->getAdminConsole->addSubmenuItem($self->getUrl('func=annotate'),$i18n->get("annotate image")) if ($self->get("filename"));
|
||||
$self->getAdminConsole->addSubmenuItem($self->getUrl('func=undo'),$i18n->get("undo image")) if ($self->get("filename"));
|
||||
my $tabform = $self->getEditForm;
|
||||
$tabform->getTab("display")->template(
|
||||
-value=>$self->get("templateId"),
|
||||
|
|
@ -278,6 +301,283 @@ sub www_edit {
|
|||
return $self->getAdminConsole->render($tabform->print,$i18n->get("edit image"));
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub www_undo {
|
||||
my $self = shift;
|
||||
my $previous = (@{$self->getRevisions()})[1];
|
||||
# instantiate assetId
|
||||
if ($previous) {
|
||||
# my $session = $self->session;
|
||||
|
||||
# my $cache = WebGUI::Cache->new($self->session, ["asset",$self->getId,$self->getRevisionDate]);
|
||||
# $cache->flush;
|
||||
# my $cache = WebGUI::Cache->new($previous->session, ["asset",$previous->getId,$previous->getRevisionDate]);
|
||||
# $cache->flush;
|
||||
|
||||
$self = $self->purgeRevision();
|
||||
# $self = undef;
|
||||
# $self = WebGUI::Asset->new($previous->session, $previous->getId, ref $previous, $previous->getRevisionDate);
|
||||
$self = $previous;
|
||||
$self->generateThumbnail;
|
||||
}
|
||||
return $self->www_edit();
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#
|
||||
# All of the images will have to change to support annotate.
|
||||
# The revision system doesn't support the blobs, it seems.
|
||||
# All of the image operations will have to be updated to support annotations.
|
||||
#
|
||||
|
||||
sub www_annotate {
|
||||
my $self = shift;
|
||||
return $self->session->privilege->insufficient() unless $self->canEdit;
|
||||
return $self->session->privilege->locked() unless $self->canEditIfLocked;
|
||||
if (1) {
|
||||
my $newSelf = $self->addRevision();
|
||||
delete $newSelf->{_storageLocation};
|
||||
$newSelf->getStorageLocation->annotate($newSelf->get("filename"),$newSelf,$newSelf->session->form);
|
||||
$newSelf->setSize($newSelf->getStorageLocation->getFileSize($newSelf->get("filename")));
|
||||
$self = $newSelf;
|
||||
$self->generateThumbnail;
|
||||
}
|
||||
|
||||
my ($style, $url) = $self->session->quick(qw(style url));
|
||||
# $style->setLink($url->extras('annotate/imageMap.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
|
||||
$style->setLink($url->extras('yui/build/resize/assets/skins/sam/resize.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
$style->setLink($url->extras('yui/build/fonts/fonts-min.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
$style->setLink($url->extras('yui/build/imagecropper/assets/skins/sam/imagecropper.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
|
||||
$style->setScript($url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/element/element-beta-min.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/dragdrop/dragdrop-min.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/resize/resize-min.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/imagecropper/imagecropper-beta-min.js'), {type=>'text/javascript'});
|
||||
|
||||
# my $imageAsset = $self->session->db->getRow("ImageAsset","assetId",$self->getId);
|
||||
|
||||
my @pieces = split(/\n/, $self->get('annotations'));
|
||||
# my ($top_left, $width_height, $note) = split(/\n/, $imageAsset->{annotations});
|
||||
|
||||
my ($img_null, $tooltip_block, $tooltip_none) = ('', '', '');
|
||||
for (my $i = 0; $i < $#pieces; $i += 3) {
|
||||
$img_null .= "YAHOO.img.container.tt$i = null;\n";
|
||||
$tooltip_block .= "YAHOO.util.Dom.setStyle('tooltip$i', 'display', 'block');\n";
|
||||
$tooltip_none .= "YAHOO.util.Dom.setStyle('tooltip$i', 'display', 'none');\n";
|
||||
my $j = $i + 2;
|
||||
# warn("i: $i: ", $self->session->form->process("delAnnotate$i"));
|
||||
}
|
||||
|
||||
my $image = '<div align="center" class="yui-skin-sam"><img src="'.$self->getStorageLocation->getUrl($self->get("filename")).'" style="border-style:none;" alt="'.$self->get("filename").'" id="yui_img" /></div>';
|
||||
|
||||
my ($width, $height) = $self->getStorageLocation->getSize($self->get("filename"));
|
||||
|
||||
my @checkboxes = ();
|
||||
my $i18n = WebGUI::International->new($self->session,"Asset_Image");
|
||||
my $f = WebGUI::HTMLForm->new($self->session,-action=>$self->getUrl);
|
||||
|
||||
$self->getAdminConsole->addSubmenuItem($self->getUrl('func=edit'),$i18n->get("edit image"));
|
||||
$f->hidden(
|
||||
-name=>"func",
|
||||
-value=>"annotate"
|
||||
);
|
||||
$f->text(
|
||||
-label=>$i18n->get('annotate image'),
|
||||
-value=>'',
|
||||
-hoverHelp=>$i18n->get('annotate image description'),
|
||||
-name=>'annotate_text'
|
||||
);
|
||||
$f->integer(
|
||||
-label=>$i18n->get('top'),
|
||||
-name=>"annotate_top",
|
||||
-value=>,
|
||||
);
|
||||
$f->integer(
|
||||
-label=>$i18n->get('left'),
|
||||
-name=>"annotate_left",
|
||||
-value=>,
|
||||
);
|
||||
$f->integer(
|
||||
-label=>$i18n->get('width'),
|
||||
-name=>"annotate_width",
|
||||
-value=>,
|
||||
);
|
||||
$f->integer(
|
||||
-label=>$i18n->get('height'),
|
||||
-name=>"annotate_height",
|
||||
-value=>,
|
||||
);
|
||||
$f->button(
|
||||
-value=>$i18n->get('annotate'),
|
||||
-extras=>'onclick="switchState();"',
|
||||
);
|
||||
$f->submit;
|
||||
my ($crop_js, $domMe) = $self->annotate_js();
|
||||
return $self->getAdminConsole->render($f->print."$image$crop_js$domMe",$i18n->get("annotate image"));
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub annotate_js {
|
||||
my $self = shift;
|
||||
my $opts = shift;
|
||||
|
||||
my @pieces = split(/\n/, $self->get('annotations'));
|
||||
|
||||
# warn("pieces: $#pieces: ". $self->getId());
|
||||
return "" if !@pieces && $opts->{just_image};
|
||||
|
||||
my ($img_null, $tooltip_block, $tooltip_none) = ('', '', '');
|
||||
for (my $i = 0; $i < $#pieces; $i += 3) {
|
||||
$img_null .= "YAHOO.img.container.tt$i = null;\n";
|
||||
$tooltip_block .= "YAHOO.util.Dom.setStyle('tooltip$i', 'display', 'block');\n";
|
||||
$tooltip_none .= "YAHOO.util.Dom.setStyle('tooltip$i', 'display', 'none');\n";
|
||||
my $j = $i + 2;
|
||||
# warn("i: $i: ", $self->session->form->process("delAnnotate$i"));
|
||||
}
|
||||
|
||||
my $id = $$opts{just_image} ? $self->getId : "yui_img";
|
||||
|
||||
my $crop_js = qq(
|
||||
<script type="text/javascript">
|
||||
var crop;
|
||||
function switchState() {
|
||||
$img_null
|
||||
|
||||
if (crop) {
|
||||
crop.destroy();
|
||||
crop = null;
|
||||
$tooltip_block
|
||||
}
|
||||
else {
|
||||
crop = new YAHOO.widget.ImageCropper('$id', {
|
||||
initialXY: [20, 20],
|
||||
keyTick: 5,
|
||||
shiftKeyTick: 50
|
||||
});
|
||||
crop.on('moveEvent', function() {
|
||||
var region = crop.getCropCoords();
|
||||
element = document.getElementById('annotate_width_formId');
|
||||
element.value = region.width;
|
||||
element = document.getElementById('annotate_height_formId');
|
||||
element.value = region.height;
|
||||
element = document.getElementById('annotate_top_formId');
|
||||
element.value = region.top;
|
||||
element = document.getElementById('annotate_left_formId');
|
||||
element.value = region.left;
|
||||
});
|
||||
$tooltip_none
|
||||
}
|
||||
}
|
||||
</script>
|
||||
);
|
||||
|
||||
my $hotspots = '';
|
||||
my $domMe = '';
|
||||
|
||||
for (my $i = 0; $i < $#pieces; $i += 3) {
|
||||
my $top_left = $pieces[$i];
|
||||
my $width_height = $pieces[$i + 1];
|
||||
my $note = $pieces[$i + 2];
|
||||
|
||||
if ($top_left =~ /top: (\d+)px; left: (\d+)px;/) {
|
||||
$top_left = "xy[0]+$1, xy[1]+$2";
|
||||
}
|
||||
|
||||
my ($width, $height) = ("", "");
|
||||
if ($width_height =~ /width: (\d+)px; height: (\d+)px;/) {
|
||||
($width, $height) = ("$1px", "$2px");
|
||||
}
|
||||
|
||||
# next if 3 == $i;
|
||||
|
||||
warn('next');
|
||||
$domMe .= qq(
|
||||
<style type="text/css">
|
||||
div#tooltip$i { position: absolute; border:1px solid; }
|
||||
</style>
|
||||
|
||||
<span id=span_tooltip$i>
|
||||
</span>
|
||||
|
||||
<script type="text/javascript">
|
||||
function on_load_$i() {
|
||||
var xy = YAHOO.util.Dom.getXY('$id');
|
||||
|
||||
document.getElementById('span_tooltip$i').innerHTML = "<div id=tooltip$i style='border:1px solid;'></div>";
|
||||
YAHOO.util.Dom.setStyle('tooltip$i', 'display', 'block');
|
||||
YAHOO.util.Dom.setStyle('tooltip$i', 'height', '$height');
|
||||
YAHOO.util.Dom.setStyle('tooltip$i', 'width', '$width');
|
||||
YAHOO.util.Dom.setXY('span_tooltip$i', [$top_left]);
|
||||
YAHOO.util.Dom.setXY('tooltip$i', [$top_left]);
|
||||
|
||||
YAHOO.namespace("img.container");
|
||||
YAHOO.img.container.tt$i = new YAHOO.widget.Tooltip("tt$i", { showdelay: 0, visible: true, context:"tooltip$i", position:"relative", container:"tooltip$i", text:"$note" });
|
||||
}
|
||||
if (document.addEventListener) {
|
||||
document.addEventListener("DOMContentLoaded", on_load_$i, false);
|
||||
}
|
||||
else if (window.attachEvent){
|
||||
window.attachEvent('onload', on_load_$i);
|
||||
}
|
||||
|
||||
</script>
|
||||
);
|
||||
}
|
||||
|
||||
return($crop_js, $domMe);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub www_rotate {
|
||||
my $self = shift;
|
||||
return $self->session->privilege->insufficient() unless $self->canEdit;
|
||||
return $self->session->privilege->locked() unless $self->canEditIfLocked;
|
||||
# warn(sprintf("Rotate_formId: %s", $self->session->form->process("Rotate")));
|
||||
if (defined $self->session->form->process("Rotate")) {
|
||||
my $newSelf = $self->addRevision();
|
||||
delete $newSelf->{_storageLocation};
|
||||
$newSelf->getStorageLocation->rotate($newSelf->get("filename"),$newSelf->session->form->process("Rotate"));
|
||||
$newSelf->setSize($newSelf->getStorageLocation->getFileSize($newSelf->get("filename")));
|
||||
$self = $newSelf;
|
||||
$self->generateThumbnail;
|
||||
}
|
||||
|
||||
my ($x, $y) = $self->getStorageLocation->getSizeInPixels($self->get("filename"));
|
||||
|
||||
##YUI specific datatable CSS
|
||||
my ($style, $url) = $self->session->quick(qw(style url));
|
||||
|
||||
my $img_name = $self->getStorageLocation->getUrl($self->get("filename"));
|
||||
my $img_file = $self->get("filename");
|
||||
my $image = '<div align="center" class="yui-skin-sam"><img src="'.$self->getStorageLocation->getUrl($self->get("filename")).'" style="border-style:none;" alt="'.$self->get("filename").'" id="yui_img" /></div>';
|
||||
|
||||
my $i18n = WebGUI::International->new($self->session,"Asset_Image");
|
||||
$self->getAdminConsole->addSubmenuItem($self->getUrl('func=edit'),$i18n->get("edit image"));
|
||||
my $f = WebGUI::HTMLForm->new($self->session,-action=>$self->getUrl);
|
||||
$f->hidden(
|
||||
-name=>"func",
|
||||
-value=>"rotate"
|
||||
);
|
||||
$f->button(
|
||||
-value=>"Left",
|
||||
-extras=>qq(onclick="var deg = document.getElementById('Rotate_formId').value; deg = parseInt(deg) + 90; document.getElementById('Rotate_formId').value = deg;"),
|
||||
);
|
||||
$f->button(
|
||||
-value=>"Right",
|
||||
-extras=>qq(onclick="var deg = document.getElementById('Rotate_formId').value; deg = parseInt(deg) - 90; document.getElementById('Rotate_formId').value = deg;"),
|
||||
);
|
||||
$f->integer(
|
||||
-label=>$i18n->get('degree'),
|
||||
-name=>"Rotate",
|
||||
-value=>0,
|
||||
);
|
||||
$f->submit;
|
||||
return $self->getAdminConsole->render($f->print.$image,$i18n->get("rotate image"));
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub www_resize {
|
||||
my $self = shift;
|
||||
|
|
@ -289,7 +589,59 @@ sub www_resize {
|
|||
$newSelf->getStorageLocation->resize($newSelf->get("filename"),$newSelf->session->form->process("newWidth"),$newSelf->session->form->process("newHeight"));
|
||||
$newSelf->setSize($newSelf->getStorageLocation->getFileSize($newSelf->get("filename")));
|
||||
$self = $newSelf;
|
||||
$self->generateThumbnail;
|
||||
}
|
||||
|
||||
my ($x, $y) = $self->getStorageLocation->getSizeInPixels($self->get("filename"));
|
||||
|
||||
##YUI specific datatable CSS
|
||||
my ($style, $url) = $self->session->quick(qw(style url));
|
||||
|
||||
$style->setLink($url->extras('yui/build/fonts/fonts-min.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
$style->setLink($url->extras('yui/build/resize/assets/skins/sam/resize.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
$style->setScript($url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/element/element-beta-min.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/dragdrop/dragdrop-min.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/resize/resize-min.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/animation/animation-min.js'), {type=>'text/javascript'});
|
||||
|
||||
my $resize_js = qq(
|
||||
<script>
|
||||
(function() {
|
||||
var Dom = YAHOO.util.Dom,
|
||||
Event = YAHOO.util.Event;
|
||||
|
||||
var resize = new YAHOO.util.Resize('yui_img', {
|
||||
handles: 'all',
|
||||
knobHandles: true,
|
||||
height: '${x}px',
|
||||
width: '${y}px',
|
||||
proxy: true,
|
||||
ghost: true,
|
||||
status: true,
|
||||
draggable: false,
|
||||
ratio: true,
|
||||
animate: true,
|
||||
animateDuration: .75,
|
||||
animateEasing: YAHOO.util.Easing.backBoth
|
||||
});
|
||||
|
||||
resize.on('startResize', function() {
|
||||
this.getProxyEl().innerHTML = '<img src="' + this.get('element').src + '" style="height: 100%; width: 100%;">';
|
||||
Dom.setStyle(this.getProxyEl().firstChild, 'opacity', '.25');
|
||||
}, resize, true);
|
||||
|
||||
resize.on('resize', function(e) {
|
||||
element = document.getElementById('newWidth_formId');
|
||||
element.value = e.width;
|
||||
|
||||
element = document.getElementById('newHeight_formId');
|
||||
element.value = e.height;
|
||||
}, resize, true);
|
||||
})();
|
||||
</script>
|
||||
);
|
||||
|
||||
my $i18n = WebGUI::International->new($self->session,"Asset_Image");
|
||||
$self->getAdminConsole->addSubmenuItem($self->getUrl('func=edit'),$i18n->get("edit image"));
|
||||
my $f = WebGUI::HTMLForm->new($self->session,-action=>$self->getUrl);
|
||||
|
|
@ -297,7 +649,6 @@ sub www_resize {
|
|||
-name=>"func",
|
||||
-value=>"resize"
|
||||
);
|
||||
my ($x, $y) = $self->getStorageLocation->getSizeInPixels($self->get("filename"));
|
||||
$f->readOnly(
|
||||
-label=>$i18n->get('image size'),
|
||||
-hoverHelp=>$i18n->get('image size description'),
|
||||
|
|
@ -316,15 +667,121 @@ sub www_resize {
|
|||
-value=>$y,
|
||||
);
|
||||
$f->submit;
|
||||
my $image = '<div align="center"><img src="'.$self->getStorageLocation->getUrl($self->get("filename")).'" style="border-style:none;" alt="'.$self->get("filename").'" /></div>';
|
||||
my $image = '<div align="center" class="yui-skin-sam"><img src="'.$self->getStorageLocation->getUrl($self->get("filename")).'" style="border-style:none;" alt="'.$self->get("filename").'" id="yui_img" /></div>'.$resize_js;
|
||||
return $self->getAdminConsole->render($f->print.$image,$i18n->get("resize image"));
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub www_crop {
|
||||
my $self = shift;
|
||||
return $self->session->privilege->insufficient() unless $self->canEdit;
|
||||
return $self->session->privilege->locked() unless $self->canEditIfLocked;
|
||||
|
||||
if ($self->session->form->process("Width") || $self->session->form->process("Height")
|
||||
|| $self->session->form->process("Top") || $self->session->form->process("Left")) {
|
||||
my $newSelf = $self->addRevision();
|
||||
delete $newSelf->{_storageLocation};
|
||||
$newSelf->getStorageLocation->crop(
|
||||
$newSelf->get("filename"),
|
||||
$newSelf->session->form->process("Width"),
|
||||
$newSelf->session->form->process("Height"),
|
||||
$newSelf->session->form->process("Top"),
|
||||
$newSelf->session->form->process("Left")
|
||||
);
|
||||
$self = $newSelf;
|
||||
$self->generateThumbnail;
|
||||
}
|
||||
|
||||
my $filename = $self->get("filename");
|
||||
|
||||
##YUI specific datatable CSS
|
||||
my ($style, $url) = $self->session->quick(qw(style url));
|
||||
|
||||
my $crop_js = qq(
|
||||
<script>
|
||||
(function() {
|
||||
var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event, results = null;
|
||||
|
||||
Event.onDOMReady(function() {
|
||||
var crop = new YAHOO.widget.ImageCropper('yui_img', {
|
||||
initialXY: [20, 20],
|
||||
keyTick: 5,
|
||||
shiftKeyTick: 50
|
||||
});
|
||||
crop.on('moveEvent', function() {
|
||||
var region = crop.getCropCoords();
|
||||
element = document.getElementById('Width_formId');
|
||||
element.value = region.width;
|
||||
element = document.getElementById('Height_formId');
|
||||
element.value = region.height;
|
||||
element = document.getElementById('Top_formId');
|
||||
element.value = region.top;
|
||||
element = document.getElementById('Left_formId');
|
||||
element.value = region.left;
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
);
|
||||
|
||||
$style->setLink($url->extras('yui/build/resize/assets/skins/sam/resize.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
$style->setLink($url->extras('yui/build/fonts/fonts-min.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
$style->setLink($url->extras('yui/build/imagecropper/assets/skins/sam/imagecropper.css'), {rel=>'stylesheet', type=>'text/css'});
|
||||
$style->setScript($url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/element/element-beta-min.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/dragdrop/dragdrop-min.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/resize/resize-min.js'), {type=>'text/javascript'});
|
||||
$style->setScript($url->extras('yui/build/imagecropper/imagecropper-beta-min.js'), {type=>'text/javascript'});
|
||||
|
||||
my $i18n = WebGUI::International->new($self->session,"Asset_Image");
|
||||
|
||||
$self->getAdminConsole->addSubmenuItem($self->getUrl('func=edit'),$i18n->get("edit image"));
|
||||
my $f = WebGUI::HTMLForm->new($self->session,-action=>$self->getUrl);
|
||||
$f->hidden(
|
||||
-name=>"degree",
|
||||
-value=>"0"
|
||||
);
|
||||
$f->hidden(
|
||||
-name=>"func",
|
||||
-value=>"crop"
|
||||
);
|
||||
my ($x, $y) = $self->getStorageLocation->getSizeInPixels($filename);
|
||||
$f->integer(
|
||||
-label=>$i18n->get('width'),
|
||||
-hoverHelp=>$i18n->get('new width description'),
|
||||
-name=>"Width",
|
||||
-value=>$x,
|
||||
);
|
||||
$f->integer(
|
||||
-label=>$i18n->get('height'),
|
||||
-hoverHelp=>$i18n->get('new height description'),
|
||||
-name=>"Height",
|
||||
-value=>$y,
|
||||
);
|
||||
$f->integer(
|
||||
-label=>$i18n->get('top'),
|
||||
-hoverHelp=>$i18n->get('new width description'),
|
||||
-name=>"Top",
|
||||
-value=>$x,
|
||||
);
|
||||
$f->integer(
|
||||
-label=>$i18n->get('left'),
|
||||
-hoverHelp=>$i18n->get('new height description'),
|
||||
-name=>"Left",
|
||||
-value=>$y,
|
||||
);
|
||||
$f->submit;
|
||||
|
||||
my $image = '<div align="center" class="yui-skin-sam"><img src="'.$self->getStorageLocation->getUrl($filename).'" style="border-style:none;" alt="'.$filename.'" id="yui_img" /></div>'.$crop_js;
|
||||
|
||||
return $self->getAdminConsole->render($f->print.$image,$i18n->get("crop image"));
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Use superclass method for now.
|
||||
sub www_view {
|
||||
my $self = shift;
|
||||
$self->SUPER::www_view;
|
||||
return($self->SUPER::www_view);
|
||||
}
|
||||
|
||||
#sub www_view {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,22 @@ These methods are available from this class:
|
|||
=cut
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 unzip ( $storage, $filename )
|
||||
|
||||
Uncompress and/or expand an archive, based on the file extension of the filename.
|
||||
Returns 1 if the unzip was successful. Returns 0 if there were problems.
|
||||
|
||||
=head3 $storage
|
||||
|
||||
A WebGUI::Storage object containing the archive.
|
||||
|
||||
=head3 $filename
|
||||
|
||||
The filename of the archive.
|
||||
|
||||
=cut
|
||||
|
||||
sub unzip {
|
||||
my $self = shift;
|
||||
my $storage = shift;
|
||||
|
|
@ -78,8 +94,8 @@ sub unzip {
|
|||
|
||||
=head2 addRevision ( )
|
||||
|
||||
This method exists for demonstration purposes only. The superclass
|
||||
handles revisions to ZipArchive Assets.
|
||||
This method exists for demonstration purposes only. The superclass
|
||||
handles revisions to ZipArchive Assets.
|
||||
|
||||
=cut
|
||||
|
||||
|
|
|
|||
|
|
@ -304,6 +304,14 @@ sub getEditForm {
|
|||
-hoverHelp =>$i18n->get("description description"),
|
||||
-value =>$self->getValue('description'),
|
||||
);
|
||||
if ($self->getParent->canEdit) {
|
||||
$form->user(
|
||||
name =>"ownerUserId",
|
||||
value =>$self->getValue('ownerUserId'),
|
||||
label =>$i18n->get('maintainer label'),
|
||||
hoverHelp =>$i18n->get('maintainer description'),
|
||||
);
|
||||
}
|
||||
$form->text(
|
||||
-name =>'version',
|
||||
-defaultValue =>undef,
|
||||
|
|
@ -335,21 +343,17 @@ sub getEditForm {
|
|||
|
||||
foreach my $category (keys %{$self->getParent->getCategories}) {
|
||||
$form->raw('<tr><td colspan="2"><b>'.$category.'</b></td></tr>');
|
||||
my $attributes;
|
||||
if ($session->form->process('func') eq 'add'){
|
||||
$attributes = $db->read("select * from Matrix_attribute where category = ? and assetId = ?",
|
||||
[$category,$matrixId]);
|
||||
}
|
||||
else{
|
||||
$attributes = $db->read("select * from Matrix_attribute as attribute
|
||||
left join MatrixListing_attribute as listing using(attributeId)
|
||||
where listing.matrixListingId = ? and category =? and attribute.assetId = ?",
|
||||
[$self->getId,$category,$matrixId]);
|
||||
}
|
||||
my $attributes = $db->read("select * from Matrix_attribute where category = ? and assetId = ?",
|
||||
[$category,$matrixId]);
|
||||
while (my $attribute = $attributes->hashRef) {
|
||||
$attribute->{label} = $attribute->{name};
|
||||
$attribute->{subtext} = $attribute->{description};
|
||||
$attribute->{name} = 'attribute_'.$attribute->{attributeId};
|
||||
unless($session->form->process('func') eq 'add'){
|
||||
$attribute->{value} = $db->quickScalar("select value from MatrixListing_attribute
|
||||
where attributeId = ? and matrixId = ? and matrixListingId = ?",
|
||||
[$attribute->{attributeId},$matrixId,$self->getId]);
|
||||
}
|
||||
if($attribute->{fieldType} eq 'Combo'){
|
||||
my %options;
|
||||
tie %options, 'Tie::IxHash';
|
||||
|
|
@ -559,7 +563,7 @@ sub setRatings {
|
|||
|
||||
my $half = round($count/2);
|
||||
my $mean = $sum / ($count || 1);
|
||||
my $median = $db->quickScalar("select rating $sql limit $half,$half",[$self->getId,$category]);
|
||||
my $median = $db->quickScalar("select rating $sql order by rating limit $half,1",[$self->getId,$category]);
|
||||
|
||||
$db->write("replace into MatrixListing_ratingSummary
|
||||
(listingId, category, meanValue, medianValue, countValue, assetId)
|
||||
|
|
@ -570,7 +574,7 @@ sub setRatings {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 view ( hasRated )
|
||||
=head2 updateScore ( )
|
||||
|
||||
Updates the score of a MatrixListing.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,205 +0,0 @@
|
|||
package WebGUI::Asset::RSSCapable;
|
||||
|
||||
=head1 LEGAL
|
||||
|
||||
-------------------------------------------------------------------
|
||||
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
|
||||
-------------------------------------------------------------------
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use NEXT;
|
||||
use WebGUI::Asset::RSSFromParent;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
WebGUI::Asset::RSSCapable
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
An extra mixin class to be included before WebGUI::Asset in any asset
|
||||
class that wishes its instances to be capable of generating RSS feeds
|
||||
using the RSSFromParent asset.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use base 'WebGUI::Asset::RSSCapable';
|
||||
|
||||
=cut
|
||||
|
||||
sub definition {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $definition = shift;
|
||||
my %properties;
|
||||
tie %properties, 'Tie::IxHash';
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_RSSCapable');
|
||||
|
||||
# We do this prefixing to avoid name collisions because properties aren't namespaced.
|
||||
%properties =
|
||||
(
|
||||
rssCapableRssEnabled => { tab => 'display',
|
||||
fieldType => 'yesNo',
|
||||
defaultValue => 1,
|
||||
label => $i18n->get('rssEnabled label'),
|
||||
hoverHelp => $i18n->get('rssEnabled hoverHelp')
|
||||
},
|
||||
rssCapableRssTemplateId => { tab => 'display',
|
||||
fieldType => 'template',
|
||||
defaultValue => 'PBtmpl0000000000000142',
|
||||
namespace => 'RSSCapable/RSS',
|
||||
label => $i18n->get('rssTemplateId label'),
|
||||
hoverHelp => $i18n->get('rssTemplateId hoverHelp')
|
||||
},
|
||||
rssCapableRssFromParentId => { fieldType => 'hidden',
|
||||
noFormPost => 1,
|
||||
defaultValue => undef,
|
||||
},
|
||||
);
|
||||
|
||||
push @$definition, { assetName => $i18n->get('assetName'),
|
||||
tableName => 'RSSCapable',
|
||||
autoGenerateForms => 1,
|
||||
className => 'WebGUI::Asset::RSSCapable',
|
||||
icon => 'rssCapable.gif',
|
||||
properties => \%properties
|
||||
};
|
||||
return $class->NEXT::definition($session, $definition);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub _rssFromParentValid {
|
||||
my $self = shift;
|
||||
my $rssFromParentId = $self->get('rssCapableRssFromParentId');
|
||||
return undef unless $rssFromParentId;
|
||||
|
||||
my $rssFromParent = WebGUI::Asset->newByDynamicClass($self->session, $rssFromParentId);
|
||||
return undef unless $rssFromParent;
|
||||
return ($rssFromParent->isa('WebGUI::Asset::RSSFromParent')
|
||||
&& $rssFromParent->getParent->getId eq $self->getId);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub _updateRssFromParentProperties {
|
||||
my $self = shift;
|
||||
my $rssFromParent = WebGUI::Asset->newByDynamicClass($self->session,
|
||||
$self->get('rssCapableRssFromParentId'));
|
||||
$rssFromParent->update({ title => $self->get('title'),
|
||||
menuTitle => $self->get('menuTitle') });
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub _purgeExtraRssFromParentAssets {
|
||||
my $self = shift;
|
||||
my $rssFromParentId = $self->get('rssCapableRssFromParentId');
|
||||
|
||||
foreach my $rssFromParent (@{$self->getLineage(['children'],
|
||||
{returnObjects => 1,
|
||||
includeOnlyClasses =>
|
||||
['WebGUI::Asset::RSSFromParent']})}) {
|
||||
$rssFromParent->purge unless $rssFromParent->getId eq $rssFromParentId;
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub _ensureRssFromParentPresent {
|
||||
my $self = shift;
|
||||
if (!$self->_rssFromParentValid) {
|
||||
# Create a new one.
|
||||
my $rssFromParent = $self->addChild({ className => 'WebGUI::Asset::RSSFromParent',
|
||||
title => $self->get('title'),
|
||||
menuTitle => $self->get('menuTitle'),
|
||||
url => $self->get('url').'.rss'
|
||||
});
|
||||
$self->update({ rssCapableRssFromParentId => $rssFromParent->getId });
|
||||
}
|
||||
|
||||
$self->_updateRssFromParentProperties;
|
||||
$self->_purgeExtraRssFromParentAssets;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub _ensureRssFromParentAbsent {
|
||||
my $self = shift;
|
||||
# Invalidate it, and then it'll get purged along with any others.
|
||||
$self->update({ rssCapableRssFromParentId => undef });
|
||||
$self->_purgeExtraRssFromParentAssets;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub processPropertiesFromFormPost {
|
||||
my $self = shift;
|
||||
my $error = $self->NEXT::processPropertiesFromFormPost(@_);
|
||||
return $error if ref $error eq 'ARRAY';
|
||||
if ($self->get('rssCapableRssEnabled')) {
|
||||
$self->_ensureRssFromParentPresent;
|
||||
} else {
|
||||
$self->_ensureRssFromParentAbsent;
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getRssUrl ( )
|
||||
|
||||
Returns the site-relative URL to the RSS feed for this asset, or undef
|
||||
if there is no such feed.
|
||||
|
||||
=cut
|
||||
|
||||
sub getRssUrl {
|
||||
my $self = shift;
|
||||
my $rssFromParentId = $self->get('rssCapableRssFromParentId');
|
||||
return undef unless $rssFromParentId;
|
||||
my $rssAsset = WebGUI::Asset->newByDynamicClass($self->session, $rssFromParentId);
|
||||
return undef unless $rssAsset;
|
||||
return $rssAsset->getUrl;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getRssItems ( )
|
||||
|
||||
Returns a list of RSS items for a feed corresponding to this asset.
|
||||
Each item may be another asset, or a hash of (properly XMLized)
|
||||
properties for the <item>..</item> tag. Defaults to no items.
|
||||
|
||||
This is the primary method that RSSCapable assets should override.
|
||||
|
||||
=cut
|
||||
|
||||
sub getRssItems { () }
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_viewRSS ( )
|
||||
|
||||
Default www method for methods that return RSS. This will redirect to the getRssUrl unless overridden.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_viewRSS {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
|
||||
my $rssUrl = $self->getRssUrl;
|
||||
|
||||
if($rssUrl) {
|
||||
$session->http->setRedirect($self->getRssUrl);
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
package WebGUI::Asset::RSSFromParent;
|
||||
|
||||
=head1 LEGAL
|
||||
|
||||
-------------------------------------------------------------------
|
||||
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
|
||||
-------------------------------------------------------------------
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use HTML::Entities;
|
||||
use Tie::IxHash;
|
||||
use base 'WebGUI::Asset';
|
||||
use WebGUI::Utility;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Package WebGUI::Asset::RSSFromParent
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Generates an RSS feed from the children/descendants of its parent.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use WebGUI::Asset::RSSFromParent;
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 definition
|
||||
|
||||
=cut
|
||||
|
||||
sub definition {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $definition = shift;
|
||||
my %properties;
|
||||
tie %properties, 'Tie::IxHash';
|
||||
my $i18n = WebGUI::International->new($session, "Asset_RSSFromParent");
|
||||
|
||||
%properties = ();
|
||||
|
||||
push(@{$definition}, {
|
||||
assetName=>$i18n->get('assetName'),
|
||||
icon=>'rssGear.gif',
|
||||
autoGenerateForms=>1,
|
||||
tableName=>'RSSFromParent',
|
||||
className=>'WebGUI::Asset::RSSFromParent',
|
||||
properties=>\%properties
|
||||
});
|
||||
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 update
|
||||
|
||||
=cut
|
||||
|
||||
sub update {
|
||||
# Re-force isHidden to 1 on each update; these should always be hidden.
|
||||
my $self = shift;
|
||||
my $properties = shift;
|
||||
$self->SUPER::update(+{%$properties, isHidden => 1});
|
||||
}
|
||||
|
||||
#------------------------------------------------
|
||||
|
||||
=head2 _escapeXml
|
||||
|
||||
=cut
|
||||
|
||||
sub _escapeXml {
|
||||
my $text = shift;
|
||||
return $text unless (ref $text eq "");
|
||||
return HTML::Entities::encode_numeric($text)
|
||||
}
|
||||
|
||||
#------------------------------------------------
|
||||
|
||||
=head2 _tlsOfAsset
|
||||
|
||||
=cut
|
||||
|
||||
sub _tlsOfAsset {
|
||||
my $self = shift;
|
||||
my $asset = shift;
|
||||
#Fix Title
|
||||
my $title = _escapeXml($asset->get('title'));
|
||||
#Fix Url
|
||||
my $url = _escapeXml($self->session->url->getSiteURL() . $asset->getUrl);
|
||||
#Fix Description
|
||||
my $description = _escapeXml($asset->get('synopsis'));
|
||||
return ($title,$url,$description);
|
||||
}
|
||||
|
||||
#------------------------------------------------
|
||||
|
||||
=head2 {
|
||||
|
||||
=cut
|
||||
|
||||
sub isValidRssItem { 0 }
|
||||
|
||||
#------------------------------------------------
|
||||
|
||||
=head2 displayInFolder2
|
||||
|
||||
=cut
|
||||
|
||||
sub displayInFolder2 { 0 }
|
||||
|
||||
#------------------------------------------------
|
||||
|
||||
=head2 www_view
|
||||
|
||||
=cut
|
||||
|
||||
sub www_view {
|
||||
my $self = shift;
|
||||
return '' unless $self->session->asset->getId eq $self->getId;
|
||||
return '' unless $self->getParent->isa('WebGUI::Asset::RSSCapable');
|
||||
return '' unless $self->getParent->canView; # Go to parent for auth
|
||||
my $parent = $self->getParent;
|
||||
my $template = WebGUI::Asset::Template->new($self->session, $parent->get('rssCapableRssTemplateId'));
|
||||
$template->prepare($self->getMetaDataAsTemplateVariables);
|
||||
$self->session->http->setMimeType('text/xml');
|
||||
|
||||
my $var = {};
|
||||
@$var{'title', 'link', 'description'} = $self->_tlsOfAsset($parent);
|
||||
$var->{'generator'} = "WebGUI $WebGUI::VERSION";
|
||||
$var->{'lastBuildDate'} = $self->session->datetime->epochToMail($parent->getContentLastModified);
|
||||
$var->{'webMaster'} = $self->session->setting->get('companyEmail');
|
||||
$var->{'docs'} = 'http://blogs.law.harvard.edu/tech/rss';
|
||||
|
||||
my @items = $parent->getRssItems;
|
||||
$var->{'item_loop'} = [];
|
||||
my $counter = 0;
|
||||
foreach my $item (@items) {
|
||||
my $subvar = {};
|
||||
|
||||
if (UNIVERSAL::isa($item, 'WebGUI::Asset')) {
|
||||
next unless $item->isValidRssItem;
|
||||
$subvar = {};
|
||||
@$subvar{'title', 'link', 'description'} = $self->_tlsOfAsset($item);
|
||||
$subvar->{guid} = $subvar->{link};
|
||||
$subvar->{pubDate} = _escapeXml($self->session->datetime->epochToMail($item->get('creationDate')));
|
||||
} elsif (ref $item eq 'HASH') {
|
||||
foreach my $key (keys %$item) {
|
||||
$subvar->{$key} = _escapeXml($item->{$key});
|
||||
}
|
||||
} else {
|
||||
$self->session->errorHandler->error("Don't know what to do with this RSS item: $item");
|
||||
next;
|
||||
}
|
||||
$counter++;
|
||||
push @{$var->{'item_loop'}}, $subvar;
|
||||
}
|
||||
|
||||
return $self->processTemplate($var, undef, $template);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -126,14 +126,6 @@ sub view {
|
|||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub www_edit {
|
||||
my $self = shift;
|
||||
return $self->session->privilege->insufficient() unless $self->canEdit;
|
||||
return $self->session->privilege->locked() unless $self->canEditIfLocked;
|
||||
return $self->getAdminConsole->render($self->getEditForm->print, $self->addEditLabel);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_view
|
||||
|
|
|
|||
|
|
@ -448,6 +448,18 @@ sub getToolbar {
|
|||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getRichEditor ( $nameId )
|
||||
|
||||
Return the javascript needed to make the Rich Editor.
|
||||
|
||||
=head3 $nameId
|
||||
|
||||
The id for the rich editor, should be unique enough to be used as the id parameter
|
||||
for a HTML tag.
|
||||
|
||||
=cut
|
||||
|
||||
sub getRichEditor {
|
||||
my $self = shift;
|
||||
return '' if ($self->getValue('disableRichEditor'));
|
||||
|
|
@ -582,6 +594,13 @@ sub indexContent {
|
|||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_edit ( )
|
||||
|
||||
Override the method from Asset.pm to change the title of the screen.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_edit {
|
||||
my $self = shift;
|
||||
return $self->session->privilege->insufficient() unless $self->canEdit;
|
||||
|
|
|
|||
|
|
@ -159,6 +159,27 @@ sub definition {
|
|||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAddToCartForm ( )
|
||||
|
||||
Returns a form to add this Sku to the cart. Used when this Sku is part of
|
||||
a shelf.
|
||||
|
||||
=cut
|
||||
|
||||
sub getAddToCartForm {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_Sku');
|
||||
return
|
||||
WebGUI::Form::formHeader($session, {action => $self->getUrl})
|
||||
. WebGUI::Form::hidden( $session, {name => 'func', value => 'addToCart'})
|
||||
. WebGUI::Form::submit( $session, {value => $i18n->get('add to cart')})
|
||||
. WebGUI::Form::formFooter($session)
|
||||
;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getCart ( )
|
||||
|
|
@ -293,6 +314,7 @@ sub getThumbnailUrl {
|
|||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getVendorId ( )
|
||||
|
||||
Returns the vendorId of the vendor for this sku. Defaults to the default
|
||||
|
|
|
|||
638
lib/WebGUI/Asset/Sku/Ad.pm
Normal file
638
lib/WebGUI/Asset/Sku/Ad.pm
Normal file
|
|
@ -0,0 +1,638 @@
|
|||
package WebGUI::Asset::Sku::Ad;
|
||||
|
||||
=head1 LEGAL
|
||||
|
||||
-------------------------------------------------------------------
|
||||
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
|
||||
-------------------------------------------------------------------
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use Tie::IxHash;
|
||||
use base 'WebGUI::Asset::Sku';
|
||||
use WebGUI::Asset::Template;
|
||||
use WebGUI::Form;
|
||||
use WebGUI::Storage;
|
||||
use WebGUI::Shop::Pay;
|
||||
use WebGUI::AssetCollateral::Sku::Ad::Ad;
|
||||
use WebGUI::AdSpace;
|
||||
use WebGUI::AdSpace::Ad;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Package WebGUI::Asset::Sku::Ad
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This Asset allows ads to be purchased via WebGUI shopping
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use WebGUI::Asset::Sku::Ad;
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
These methods are available from this class:
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 definition
|
||||
|
||||
Adds purchaseTemplate, manageTemplate, adSpace, priority, pricePerClick, pricePerImpression, clickDiscounts, impresisonDiscounts
|
||||
|
||||
=cut
|
||||
|
||||
sub definition {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $definition = shift;
|
||||
my %properties;
|
||||
tie %properties, 'Tie::IxHash';
|
||||
my $i18n = WebGUI::International->new($session, "Asset_AdSku");
|
||||
%properties = (
|
||||
purchaseTemplate => {
|
||||
tab => "display",
|
||||
fieldType => "template",
|
||||
namespace => "AdSku/Purchase",
|
||||
defaultValue => 'AldPGu0u-jm_5xK13atCSQ',
|
||||
label => $i18n->get("property purchase template"),
|
||||
hoverHelp => $i18n->get("property purchase template help"),
|
||||
},
|
||||
manageTemplate => {
|
||||
tab => "display",
|
||||
fieldType => "template",
|
||||
namespace => "AdSku/Manage",
|
||||
defaultValue => 'ohjyzab5i-yW6GOWTeDUHg',
|
||||
label => $i18n->get("property manage template"),
|
||||
hoverHelp => $i18n->get("property manage template help"),
|
||||
},
|
||||
adSpace => {
|
||||
tab => "properties",
|
||||
fieldType => "AdSpace",
|
||||
namespace => "AdSku",
|
||||
label => $i18n->get("property ad space"),
|
||||
hoverHelp => $i18n->get("property ad Space help"),
|
||||
},
|
||||
priority => {
|
||||
tab => "properties",
|
||||
defaultValue => '1',
|
||||
fieldType => "integer",
|
||||
label => $i18n->get("property priority"),
|
||||
hoverHelp => $i18n->get("property priority help"),
|
||||
},
|
||||
pricePerClick => {
|
||||
tab => "shop",
|
||||
defaultValue => '0.00',
|
||||
fieldType => "float",
|
||||
label => $i18n->get("property price per click"),
|
||||
hoverHelp => $i18n->get("property price per click help"),
|
||||
},
|
||||
pricePerImpression => {
|
||||
tab => "shop",
|
||||
defaultValue => '0.00',
|
||||
fieldType => "float",
|
||||
label => $i18n->get("property price per impression"),
|
||||
hoverHelp => $i18n->get("property price per impression help"),
|
||||
},
|
||||
clickDiscounts => {
|
||||
tab => "shop",
|
||||
fieldType => 'textarea',
|
||||
label => $i18n->get('property click discounts'),
|
||||
hoverHelp => $i18n->get('property click discounts help'),
|
||||
defaultValue => '',
|
||||
},
|
||||
impressionDiscounts => {
|
||||
tab => "shop",
|
||||
fieldType => 'textarea',
|
||||
label => $i18n->get('property impression discounts'),
|
||||
hoverHelp => $i18n->get('property impression discounts help'),
|
||||
defaultValue => '',
|
||||
},
|
||||
);
|
||||
|
||||
# Show the karma field only if karma is enabled
|
||||
if ($session->setting->get("useKarma")) {
|
||||
$properties{ karma } = {
|
||||
type => 'integer',
|
||||
label => $i18n->get('property adsku karma'),
|
||||
hoverHelp => $i18n->get('property adsku karma description'),
|
||||
defaultvalue => 0,
|
||||
};
|
||||
}
|
||||
|
||||
push(@{$definition}, {
|
||||
assetName => $i18n->get('assetName'),
|
||||
icon => 'adsku.gif',
|
||||
autoGenerateForms => 1,
|
||||
tableName => 'AdSku',
|
||||
className => 'WebGUI::Asset::Sku::AdSku',
|
||||
properties => \%properties,
|
||||
});
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAddToCartForm
|
||||
|
||||
Returns an empty string, since the add to cart form is complex.
|
||||
|
||||
=cut
|
||||
|
||||
sub getAddToCartForm {
|
||||
return '';
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getClickDiscountText
|
||||
|
||||
returns the text to display the number of clicks purchasaed where discounts apply
|
||||
|
||||
=cut
|
||||
|
||||
sub getClickDiscountText {
|
||||
my $self = shift;
|
||||
return getDiscountText($self->i18n->get('click discount'),
|
||||
$self->get('clickDiscounts'));
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getConfiguredTitle
|
||||
|
||||
combines the adSKu title with the customers ad title
|
||||
|
||||
=cut
|
||||
|
||||
sub getConfiguredTitle {
|
||||
my $self = shift;
|
||||
return $self->get('title') . ' (' . $self->getOptions->{'adtitle'} . ')';
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getDiscountAmount -- class level function
|
||||
|
||||
returns the amount of discount to apply to this purchase
|
||||
|
||||
=cut
|
||||
|
||||
sub getDiscountAmount {
|
||||
my($discounts,$count) = @_;
|
||||
my @discounts = parseDiscountText( $discounts );
|
||||
my $previousDiscount = 0;
|
||||
foreach my $discountSet ( @discounts ) {
|
||||
last if $count < $discountSet->[1];
|
||||
$previousDiscount = $discountSet->[0];
|
||||
}
|
||||
return $previousDiscount;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getDiscountText -- class level function
|
||||
|
||||
returns a string with a coma seperated list of counts from the discount text
|
||||
|
||||
=cut
|
||||
|
||||
sub getDiscountText {
|
||||
my($format,$discounts) = @_;
|
||||
return sprintf( $format, join( ',', (map { $_->[1] } ( parseDiscountText( $discounts ) ) ) ) );
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getImpressionDiscountText
|
||||
|
||||
returns the text to display the number of impressions purchased where discounts apply
|
||||
|
||||
=cut
|
||||
|
||||
sub getImpressionDiscountText {
|
||||
my $self = shift;
|
||||
return getDiscountText($self->i18n->get('impression discount'),
|
||||
$self->get('impressionDiscounts'));
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getPrice
|
||||
|
||||
get the price for this purchase
|
||||
|
||||
=cut
|
||||
|
||||
sub getPrice {
|
||||
my $self = shift;
|
||||
my $options = $self->getOptions;
|
||||
my $impressionCount = $options->{impressions} || $self->{formImpressions};
|
||||
my $clickCount = $options->{clicks};
|
||||
my $impressionDiscount = getDiscountAmount($self->get('impressionDiscounts'),$impressionCount );
|
||||
my $clickDiscount = getDiscountAmount($self->get('clickDiscounts'),$clickCount );
|
||||
my $impressionPrice = $self->get('pricePerImpression') * ( 100 - $impressionDiscount ) / 100 ;
|
||||
my $clickPrice = $self->get('pricePerClick') * ( 100 - $clickDiscount ) / 100 ;
|
||||
return sprintf "%.2f", $impressionPrice * $impressionCount + $clickPrice * $clickCount;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 i18n
|
||||
|
||||
returns an internationalization object for this class
|
||||
|
||||
=cut
|
||||
|
||||
sub i18n {
|
||||
my $self = shift;
|
||||
return WebGUI::International->new($self->session, "Asset_AdSku");
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 manage
|
||||
|
||||
generate template vars for manage page
|
||||
|
||||
=cut
|
||||
|
||||
sub manage {
|
||||
my ($self) = @_;
|
||||
my $session = $self->session;
|
||||
|
||||
my $i18n = WebGUI::International->new($session, "Asset_AdSku");
|
||||
my %var;
|
||||
$var{purchaseLink} = $self->getUrl;
|
||||
my $iterator = WebGUI::AssetCollateral::Sku::Ad::Ad->getAllIterator($session,{
|
||||
constraints => [ { "adSkuPurchase.userId = ?" => $self->session->user->userId } ],
|
||||
orderBy => 'dateOfPurchase',
|
||||
});
|
||||
my %ads;
|
||||
while( my $object = $iterator->() ) {
|
||||
next if $object->get('isDeleted');
|
||||
next if exists $ads{$object->get('adId')};
|
||||
my $ad = $ads{$object->get('adId')} = WebGUI::AdSpace::Ad->new($session,$object->get('adId'));
|
||||
push @{$var{myAds}}, {
|
||||
rowTitle => $ad->get('title'),
|
||||
rowClicks => $ad->get('clicks') . '/' . $ad->get('clicksBought'),
|
||||
rowImpressions => $ad->get('impressions') . '/' . $ad->get('impressionsBought'),
|
||||
rowRenewLink => $self->getUrl('func=renew;Id=' . $object->get('adSkuPurchaseId') ),
|
||||
};
|
||||
}
|
||||
return $self->processTemplate(\%var,undef,$self->{_viewTemplate});
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 onCompletePurchase
|
||||
|
||||
inserts the ad into the adspace...
|
||||
|
||||
=cut
|
||||
|
||||
sub onCompletePurchase {
|
||||
my $self = shift;
|
||||
my $item = shift;
|
||||
my $options = $self->getOptions;
|
||||
my $ad;
|
||||
|
||||
# LATER: if we use Temp Storage for the image we need to move it to perm storage
|
||||
|
||||
if( $options->{adId} ne '' ) {
|
||||
$ad = WebGUI::AdSpace::Ad->new($self->session,$options->{adId});
|
||||
my $clicks = $options->{clicks} + $ad->get('clicksBought');
|
||||
my $impressions = $options->{impressions} + $ad->get('impressionsBought');
|
||||
$ad->set({
|
||||
title => $options->{'adtitle'},
|
||||
clicksBought => $clicks,
|
||||
impressionsBought => $impressions,
|
||||
url => $options->{'link'},
|
||||
storageId => $options->{'image'},
|
||||
});
|
||||
} else {
|
||||
$ad = WebGUI::AdSpace::Ad->create($self->session,$self->get('adSpace'),{
|
||||
title => $options->{'adtitle'},
|
||||
clicksBought => $options->{'clicks'},
|
||||
impressionsBought => $options->{'impressions'},
|
||||
url => $options->{'link'},
|
||||
storageId => $options->{'image'},
|
||||
ownerUserId => $self->session->user->userId,
|
||||
isActive => 1,
|
||||
type => 'image',
|
||||
priority => $self->get('priority'),
|
||||
adSpace => $self->get('adSpace'),
|
||||
});
|
||||
}
|
||||
|
||||
WebGUI::AssetCollateral::Sku::Ad::Ad->create($self->session,{
|
||||
userId => $item->transaction->get('userId'),
|
||||
transactionItemId => $item->getId,
|
||||
adId => $ad->getId,
|
||||
clicksPurchased => $options->{'clicks'},
|
||||
impressionsPurchased => $options->{'impressions'},
|
||||
dateOfPurchase => $item->transaction->get('dateOfPurchase'),
|
||||
storedImage => $options->{'image'},
|
||||
isDeleted => 0,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 onRemoveFromCart
|
||||
|
||||
deletes the image if it gets removed from the cart
|
||||
|
||||
LATER: if we switch to using Temp Storage we do not need to do this.
|
||||
|
||||
=cut
|
||||
|
||||
sub onRemoveFromCart {
|
||||
my $self = shift;
|
||||
my $item = shift;
|
||||
my $options = $self->getOptions;
|
||||
WebGUI::Storage->get($self->session,$options->{'image'})->delete;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 onRefund
|
||||
|
||||
delete the add if it gets refunded
|
||||
|
||||
=cut
|
||||
|
||||
sub onRefund {
|
||||
my $self = shift;
|
||||
my $item = shift;
|
||||
|
||||
my $iterator = WebGUI::AssetCollateral::Sku::Ad::Ad->getAllIterator($self->session,{
|
||||
constraints => [ { "transactionItemId = ?" => $item->getId } ],
|
||||
});
|
||||
my $crud = $iterator->();
|
||||
|
||||
my $ad = WebGUI::AdSpace::Ad->new($self->session,$crud->get('adId'));
|
||||
my $clicks = $ad->get('clicksBought') - $crud->get('clicksPurchased');
|
||||
my $impressions = $ad->get('impressionsBought') - $crud->get('impressionsPurchased') ;
|
||||
$ad->set({
|
||||
clicksBought => $clicks,
|
||||
impressionsBought => $impressions,
|
||||
});
|
||||
|
||||
$crud->delete;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 parseDiscountText -- class level function
|
||||
|
||||
returns an array of array ref's that are extracted from the discount description text
|
||||
|
||||
=cut
|
||||
|
||||
sub parseDiscountText {
|
||||
my $discountDescription = shift;
|
||||
my @lines = split "\n", $discountDescription;
|
||||
my @discounts;
|
||||
foreach my $line ( @lines ) {
|
||||
if( $line =~ /^(\d+)\@(\d+)/ ) {
|
||||
push @discounts, [ $1, $2 ];
|
||||
}
|
||||
}
|
||||
return sort { $a->[1] <=> $b->[1] } @discounts;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 prepareManage
|
||||
|
||||
Prepares the template.
|
||||
|
||||
=cut
|
||||
|
||||
sub prepareManage {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
my $templateId = $self->get("manageTemplate");
|
||||
my $template = WebGUI::Asset::Template->new($self->session, $templateId);
|
||||
$template->prepare($self->getMetaDataAsTemplateVariables);
|
||||
$self->{_viewTemplate} = $template;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 prepareView
|
||||
|
||||
Prepares the template.
|
||||
|
||||
=cut
|
||||
|
||||
sub prepareView {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
my $templateId = $self->get("purchaseTemplate");
|
||||
my $template = WebGUI::Asset::Template->new($self->session, $templateId);
|
||||
$template->prepare($self->getMetaDataAsTemplateVariables);
|
||||
$self->{_viewTemplate} = $template;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 view
|
||||
|
||||
Displays the purchase adspace form
|
||||
|
||||
=cut
|
||||
|
||||
sub view {
|
||||
my ($self) = @_;
|
||||
my $session = $self->session;
|
||||
my $options = $self->getOptions();
|
||||
|
||||
my $i18n = WebGUI::International->new($session, "Asset_AdSku");
|
||||
my %var = (
|
||||
formHeader => WebGUI::Form::formHeader($session, { action=>$self->getUrl })
|
||||
. WebGUI::Form::hidden( $session, { name=>"func", value=>"addToCart" }),
|
||||
formFooter => WebGUI::Form::formFooter($session),
|
||||
formSubmit => WebGUI::Form::submit( $session, { value => $i18n->get("form purchase button") }),
|
||||
error_msg => $options->{error_msg},
|
||||
hasAddedToCart => $self->{_hasAddedToCart},
|
||||
continueShoppingUrl => $self->getUrl,
|
||||
manageLink => $self->getUrl("func=manage"),
|
||||
adSkuTitle => $self->get('title'),
|
||||
adSkuDescription => $self->get('description'),
|
||||
formTitle => WebGUI::Form::text($session, {
|
||||
-name=>"formTitle",
|
||||
-value=>$options->{adtitle},
|
||||
-size=>40
|
||||
-default=>'untitled',
|
||||
}),
|
||||
formLink => WebGUI::Form::Url($session, {
|
||||
-name=>"formLink",
|
||||
-value=>$options->{link},
|
||||
-size=>40
|
||||
-required=>1,
|
||||
}),
|
||||
formImage => WebGUI::Form::File($session, {
|
||||
-name=>"formImage",
|
||||
-value=>$options->{image},
|
||||
-size=>40
|
||||
-forceImageOnly=>1,
|
||||
}),
|
||||
formClicks => WebGUI::Form::Integer($session, {
|
||||
-name=>"formClicks",
|
||||
-value=>$options->{clicks},
|
||||
-size=>40
|
||||
-required=>1,
|
||||
}),
|
||||
formImpressions => WebGUI::Form::Integer($session, {
|
||||
-name=>"formImpressions",
|
||||
-value=>$options->{impressions},
|
||||
-size=>40
|
||||
-required=>1,
|
||||
}),
|
||||
formAdId => WebGUI::Form::Hidden($session, {
|
||||
-name=>"formAdId",
|
||||
-value=>$options->{adId} || '',
|
||||
}),
|
||||
clickPrice => $self->get('pricePerClick'),
|
||||
impressionPrice => $self->get('pricePerImpression'),
|
||||
clickDiscount => $self->getClickDiscountText,
|
||||
impressionDiscount => $self->getImpressionDiscountText,
|
||||
);
|
||||
return $self->processTemplate(\%var,undef,$self->{_viewTemplate});
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_addToCart
|
||||
|
||||
Add this subscription to the cart.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_addToCart {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $i18n = $self->i18n;
|
||||
if ($self->canView) {
|
||||
my $form = $session->form;
|
||||
my @errors;
|
||||
#my $imageStorage = $self->getOptions->{image} || WebGUI::Storage->create($session); # LATER should be createTemp
|
||||
my $imageStorageId = $form->process('formImage', 'image'); # , $self->getOptions->{image});
|
||||
my $imageStorage = WebGUI::Storage->get($session,$imageStorageId);
|
||||
my $code;
|
||||
if( not defined $imageStorage ) { $code = 1; }
|
||||
elsif( $imageStorage->getErrorCount > 0 ) { $code = 2; }
|
||||
elsif( scalar(@{$imageStorage->getFiles}) == 0 ) { $code = 3; }
|
||||
elsif( $imageStorage->isImage((@{$imageStorage->getFiles})[0]) ) { $code = 4; }
|
||||
if( not defined $imageStorage
|
||||
or $imageStorage->getErrorCount > 0
|
||||
or scalar(@{$imageStorage->getFiles}) == 0
|
||||
# or $imageStorage->isImage((@{$imageStorage->getFiles})[0]) # not currently working
|
||||
) {
|
||||
push @errors, $i18n->get('form error no image') . $code . eval { (@{$imageStorage->getFiles})[0] } ;
|
||||
}
|
||||
my $title = $form->process('formTitle');
|
||||
if($title eq '' ) {
|
||||
push @errors, $i18n->get('form error no title');
|
||||
}
|
||||
my $link = $form->process('formLink','url');
|
||||
if($link eq '' ) {
|
||||
push @errors, $i18n->get('form error no link');
|
||||
}
|
||||
my $adId = $self->get('adSpace');
|
||||
my $adSpace = WebGUI::AdSpace->new($session,$adId);
|
||||
my $clicks = $form->process('formClicks','integer');
|
||||
if($clicks < $adSpace->get('minimumClicks') ) {
|
||||
push @errors, sprintf($i18n->get('form error min clicks'), $adSpace->get('minimumClicks'));
|
||||
}
|
||||
my $impressions = $form->process('formImpressions','integer');
|
||||
if($impressions < $adSpace->get('minimumImpressions') ) {
|
||||
push @errors, sprintf($i18n->get('form error min impressions'), $adSpace->get('minimumImpressions'));
|
||||
}
|
||||
if( @errors == 0 ) {
|
||||
$self->{_hasAddedToCart} = 1;
|
||||
$self->addToCart({
|
||||
adtitle => $title,
|
||||
link => $link,
|
||||
clicks => $clicks,
|
||||
impressions => $impressions,
|
||||
adId => $adId,
|
||||
image => $imageStorageId,
|
||||
});
|
||||
} else {
|
||||
$self->applyOptions({
|
||||
adtitle => $title,
|
||||
link => $link,
|
||||
clicks => $clicks,
|
||||
impressions => $impressions,
|
||||
adId => $adId,
|
||||
image => $imageStorageId,
|
||||
error_msg => join( '<br>', @errors ),
|
||||
});
|
||||
}
|
||||
}
|
||||
return $self->www_view;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_manage
|
||||
|
||||
manage previously purchased ads
|
||||
|
||||
=cut
|
||||
|
||||
sub www_manage {
|
||||
my $self = shift;
|
||||
my $check = $self->checkView;
|
||||
return $check if (defined $check);
|
||||
$self->session->http->setLastModified($self->getContentLastModified);
|
||||
$self->session->http->sendHeader;
|
||||
$self->prepareManage;
|
||||
my $style = $self->processStyle($self->getSeparator);
|
||||
my ($head, $foot) = split($self->getSeparator,$style);
|
||||
$self->session->output->print($head, 1);
|
||||
$self->session->output->print($self->manage);
|
||||
$self->session->output->print($foot, 1);
|
||||
return "chunked";
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_renew
|
||||
|
||||
renew an ad
|
||||
|
||||
=cut
|
||||
|
||||
sub www_renew {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $id = $session->form->get('Id');
|
||||
my $crud = WebGUI::AssetCollateral::Sku::Ad::Ad->new($session,$id);
|
||||
my $ad = WebGUI::AdSpace::Ad->new($session,$crud->get('adId'));
|
||||
$self->applyOptions({
|
||||
adtitle => $ad->get('title'),
|
||||
clicks => $crud->get('clicksPurchased'),
|
||||
impressions => $crud->get('impressionsPurchased'),
|
||||
link => $ad->get('url'),
|
||||
image => $ad->get('storageId'),
|
||||
adId => $crud->get('adId'),
|
||||
});
|
||||
return $self->www_view;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
|
@ -92,6 +92,28 @@ sub definition {
|
|||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAddToCartForm ( )
|
||||
|
||||
Returns a form to add this Sku to the cart. Used when this Sku is part of
|
||||
a shelf. Overrode master class to add price form.
|
||||
|
||||
=cut
|
||||
|
||||
sub getAddToCartForm {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_Donation');
|
||||
return
|
||||
WebGUI::Form::formHeader($session, {action => $self->getUrl})
|
||||
. WebGUI::Form::hidden( $session, {name => 'func', value => 'donate'})
|
||||
. WebGUI::Form::float( $session, {name => 'price', defaultValue => $self->getPrice })
|
||||
. WebGUI::Form::submit( $session, {value => $i18n->get('donate button')})
|
||||
. WebGUI::Form::formFooter($session)
|
||||
;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getConfiguredTitle
|
||||
|
|
@ -162,18 +184,21 @@ sub view {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 wwww_donate
|
||||
=head2 www_donate
|
||||
|
||||
Accepts the information from the donation form and adds it to the cart.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_donate {
|
||||
my $self = shift;
|
||||
if ($self->canView) {
|
||||
my $self = shift;
|
||||
my $price = $self->session->form->get("price") || $self->getPrice;
|
||||
|
||||
if ($self->canView && $price > 0) {
|
||||
$self->{_hasAddedToCart} = 1;
|
||||
$self->addToCart({price => ($self->session->form->get("price") || $self->getPrice) });
|
||||
$self->addToCart( { price => $price } );
|
||||
}
|
||||
|
||||
return $self->www_view;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -165,6 +165,26 @@ sub drawRelatedBadgeGroupsField {
|
|||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAddToCartForm
|
||||
|
||||
Returns a button to take the user to the view screen.
|
||||
|
||||
=cut
|
||||
|
||||
sub getAddToCartForm {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_Sku');
|
||||
return
|
||||
WebGUI::Form::formHeader($session, {action => $self->getUrl})
|
||||
. WebGUI::Form::hidden( $session, {name => 'func', value => 'view'})
|
||||
. WebGUI::Form::submit( $session, {value => $i18n->get('see more')})
|
||||
. WebGUI::Form::formFooter($session)
|
||||
;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getConfiguredTitle
|
||||
|
|
|
|||
|
|
@ -83,6 +83,26 @@ sub definition {
|
|||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAddToCartForm
|
||||
|
||||
Returns a button to take the user to the view screen.
|
||||
|
||||
=cut
|
||||
|
||||
sub getAddToCartForm {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_Sku');
|
||||
return
|
||||
WebGUI::Form::formHeader($session, {action => $self->getUrl})
|
||||
. WebGUI::Form::hidden( $session, {name => 'func', value => 'view'})
|
||||
. WebGUI::Form::submit( $session, {value => $i18n->get('see more')})
|
||||
. WebGUI::Form::formFooter($session)
|
||||
;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getConfiguredTitle
|
||||
|
|
|
|||
|
|
@ -229,6 +229,25 @@ sub drawRelatedRibbonsField {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAddToCartForm
|
||||
|
||||
Returns a button to take the user to the view screen.
|
||||
|
||||
=cut
|
||||
|
||||
sub getAddToCartForm {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_Sku');
|
||||
return
|
||||
WebGUI::Form::formHeader($session, {action => $self->getUrl})
|
||||
. WebGUI::Form::hidden( $session, {name => 'func', value => 'view'})
|
||||
. WebGUI::Form::submit( $session, {value => $i18n->get('see more')})
|
||||
. WebGUI::Form::formFooter($session)
|
||||
;}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getConfiguredTitle
|
||||
|
||||
Returns title + badgeholder name.
|
||||
|
|
|
|||
|
|
@ -76,6 +76,26 @@ sub definition {
|
|||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAddToCartForm
|
||||
|
||||
Returns a button to take the user to the view screen.
|
||||
|
||||
=cut
|
||||
|
||||
sub getAddToCartForm {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_Sku');
|
||||
return
|
||||
WebGUI::Form::formHeader($session, {action => $self->getUrl})
|
||||
. WebGUI::Form::hidden( $session, {name => 'func', value => 'view'})
|
||||
. WebGUI::Form::submit( $session, {value => $i18n->get('see more')})
|
||||
. WebGUI::Form::formFooter($session)
|
||||
;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getConfiguredTitle
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ sub view {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 wwww_addToCart
|
||||
=head2 www_addToCart
|
||||
|
||||
Accepts the information from the form and adds it to the cart.
|
||||
|
||||
|
|
|
|||
|
|
@ -240,6 +240,37 @@ sub duplicate {
|
|||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAddToCartForm ( )
|
||||
|
||||
Returns a form to add this Sku to the cart. Used when this Sku is part of
|
||||
a shelf. Overrode master class to add variant dropdown.
|
||||
|
||||
=cut
|
||||
|
||||
sub getAddToCartForm {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_Product');
|
||||
my %variants = ();
|
||||
tie %variants, 'Tie::IxHash';
|
||||
foreach my $collateral ( @{ $self->getAllCollateral('variantsJSON')} ) {
|
||||
$variants{$collateral->{variantId}} = join ", ", $collateral->{shortdesc}, sprintf('%.2f',$collateral->{price});
|
||||
}
|
||||
return
|
||||
WebGUI::Form::formHeader($session, {action => $self->getUrl})
|
||||
. WebGUI::Form::hidden( $session, {name => 'func', value => 'buy'})
|
||||
. WebGUI::Form::selectBox( $session, {
|
||||
name => 'vid',
|
||||
options => \%variants,
|
||||
value => [0],
|
||||
})
|
||||
. WebGUI::Form::submit( $session, {value => $i18n->get('add to cart')})
|
||||
. WebGUI::Form::formFooter($session)
|
||||
;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAllCollateral ( tableName )
|
||||
|
|
|
|||
|
|
@ -269,6 +269,27 @@ sub generateSubscriptionCodeBatch {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAddToCartForm ( )
|
||||
|
||||
Returns a form to add this Sku to the cart. Used when this Sku is part of
|
||||
a shelf. Override master class to add different form.
|
||||
|
||||
=cut
|
||||
|
||||
sub getAddToCartForm {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_Subscription');
|
||||
return
|
||||
WebGUI::Form::formHeader($session, {action => $self->getUrl})
|
||||
. WebGUI::Form::hidden( $session, {name => 'func', value => 'purchaseSubscription'})
|
||||
. WebGUI::Form::submit( $session, {value => $i18n->get('purchase button')})
|
||||
. WebGUI::Form::formFooter($session)
|
||||
;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAdminConsoleWithSubmenu ( )
|
||||
|
||||
Returns an admin console with management links added to the submenu.
|
||||
|
|
@ -933,7 +954,7 @@ sub www_listSubscriptionCodes {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 wwww_purchaseSubscription
|
||||
=head2 www_purchaseSubscription
|
||||
|
||||
Add this subscription to the cart.
|
||||
|
||||
|
|
|
|||
|
|
@ -191,6 +191,18 @@ sub purgeCache {
|
|||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 view ( $calledAsWebMethod )
|
||||
|
||||
Override the base class to implement caching, template and macro processing.
|
||||
|
||||
=head3 $calledAsWebMethod
|
||||
|
||||
If this is true, then change the cache method, and do not display the
|
||||
toolbar if in adminMode.
|
||||
|
||||
=cut
|
||||
|
||||
sub view {
|
||||
my $self = shift;
|
||||
my $calledAsWebMethod = shift;
|
||||
|
|
@ -216,15 +228,6 @@ sub view {
|
|||
return $output;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub www_edit {
|
||||
my $self = shift;
|
||||
return $self->session->privilege->insufficient() unless $self->canEdit;
|
||||
return $self->session->privilege->locked() unless $self->canEditIfLocked;
|
||||
return $self->getAdminConsole->render($self->getEditForm->print,$self->addEditLabel);
|
||||
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_view
|
||||
|
|
@ -234,12 +237,12 @@ A web accessible version of the view method.
|
|||
=cut
|
||||
|
||||
sub www_view {
|
||||
my $self = shift;
|
||||
return $self->session->privilege->insufficient() unless $self->canView;
|
||||
my $mimeType=$self->getValue('mimeType');
|
||||
$self->session->http->setMimeType($mimeType || 'text/html');
|
||||
$self->session->http->setCacheControl($self->get("cacheTimeout"));
|
||||
return $self->view(1);
|
||||
my $self = shift;
|
||||
return $self->session->privilege->insufficient() unless $self->canView;
|
||||
my $mimeType=$self->getValue('mimeType');
|
||||
$self->session->http->setMimeType($mimeType || 'text/html');
|
||||
$self->session->http->setCacheControl($self->get("cacheTimeout"));
|
||||
return $self->view(1);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ sub getEditForm {
|
|||
formContent => WebGUI::Form::HTMLArea($session, { name => 'content', richEditId => $wiki->get('richEditor'), value => $self->get('content') }) ,
|
||||
formSubmit => WebGUI::Form::submit($session, { value => 'Save' }),
|
||||
formProtect => WebGUI::Form::yesNo($session, { name => "isProtected", value=>$self->getValue("isProtected")}),
|
||||
formKeywords => WebGUI::Form::text($session, {
|
||||
formKeywords => WebGUI::Form::keywords($session, {
|
||||
name => "keywords",
|
||||
value => WebGUI::Keyword->new($session)->getKeywordsForAsset({asset=>$self}),
|
||||
}),
|
||||
|
|
|
|||
338
lib/WebGUI/Asset/Wobject/Carousel.pm
Normal file
338
lib/WebGUI/Asset/Wobject/Carousel.pm
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
package WebGUI::Asset::Wobject::Carousel;
|
||||
|
||||
$VERSION = "1.0.0";
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# WebGUI is Copyright 2001-2008 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 warnings;
|
||||
use JSON;
|
||||
use Tie::IxHash;
|
||||
use WebGUI::International;
|
||||
use WebGUI::Utility;
|
||||
use base 'WebGUI::Asset::Wobject';
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 definition ( )
|
||||
|
||||
defines wobject properties for New Wobject instances. You absolutely need
|
||||
this method in your new Wobjects. If you choose to "autoGenerateForms", the
|
||||
getEditForm method is unnecessary/redundant/useless.
|
||||
|
||||
=cut
|
||||
|
||||
sub definition {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $definition = shift;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_Carousel');
|
||||
my %properties;
|
||||
tie %properties, 'Tie::IxHash';
|
||||
%properties = (
|
||||
templateId =>{
|
||||
fieldType =>"template",
|
||||
defaultValue =>'CarouselTmpl0000000002',
|
||||
tab =>"display",
|
||||
noFormPost =>0,
|
||||
namespace =>"Carousel",
|
||||
hoverHelp =>$i18n->get('carousel template description'),
|
||||
label =>$i18n->get('carousel template label'),
|
||||
},
|
||||
items =>{
|
||||
noFormPost =>1,
|
||||
fieldType =>'text',
|
||||
autoGenerate =>0,
|
||||
},
|
||||
);
|
||||
push(@{$definition}, {
|
||||
assetName=>$i18n->get('assetName'),
|
||||
icon=>'Carousel.png',
|
||||
autoGenerateForms=>1,
|
||||
tableName=>'Carousel',
|
||||
className=>'WebGUI::Asset::Wobject::Carousel',
|
||||
properties=>\%properties
|
||||
});
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 duplicate ( )
|
||||
|
||||
duplicates a New Wobject. This method is unnecessary, but if you have
|
||||
auxiliary, ancillary, or "collateral" data or files related to your
|
||||
wobject instances, you will need to duplicate them here.
|
||||
|
||||
=cut
|
||||
|
||||
sub duplicate {
|
||||
my $self = shift;
|
||||
my $newAsset = $self->SUPER::duplicate(@_);
|
||||
return $newAsset;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getEditForm ( )
|
||||
|
||||
returns the tabform object that will be used in generating the edit page for New Wobjects.
|
||||
This method is optional if you set autoGenerateForms=1 in the definition.
|
||||
|
||||
=cut
|
||||
|
||||
sub getEditForm {
|
||||
my $self = shift;
|
||||
my $tabform = $self->SUPER::getEditForm();
|
||||
my $i18n = WebGUI::International->new($self->session, "Asset_Carousel");
|
||||
|
||||
$self->session->style->setScript($self->session->url->extras('yui/build/editor/editor-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->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()"></button><br /><br />';
|
||||
|
||||
$tabform->getTab("properties")->raw($tableRowStart);
|
||||
|
||||
if($self->getValue('items')){
|
||||
my @items = @{JSON->new->decode($self->getValue('items'))->{items}};
|
||||
|
||||
foreach my $item (@items){
|
||||
my $itemHTML = $i18n->get("id label").'<div class="wg-hoverhelp">'.$i18n->get("id description").'</div>: '
|
||||
.'<input type="text" id="itemId'.$item->{sequenceNumber}.'" '
|
||||
.'name="itemId_'.$item->{sequenceNumber}.'" value="'.$item->{itemId}.'">'
|
||||
.'<textarea id="item'.$item->{sequenceNumber}.'" name="item_'.$item->{sequenceNumber}.'" '
|
||||
.'class="carouselItemText" rows="#" cols="#" '
|
||||
.'style="width: 500px; height: 80px;">'.$item->{text}."</textarea><br />\n";
|
||||
|
||||
$itemHTML .=
|
||||
" <script type='text/javascript'>\n"
|
||||
.'var myEditor'.$item->{sequenceNumber}.' '
|
||||
.'= new YAHOO.widget.SimpleEditor("item'.$item->{sequenceNumber}.'", '
|
||||
."{height: '80px', width: '500px', handleSubmit: true});\n"
|
||||
.'myEditor'.$item->{sequenceNumber}.".render()\n"
|
||||
."</script>\n";
|
||||
$tabform->getTab("properties")->raw($itemHTML);
|
||||
}
|
||||
}
|
||||
else{
|
||||
my $itemHTML = 'ID: <input type="text" id="itemId1" name="itemId_1" value="carousel_item_1">'
|
||||
.'<textarea id="item1" name="item_1" class="carouselItemText" rows="#" cols="#" '
|
||||
."style='width: 500px; height: 80px;'></textarea><br />\n";
|
||||
|
||||
$itemHTML .=
|
||||
"<script type='text/javascript'>\n"
|
||||
."var myEditor1 = new YAHOO.widget.SimpleEditor('item1', {height: '80px', width: '500px', handleSubmit: true});\n"
|
||||
."myEditor1.render()\n"
|
||||
."</script>\n";
|
||||
$tabform->getTab("properties")->raw($itemHTML);
|
||||
}
|
||||
my $tableRowEnd = qq|
|
||||
</td>
|
||||
</tr>
|
||||
|;
|
||||
$tabform->getTab("properties")->raw($tableRowEnd);
|
||||
|
||||
return $tabform;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 prepareView ( )
|
||||
|
||||
See WebGUI::Asset::prepareView() for details.
|
||||
|
||||
=cut
|
||||
|
||||
sub prepareView {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
#$self->session->errorHandler->warn('templateId: '.$self->get("parentId"));
|
||||
my $template = WebGUI::Asset::Template->new($self->session, $self->get("templateId"));
|
||||
$template->prepare;
|
||||
$self->{_viewTemplate} = $template;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 processPropertiesFromFormPost ( )
|
||||
|
||||
Used to process properties from the form posted.
|
||||
|
||||
=cut
|
||||
|
||||
sub processPropertiesFromFormPost {
|
||||
my $self = shift;
|
||||
my $form = $self->session->form;
|
||||
my (@items,$items);
|
||||
$self->SUPER::processPropertiesFromFormPost(@_);
|
||||
|
||||
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});
|
||||
return undef;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 purge ( )
|
||||
|
||||
removes collateral data associated with a Carousel when the system
|
||||
purges it's data. This method is unnecessary, but if you have
|
||||
auxiliary, ancillary, or "collateral" data or files related to your
|
||||
wobject instances, you will need to purge them here.
|
||||
|
||||
=cut
|
||||
|
||||
sub purge {
|
||||
my $self = shift;
|
||||
#purge your wobject-specific data here. This does not include fields
|
||||
# you create for your Carousel asset/wobject table.
|
||||
return $self->SUPER::purge;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 view ( )
|
||||
|
||||
method called by the www_view method. Returns a processed template
|
||||
to be displayed within the page style.
|
||||
|
||||
=cut
|
||||
|
||||
sub view {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my (@item_loop);
|
||||
|
||||
#This automatically creates template variables for all of your wobject's properties.
|
||||
my $var = $self->get;
|
||||
|
||||
if($self->getValue('items')){
|
||||
$var->{item_loop} = JSON->new->decode($self->getValue('items'))->{items};
|
||||
}
|
||||
|
||||
#This is an example of debugging code to help you diagnose problems.
|
||||
#WebGUI::ErrorHandler::warn($self->get("templateId"));
|
||||
|
||||
return $self->processTemplate($var, undef, $self->{_viewTemplate});
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_edit ( )
|
||||
|
||||
Web facing method which is the default edit page. This method is entirely
|
||||
optional. Take it out unless you specifically want to set a submenu in your
|
||||
adminConsole views.
|
||||
|
||||
=cut
|
||||
|
||||
#sub www_edit {
|
||||
# my $self = shift;
|
||||
# return $self->session->privilege->insufficient() unless $self->canEdit;
|
||||
# return $self->session->privilege->locked() unless $self->canEditIfLocked;
|
||||
# my $i18n = WebGUI::International->new($self->session, "Asset_Carousel");
|
||||
# return $self->getAdminConsole->render($self->getEditForm->print, $i18n->get("edit title"));
|
||||
#}
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Everything below here is to make it easier to install your custom
|
||||
# wobject, but has nothing to do with wobjects in general
|
||||
#-------------------------------------------------------------------
|
||||
# cd /data/WebGUI/lib
|
||||
# perl -MWebGUI::Asset::Wobject::Carousel -e install www.example.com.conf [ /path/to/WebGUI ]
|
||||
# - or -
|
||||
# perl -MWebGUI::Asset::Wobject::Carousel -e uninstall www.example.com.conf [ /path/to/WebGUI ]
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
|
||||
use base 'Exporter';
|
||||
our @EXPORT = qw(install uninstall);
|
||||
use WebGUI::Session;
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub install {
|
||||
my $config = $ARGV[0];
|
||||
my $home = $ARGV[1] || "/data/WebGUI";
|
||||
die "usage: perl -MWebGUI::Asset::Wobject::Carousel -e install www.example.com.conf\n" unless ($home && $config);
|
||||
print "Installing asset.\n";
|
||||
my $session = WebGUI::Session->open($home, $config);
|
||||
|
||||
my $assets = $session->config->get( "assets" );
|
||||
$assets->{ "WebGUI::Asset::Wobject::Carousel" } = { category => "utilities" };
|
||||
$session->config->set( "assets", $assets );
|
||||
#$session->config->addToArray("assets","WebGUI::Asset::Wobject::Carousel");
|
||||
$session->db->write("create table Carousel (
|
||||
assetId char(22) binary not null,
|
||||
revisionDate bigint not null,
|
||||
items mediumtext,
|
||||
templateId char(22),
|
||||
primary key (assetId, revisionDate)
|
||||
)");
|
||||
$session->var->end;
|
||||
$session->close;
|
||||
print "Done. Please restart Apache.\n";
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub uninstall {
|
||||
my $config = $ARGV[0];
|
||||
my $home = $ARGV[1] || "/data/WebGUI";
|
||||
die "usage: perl -MWebGUI::Asset::Wobject::Carousel -e uninstall www.example.com.conf\n" unless ($home && $config);
|
||||
print "Uninstalling asset.\n";
|
||||
my $session = WebGUI::Session->open($home, $config);
|
||||
$session->config->deleteFromArray("assets","WebGUI::Asset::Wobject::Carousel");
|
||||
my $rs = $session->db->read("select assetId from asset where className='WebGUI::Asset::Wobject::Carousel'");
|
||||
while (my ($id) = $rs->array) {
|
||||
my $asset = WebGUI::Asset->new($session, $id, "WebGUI::Asset::Wobject::Carousel");
|
||||
$asset->purge if defined $asset;
|
||||
}
|
||||
$session->db->write("drop table Carousel");
|
||||
$session->var->end;
|
||||
$session->close;
|
||||
print "Done. Please restart Apache.\n";
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
#vim:ft=perl
|
||||
|
|
@ -20,9 +20,9 @@ use WebGUI::Paginator;
|
|||
use WebGUI::Utility;
|
||||
use WebGUI::Asset::Wobject;
|
||||
use WebGUI::Workflow::Cron;
|
||||
use WebGUI::Asset::RSSCapable;
|
||||
use base 'WebGUI::Asset::RSSCapable';
|
||||
use base 'WebGUI::Asset::Wobject';
|
||||
use Class::C3;
|
||||
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub _computePostCount {
|
||||
|
|
@ -62,27 +62,16 @@ sub _visitorCacheOk {
|
|||
&& !$self->session->form->process('sortBy'));
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# encode a string to include in xml (for RSS export)
|
||||
sub _xml_encode {
|
||||
my $text = shift;
|
||||
$text =~ s/&/&/g;
|
||||
$text =~ s/</</g;
|
||||
$text =~ s/\]\]>/\]\]>/g;
|
||||
return $text;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub addChild {
|
||||
my $self = shift;
|
||||
my $properties = shift;
|
||||
my @other = @_;
|
||||
if ($properties->{className} ne "WebGUI::Asset::Post::Thread"
|
||||
and $properties->{className} ne 'WebGUI::Asset::RSSFromParent') {
|
||||
if ($properties->{className} ne "WebGUI::Asset::Post::Thread") {
|
||||
$self->session->errorHandler->security("add a ".$properties->{className}." to a ".$self->get("className"));
|
||||
return undef;
|
||||
}
|
||||
return $self->SUPER::addChild($properties, @other);
|
||||
return $self->next::method($properties, @other);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -263,7 +252,7 @@ sub canEdit {
|
|||
) &&
|
||||
$self->canStartThread( $userId )
|
||||
) || # account for new threads
|
||||
$self->SUPER::canEdit( $userId )
|
||||
$self->next::method( $userId )
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -271,7 +260,7 @@ sub canEdit {
|
|||
sub canModerate {
|
||||
my $self = shift;
|
||||
my $userId = shift || $self->session->user->userId;
|
||||
return $self->SUPER::canEdit( $userId );
|
||||
return $self->WebGUI::Asset::Wobject::canEdit( $userId );
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -294,7 +283,7 @@ sub canPost {
|
|||
}
|
||||
# Users who can edit the collab can post
|
||||
else {
|
||||
return $self->SUPER::canEdit( $userId );
|
||||
return $self->WebGUI::Asset::Wobject::canEdit( $userId );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -322,7 +311,7 @@ sub canStartThread {
|
|||
;
|
||||
return (
|
||||
$user->isInGroup($self->get("canStartThreadGroupId"))
|
||||
|| $self->SUPER::canEdit( $userId )
|
||||
|| $self->WebGUI::Asset::Wobject::canEdit( $userId )
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -331,13 +320,13 @@ sub canStartThread {
|
|||
sub canView {
|
||||
my $self = shift;
|
||||
my $userId = shift || $self->session->user->userId;
|
||||
return $self->SUPER::canView( $userId ) || $self->canPost( $userId );
|
||||
return $self->next::method( $userId ) || $self->canPost( $userId );
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub commit {
|
||||
my $self = shift;
|
||||
$self->SUPER::commit;
|
||||
$self->next::method;
|
||||
my $cron = undef;
|
||||
if ($self->get("getMailCronId")) {
|
||||
$cron = WebGUI::Workflow::Cron->new($self->session, $self->get("getMailCronId"));
|
||||
|
|
@ -799,13 +788,13 @@ sub definition {
|
|||
className=>'WebGUI::Asset::Wobject::Collaboration',
|
||||
properties=>\%properties,
|
||||
});
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
return $class->next::method($session, $definition);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub duplicate {
|
||||
my $self = shift;
|
||||
my $newAsset = $self->SUPER::duplicate(@_);
|
||||
my $newAsset = $self->next::method(@_);
|
||||
$newAsset->createSubscriptionGroup;
|
||||
return $newAsset;
|
||||
}
|
||||
|
|
@ -821,7 +810,7 @@ Add a tab for the mail interface.
|
|||
sub getEditTabs {
|
||||
my $self = shift;
|
||||
my $i18n = WebGUI::International->new($self->session,"Asset_Collaboration");
|
||||
return ($self->SUPER::getEditTabs(), ['mail', $i18n->get('mail'), 9]);
|
||||
return ($self->next::method, ['mail', $i18n->get('mail'), 9]);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -838,7 +827,7 @@ sub getNewThreadUrl {
|
|||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub getRssItems {
|
||||
sub getRssFeedItems {
|
||||
my $self = shift;
|
||||
|
||||
# XXX copied and reformatted this query from www_viewRSS, but why is it constructed like this?
|
||||
|
|
@ -861,6 +850,7 @@ SQL
|
|||
my $datetime = $self->session->datetime;
|
||||
|
||||
my @posts;
|
||||
my $rssLimit = $self->get('itemsPerFeed');
|
||||
for my $postId (@postIds) {
|
||||
my $post = WebGUI::Asset->new($self->session, $postId, 'WebGUI::Asset::Post::Thread');
|
||||
my $postUrl = $siteUrl . $post->getUrl;
|
||||
|
|
@ -881,24 +871,26 @@ SQL
|
|||
}
|
||||
}
|
||||
|
||||
push @posts, {
|
||||
push @posts, {
|
||||
author => $post->get('username'),
|
||||
title => $post->get('title'),
|
||||
'link' => $postUrl,
|
||||
'link' => $postUrl,
|
||||
guid => $postUrl,
|
||||
description => $post->get('synopsis'),
|
||||
epochDate => $post->get('creationDate'),
|
||||
pubDate => $datetime->epochToMail($post->get('creationDate')),
|
||||
attachmentLoop => $attachmentLoop,
|
||||
attachmentLoop => $attachmentLoop,
|
||||
userDefined1 => $post->get("userDefined1"),
|
||||
userDefined2 => $post->get("userDefined2"),
|
||||
userDefined3 => $post->get("userDefined3"),
|
||||
userDefined4 => $post->get("userDefined4"),
|
||||
userDefined5 => $post->get("userDefined5"),
|
||||
};
|
||||
|
||||
last if $rssLimit <= scalar(@posts);
|
||||
}
|
||||
|
||||
return @posts;
|
||||
return \@posts;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -1064,7 +1056,7 @@ sub getViewTemplateVars {
|
|||
$var{'user.canPost'} = $self->canPost;
|
||||
$var{'user.canStartThread'} = $self->canStartThread;
|
||||
$var{"add.url"} = $self->getNewThreadUrl;
|
||||
$var{"rss.url"} = $self->getRssUrl;
|
||||
$var{"rss.url"} = $self->getRssFeedUrl;
|
||||
$var{'user.isModerator'} = $self->canModerate;
|
||||
$var{'user.isVisitor'} = ($self->session->user->isVisitor);
|
||||
$var{'user.isSubscribed'} = $self->isSubscribed;
|
||||
|
|
@ -1170,11 +1162,8 @@ See WebGUI::Asset::prepareView() for details.
|
|||
|
||||
sub prepareView {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
$self->next::method;
|
||||
my $template = WebGUI::Asset::Template->new($self->session, $self->get("collaborationTemplateId")) or die "no good: ".$self->get("collaborationTemplateId");
|
||||
if ($self->get('rssCapableRssEnabled')) {
|
||||
$self->session->style->setLink($self->getRssUrl,{ rel=>'alternate', type=>'application/rss+xml', title=>$self->get('title') . ' RSS' });
|
||||
}
|
||||
$template->prepare($self->getMetaDataAsTemplateVariables);
|
||||
$self->{_viewTemplate} = $template;
|
||||
}
|
||||
|
|
@ -1184,7 +1173,7 @@ sub prepareView {
|
|||
sub processPropertiesFromFormPost {
|
||||
my $self = shift;
|
||||
my $updatePrivs = ($self->session->form->process("groupIdView") ne $self->get("groupIdView") || $self->session->form->process("groupIdEdit") ne $self->get("groupIdEdit"));
|
||||
$self->SUPER::processPropertiesFromFormPost;
|
||||
$self->next::method;
|
||||
if ($self->get("subscriptionGroupId") eq "") {
|
||||
$self->createSubscriptionGroup;
|
||||
}
|
||||
|
|
@ -1212,7 +1201,7 @@ sub purge {
|
|||
my $cron = WebGUI::Workflow::Cron->new($self->session, $self->get("getMailCronId"));
|
||||
$cron->delete if defined $cron;
|
||||
}
|
||||
$self->SUPER::purge;
|
||||
$self->next::method;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -1227,7 +1216,7 @@ sub purgeCache {
|
|||
my $self = shift;
|
||||
WebGUI::Cache->new($self->session,"view_".$self->getId)->delete;
|
||||
WebGUI::Cache->new($self->session,$self->_visitorCacheKey)->delete;
|
||||
$self->SUPER::purgeCache;
|
||||
$self->next::method;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -1460,7 +1449,7 @@ sub www_view {
|
|||
my $self = shift;
|
||||
my $disableCache = ($self->session->form->process("sortBy") ne "");
|
||||
$self->session->http->setCacheControl($self->get("visitorCacheTimeout")) if ($self->session->user->isVisitor && !$disableCache);
|
||||
return $self->SUPER::www_view(@_);
|
||||
return $self->next::method(@_);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
|||
|
|
@ -359,6 +359,14 @@ sub prepareView {
|
|||
|
||||
#------------------------------------------------------------------
|
||||
|
||||
=head2 purge ( )
|
||||
|
||||
See WebGUI::Asset::purge() for details. Extend SUPERclass
|
||||
to handle deleting tickets, tokens, ribbons, registrants, badge groups
|
||||
and event meta data.
|
||||
|
||||
=cut
|
||||
|
||||
sub purge {
|
||||
my $self = shift;
|
||||
my $db = $self->session->db;
|
||||
|
|
|
|||
|
|
@ -206,6 +206,14 @@ sub purgeCache {
|
|||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 view ( )
|
||||
|
||||
See WebGUI::Asset::view for details. Generate template variables and
|
||||
render the template. Also handles caching.
|
||||
|
||||
=cut
|
||||
|
||||
sub view {
|
||||
my $self = shift;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ package WebGUI::Asset::Wobject::Gallery;
|
|||
#-------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use base 'WebGUI::Asset::Wobject';
|
||||
use Class::C3;
|
||||
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
|
||||
use JSON;
|
||||
use Tie::IxHash;
|
||||
use WebGUI::International;
|
||||
|
|
@ -338,7 +339,7 @@ sub definition {
|
|||
properties => \%properties,
|
||||
};
|
||||
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
return $class->next::method($session, $definition);
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
@ -366,7 +367,7 @@ sub addChild {
|
|||
return undef;
|
||||
}
|
||||
|
||||
return $self->SUPER::addChild( $properties, @_ );
|
||||
return $self->next::method( $properties, @_ );
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
@ -740,6 +741,41 @@ sub getPreviousAlbumId {
|
|||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getRssFeedItems ()
|
||||
|
||||
Returns an array reference of hash references. Each hash reference has a title,
|
||||
description, link, and date field. The date field can be either an epoch date, an RFC 1123
|
||||
date, or a ISO date in the format of YYYY-MM-DD HH:MM::SS. Optionally specify an
|
||||
author, and a guid field.
|
||||
|
||||
=cut
|
||||
|
||||
sub getRssFeedItems {
|
||||
my $self = shift;
|
||||
|
||||
my $p
|
||||
= $self->getAlbumPaginator( {
|
||||
perpage => $self->get('itemsPerFeed'),
|
||||
} );
|
||||
|
||||
my $var = [];
|
||||
for my $assetId ( @{ $p->getPageData } ) {
|
||||
my $asset = WebGUI::Asset::Wobject::GalleryAlbum->newPending( $self->session, $assetId );
|
||||
push @{ $var }, {
|
||||
'link' => $asset->getUrl,
|
||||
'guid' => $asset->{_properties}->{ 'assetId' },
|
||||
'title' => $asset->getTitle,
|
||||
'description' => $asset->{_properties}->{ 'description' },
|
||||
'date' => $asset->{_properties}->{ 'creationDate' },
|
||||
'author' => WebGUI::User->new($self->session, $asset->{_properties}->{ 'ownerUserId' })->username
|
||||
};
|
||||
}
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 getSearchPaginator ( rules )
|
||||
|
|
@ -934,7 +970,7 @@ See WebGUI::Asset::prepareView() for details.
|
|||
|
||||
sub prepareView {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
$self->next::method();
|
||||
|
||||
if ( $self->get("viewDefault") eq "album" && $self->get("viewAlbumAssetId") && $self->get("viewAlbumAssetId")
|
||||
ne 'PBasset000000000000001') {
|
||||
|
|
@ -1042,7 +1078,7 @@ sub www_add {
|
|||
return $self->processStyle($i18n->get("error add uncommitted"));
|
||||
}
|
||||
|
||||
return $self->SUPER::www_add( @_ );
|
||||
return $self->next::method( @_ );
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ package WebGUI::Asset::Wobject::GalleryAlbum;
|
|||
#-------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use base 'WebGUI::Asset::Wobject';
|
||||
use Class::C3;
|
||||
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
|
||||
use Carp qw( croak );
|
||||
use File::Find;
|
||||
use File::Spec;
|
||||
|
|
@ -77,7 +78,7 @@ sub definition {
|
|||
properties => \%properties,
|
||||
};
|
||||
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
return $class->next::method($session, $definition);
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
@ -174,7 +175,7 @@ sub addChild {
|
|||
return undef;
|
||||
}
|
||||
|
||||
return $self->SUPER::addChild( $properties, @_ );
|
||||
return $self->next::method( $properties, @_ );
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
@ -400,7 +401,7 @@ sub getCurrentRevisionDate {
|
|||
return $revisionDate;
|
||||
}
|
||||
else {
|
||||
return $class->SUPER::getCurrentRevisionDate( $session, $assetId );
|
||||
return $class->next::method( $session, $assetId );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -497,6 +498,41 @@ sub getPreviousAlbum {
|
|||
return $self->{_previousAlbum};
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getRssFeedItems ()
|
||||
|
||||
Returns an array reference of hash references. Each hash reference has a title,
|
||||
description, link, and date field. The date field can be either an epoch date, an RFC 1123
|
||||
date, or a ISO date in the format of YYYY-MM-DD HH:MM::SS. Optionally specify an
|
||||
author, and a guid field.
|
||||
|
||||
=cut
|
||||
|
||||
sub getRssFeedItems {
|
||||
my $self = shift;
|
||||
|
||||
my $p
|
||||
= $self->getFilePaginator( {
|
||||
perpage => $self->get('itemsPerFeed'),
|
||||
} );
|
||||
|
||||
my $var = [];
|
||||
for my $assetId ( @{ $p->getPageData } ) {
|
||||
my $asset = WebGUI::Asset::Wobject::GalleryAlbum->newPending( $self->session, $assetId );
|
||||
push @{ $var }, {
|
||||
'link' => $asset->getUrl,
|
||||
'guid' => $asset->{_properties}->{ 'assetId' },
|
||||
'title' => $asset->getTitle,
|
||||
'description' => $asset->{_properties}->{ 'description' },
|
||||
'date' => $asset->{_properties}->{ 'creationDate' },
|
||||
'author' => WebGUI::User->new($self->session, $asset->{_properties}->{ 'ownerUserId' })->username
|
||||
};
|
||||
}
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 getTemplateVars ( )
|
||||
|
|
@ -639,7 +675,7 @@ See WebGUI::Asset::prepareView() for details.
|
|||
|
||||
sub prepareView {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
$self->next::method();
|
||||
|
||||
my $templateId = $self->getParent->get("templateIdViewAlbum");
|
||||
|
||||
|
|
@ -719,7 +755,7 @@ approval workflow.
|
|||
sub processPropertiesFromFormPost {
|
||||
my $self = shift;
|
||||
my $form = $self->session->form;
|
||||
my $errors = $self->SUPER::processPropertiesFromFormPost || [];
|
||||
my $errors = $self->next::method || [];
|
||||
|
||||
# Return if error
|
||||
return $errors if @$errors;
|
||||
|
|
@ -762,7 +798,7 @@ Override update to force isHidden=1 on all albums.
|
|||
sub update {
|
||||
my $self = shift;
|
||||
my $properties = shift;
|
||||
return $self->SUPER::update({ %{ $properties }, isHidden=>1 });
|
||||
return $self->next::method({ %{ $properties }, isHidden=>1 });
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ sub definition {
|
|||
lineage => $i18n->get('sort by asset rank label'),
|
||||
lastUpdated => $i18n->get('sort by last updated label'),
|
||||
},
|
||||
defaultValue =>"score",
|
||||
defaultValue =>"title",
|
||||
hoverHelp =>$i18n->get('default sort description'),
|
||||
label =>$i18n->get('default sort label'),
|
||||
},
|
||||
|
|
@ -238,6 +238,14 @@ sub definition {
|
|||
hoverHelp =>$i18n->get('ratings duration description'),
|
||||
label =>$i18n->get('ratings duration label'),
|
||||
},
|
||||
statisticsCacheTimeout => {
|
||||
tab => "display",
|
||||
fieldType => "interval",
|
||||
defaultValue => 3600,
|
||||
uiLevel => 8,
|
||||
label => $i18n->get("statistics cache timeout label"),
|
||||
hoverHelp => $i18n->get("statistics cache timeout description")
|
||||
},
|
||||
);
|
||||
push(@{$definition}, {
|
||||
assetName=>$i18n->get('assetName'),
|
||||
|
|
@ -520,6 +528,7 @@ sub view {
|
|||
$self->session->style->setScript($self->session->url->extras('wobject/Matrix/matrix.js'), {type =>
|
||||
'text/javascript'});
|
||||
|
||||
my ($varStatistics,$varStatisticsEncoded);
|
||||
my $var = $self->get;
|
||||
$var->{isLoggedIn} = ($self->session->user->userId ne "1");
|
||||
$var->{addMatrixListing_url} = $self->getUrl('func=add;class=WebGUI::Asset::MatrixListing');
|
||||
|
|
@ -527,90 +536,104 @@ sub view {
|
|||
$var->{exportAttributes_url} = $self->getUrl('func=exportAttributes');
|
||||
$var->{listAttributes_url} = $self->getUrl('func=listAttributes');
|
||||
$var->{search_url} = $self->getUrl('func=search');
|
||||
|
||||
# Get the MatrixListing with the most views as an object using getLineage.
|
||||
my ($bestViews_listing) = @{ $self->getLineage(['descendants'], {
|
||||
|
||||
if ($self->canEdit){
|
||||
# Get all the MatrixListings that are still pending.
|
||||
my @pendingListings = @{ $self->getLineage(['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
|
||||
orderByClause => "revisionDate asc",
|
||||
returnObjects => 1,
|
||||
statusToInclude => ['pending'],
|
||||
}) };
|
||||
foreach my $pendingListing (@pendingListings){
|
||||
push (@{ $var->{pending_loop} }, {
|
||||
url => $pendingListing->getUrl
|
||||
."?func=view;revision=".$pendingListing->get('revisionDate'),
|
||||
name => $pendingListing->get('title'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
my $versionTag = WebGUI::VersionTag->getWorking($session, 1);
|
||||
my $noCache =
|
||||
$session->var->isAdminOn
|
||||
|| $self->get("statisticsCacheTimeout") <= 10
|
||||
|| ($versionTag && $versionTag->getId eq $self->get("tagId"));
|
||||
unless ($noCache) {
|
||||
$varStatisticsEncoded = WebGUI::Cache->new($session,"matrixStatistics_".$self->getId)->get;
|
||||
}
|
||||
|
||||
if ($varStatisticsEncoded){
|
||||
$varStatistics = JSON->new->decode($varStatisticsEncoded);
|
||||
}
|
||||
else{
|
||||
# Get the MatrixListing with the most views as an object using getLineage.
|
||||
my ($bestViews_listing) = @{ $self->getLineage(['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
|
||||
joinClass => "WebGUI::Asset::MatrixListing",
|
||||
orderByClause => "views desc",
|
||||
limit => 1,
|
||||
returnObjects => 1,
|
||||
}) };
|
||||
if($bestViews_listing){
|
||||
$var->{bestViews_url} = $bestViews_listing->getUrl;
|
||||
$var->{bestViews_count} = $bestViews_listing->get('views');
|
||||
$var->{bestViews_name} = $bestViews_listing->get('title');
|
||||
$var->{bestViews_sortButton} = "<span id='sortByViews'><button type='button'>Sort by views</button></span><br />";
|
||||
}
|
||||
if($bestViews_listing){
|
||||
$varStatistics->{bestViews_url} = $bestViews_listing->getUrl;
|
||||
$varStatistics->{bestViews_count} = $bestViews_listing->get('views');
|
||||
$varStatistics->{bestViews_name} = $bestViews_listing->get('title');
|
||||
$varStatistics->{bestViews_sortButton} = "<span id='sortByViews'><button type='button'>Sort by views</button></span><br />";
|
||||
}
|
||||
|
||||
# Get the MatrixListing with the most compares as an object using getLineage.
|
||||
# Get the MatrixListing with the most compares as an object using getLineage.
|
||||
|
||||
my ($bestCompares_listing) = @{ $self->getLineage(['descendants'], {
|
||||
my ($bestCompares_listing) = @{ $self->getLineage(['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
|
||||
joinClass => "WebGUI::Asset::MatrixListing",
|
||||
orderByClause => "compares desc",
|
||||
limit => 1,
|
||||
returnObjects => 1,
|
||||
}) };
|
||||
if($bestCompares_listing){
|
||||
$var->{bestCompares_url} = $bestCompares_listing->getUrl;
|
||||
$var->{bestCompares_count} = $bestCompares_listing->get('compares');
|
||||
$var->{bestCompares_name} = $bestCompares_listing->get('title');
|
||||
$var->{bestCompares_sortButton} = "<span id='sortByCompares'><button type='button'>Sort by compares</button></span><br />";
|
||||
}
|
||||
if($bestCompares_listing){
|
||||
$varStatistics->{bestCompares_url} = $bestCompares_listing->getUrl;
|
||||
$varStatistics->{bestCompares_count} = $bestCompares_listing->get('compares');
|
||||
$varStatistics->{bestCompares_name} = $bestCompares_listing->get('title');
|
||||
$varStatistics->{bestCompares_sortButton} = "<span id='sortByCompares'><button type='button'>Sort by compares</button></span><br />";
|
||||
}
|
||||
|
||||
# Get the MatrixListing with the most clicks as an object using getLineage.
|
||||
my ($bestClicks_listing) = @{ $self->getLineage(['descendants'], {
|
||||
# Get the MatrixListing with the most clicks as an object using getLineage.
|
||||
my ($bestClicks_listing) = @{ $self->getLineage(['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
|
||||
joinClass => "WebGUI::Asset::MatrixListing",
|
||||
orderByClause => "clicks desc",
|
||||
limit => 1,
|
||||
returnObjects => 1,
|
||||
}) };
|
||||
if($bestClicks_listing){
|
||||
$var->{bestClicks_url} = $bestClicks_listing->getUrl;
|
||||
$var->{bestClicks_count} = $bestClicks_listing->get('clicks');
|
||||
$var->{bestClicks_name} = $bestClicks_listing->get('title');
|
||||
$var->{bestClicks_sortButton} = "<span id='sortByClicks'><button type='button'>Sort by clicks</button></span><br />";
|
||||
}
|
||||
# Get the 5 MatrixListings that were last updated as objects using getLineage.
|
||||
if($bestClicks_listing){
|
||||
$varStatistics->{bestClicks_url} = $bestClicks_listing->getUrl;
|
||||
$varStatistics->{bestClicks_count} = $bestClicks_listing->get('clicks');
|
||||
$varStatistics->{bestClicks_name} = $bestClicks_listing->get('title');
|
||||
$varStatistics->{bestClicks_sortButton} = "<span id='sortByClicks'><button type='button'>Sort by clicks</button></span><br />";
|
||||
}
|
||||
|
||||
my @lastUpdatedListings = @{ $self->getLineage(['descendants'], {
|
||||
# Get the 5 MatrixListings that were last updated as objects using getLineage.
|
||||
|
||||
my @lastUpdatedListings = @{ $self->getLineage(['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
|
||||
joinClass => "WebGUI::Asset::MatrixListing",
|
||||
orderByClause => "lastUpdated desc",
|
||||
limit => 5,
|
||||
returnObjects => 1,
|
||||
}) };
|
||||
foreach my $lastUpdatedListing (@lastUpdatedListings){
|
||||
push (@{ $var->{last_updated_loop} }, {
|
||||
foreach my $lastUpdatedListing (@lastUpdatedListings){
|
||||
push (@{ $varStatistics->{last_updated_loop} }, {
|
||||
url => $lastUpdatedListing->getUrl,
|
||||
name => $lastUpdatedListing->get('title'),
|
||||
lastUpdated => $self->session->datetime->epochToHuman($lastUpdatedListing->get('lastUpdated'),"%z")
|
||||
});
|
||||
}
|
||||
$var->{lastUpdated_sortButton} = "<span id='sortByUpdated'><button type='button'>Sort by updated</button></span><br />";
|
||||
}
|
||||
$var->{lastUpdated_sortButton} = "<span id='sortByUpdated'><button type='button'>Sort by updated</button></span><br />";
|
||||
|
||||
# For each category, get the MatrixListings with the best ratings.
|
||||
|
||||
# Get all the MatrixListings that are still pending.
|
||||
|
||||
my @pendingListings = @{ $self->getLineage(['descendants'], {
|
||||
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
|
||||
orderByClause => "revisionDate asc",
|
||||
returnObjects => 1,
|
||||
statusToInclude => ['pending'],
|
||||
}) };
|
||||
foreach my $pendingListing (@pendingListings){
|
||||
push (@{ $var->{pending_loop} }, {
|
||||
url => $pendingListing->getUrl
|
||||
."?func=view;revision=".$pendingListing->get('revisionDate'),
|
||||
name => $pendingListing->get('title'),
|
||||
});
|
||||
}
|
||||
|
||||
# For each category, get the MatrixListings with the best ratings.
|
||||
|
||||
foreach my $category (keys %{$self->getCategories}) {
|
||||
foreach my $category (keys %{$self->getCategories}) {
|
||||
my $data;
|
||||
my $sql = "
|
||||
select
|
||||
|
|
@ -641,7 +664,7 @@ sub view {
|
|||
order by rating.meanValue ";
|
||||
|
||||
$data = $db->quickHashRef($sql." desc limit 1",[$category,$self->getId]);
|
||||
push(@{ $var->{best_rating_loop} },{
|
||||
push(@{ $varStatistics->{best_rating_loop} },{
|
||||
url=>'/'.$data->{url},
|
||||
category=>$category,
|
||||
name=>$data->{productName},
|
||||
|
|
@ -650,7 +673,7 @@ sub view {
|
|||
count=>$data->{countValue}
|
||||
});
|
||||
$data = $db->quickHashRef($sql." asc limit 1",[$category,$self->getId]);
|
||||
push(@{ $var->{worst_rating_loop} },{
|
||||
push(@{ $varStatistics->{worst_rating_loop} },{
|
||||
url=>'/'.$data->{url},
|
||||
category=>$category,
|
||||
name=>$data->{productName},
|
||||
|
|
@ -658,9 +681,9 @@ sub view {
|
|||
median=>$data->{medianValue},
|
||||
count=>$data->{countValue}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$var->{listingCount} = scalar $db->buildArray("
|
||||
$varStatistics->{listingCount} = scalar $db->buildArray("
|
||||
select *
|
||||
from asset, assetData
|
||||
where asset.assetId=assetData.assetId
|
||||
|
|
@ -670,7 +693,17 @@ sub view {
|
|||
and assetData.status='approved'
|
||||
group by asset.assetId",
|
||||
[$self->getId]);
|
||||
|
||||
|
||||
$varStatisticsEncoded = JSON->new->encode($varStatistics);
|
||||
WebGUI::Cache->new($session,"matrixStatistics_".$self->getId)->set(
|
||||
$varStatisticsEncoded,$self->get("statisticsCacheTimeout")
|
||||
);
|
||||
}
|
||||
|
||||
foreach my $statistic (keys %{$varStatistics}) {
|
||||
$var->{$statistic} = $varStatistics->{$statistic};
|
||||
}
|
||||
|
||||
return $self->processTemplate($var, undef, $self->{_viewTemplate});
|
||||
}
|
||||
|
||||
|
|
@ -977,13 +1010,32 @@ sub www_getCompareFormData {
|
|||
my $form = $session->form;
|
||||
my $sort = shift || $session->scratch->get('matrixSort') || $self->get('defaultSort');
|
||||
my $sortDirection = ' desc';
|
||||
# if ( WebGUI::Utility::isIn($sort, qw(revisionDate score)) ) {
|
||||
# $sortDirection = " desc";
|
||||
# }
|
||||
my @results;
|
||||
my @listingIds = $self->session->form->checkList("listingId");
|
||||
if ($sort eq 'title'){
|
||||
$sortDirection = ' asc';
|
||||
}
|
||||
|
||||
$self->session->http->setMimeType("application/json");
|
||||
my @listingIds = $session->form->checkList("listingId");
|
||||
|
||||
$session->http->setMimeType("application/json");
|
||||
|
||||
my (@searchParams,@searchParams_sorted,@searchParamList,$searchParamList);
|
||||
if($form->process("search")){
|
||||
foreach my $param ($form->param) {
|
||||
if($param =~ m/^search_/){
|
||||
my $parameter;
|
||||
$parameter->{name} = $param;
|
||||
$parameter->{value} = $form->process($param);
|
||||
my $attributeId = $param;
|
||||
$attributeId =~ s/^search_//;
|
||||
$attributeId =~ s/_____/-/g;
|
||||
$parameter->{attributeId} = $attributeId;
|
||||
push(@searchParamList,'"'.$parameter->{attributeId}.'"');
|
||||
push(@searchParams,$parameter);
|
||||
}
|
||||
}
|
||||
$searchParamList = join(',',@searchParamList);
|
||||
@searchParams_sorted = sort { $b->{value} <=> $a->{value} } @searchParams;
|
||||
}
|
||||
|
||||
my $sql = "
|
||||
select
|
||||
|
|
@ -1005,31 +1057,17 @@ assetData.revisionDate
|
|||
and assetData.revisionDate = (SELECT max(revisionDate) from assetData where assetId=asset.assetId and status='approved')
|
||||
and status='approved'
|
||||
order by ".$sort.$sortDirection;
|
||||
|
||||
my $sth = $session->db->read($sql,[$self->getId]);
|
||||
my @results;
|
||||
|
||||
@results = @{ $session->db->buildArrayRefOfHashRefs($sql,[$self->getId]) };
|
||||
|
||||
my (@searchParams,@searchParams_sorted);
|
||||
if($form->process("search")){
|
||||
foreach my $param ($form->param) {
|
||||
if($param =~ m/^search_/){
|
||||
my $parameter;
|
||||
$parameter->{name} = $param;
|
||||
$parameter->{value} = $form->process($param);
|
||||
my $attributeId = $param;
|
||||
$attributeId =~ s/^search_//;
|
||||
$attributeId =~ s/_____/-/g;
|
||||
$parameter->{attributeId} = $attributeId;
|
||||
push(@searchParams,$parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@searchParams_sorted = sort { $b->{value} <=> $a->{value} } @searchParams;
|
||||
foreach my $result (@results){
|
||||
if($form->process("search")){
|
||||
while (my $result = $sth->hashRef) {
|
||||
my $matrixListing_attributes = $session->db->buildHashRefOfHashRefs("
|
||||
select value, fieldType, attributeId from Matrix_attribute
|
||||
left join MatrixListing_attribute as listing using(attributeId)
|
||||
where listing.matrixListingId = ? order by value asc",
|
||||
where listing.matrixListingId = ?
|
||||
and attributeId IN(".$searchParamList.")",
|
||||
[$result->{assetId}],'attributeId');
|
||||
PARAM: foreach my $param (@searchParams_sorted) {
|
||||
my $fieldType = $matrixListing_attributes->{$param->{attributeId}}->{fieldType};
|
||||
|
|
@ -1046,20 +1084,27 @@ assetData.revisionDate
|
|||
$result->{checked} = 'checked';
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
$result->{assetId} =~ s/-/_____/g;
|
||||
if(WebGUI::Utility::isIn($result->{assetId},@listingIds)){
|
||||
$result->{checked} = 'checked';
|
||||
}
|
||||
}
|
||||
$result->{assetId} =~ s/-/_____/g;
|
||||
$result->{url} = $session->url->gateway($result->{url});
|
||||
push @results, $result;
|
||||
}
|
||||
}else{
|
||||
while (my $result = $sth->hashRef) {
|
||||
$result->{assetId} =~ s/-/_____/g;
|
||||
if(WebGUI::Utility::isIn($result->{assetId},@listingIds)){
|
||||
$result->{checked} = 'checked';
|
||||
}
|
||||
$result->{url} = $session->url->gateway($result->{url});
|
||||
push @results, $result;
|
||||
}
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
my $jsonOutput;
|
||||
$jsonOutput->{ResultSet} = {Result=>\@results};
|
||||
|
||||
my $encodedOutput = JSON->new->encode($jsonOutput);
|
||||
|
||||
return $encodedOutput;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -297,8 +297,8 @@ Returns a toolbar with a set of icons that hyperlink to functions that delete, e
|
|||
|
||||
sub getToolbar {
|
||||
my $self = shift;
|
||||
return
|
||||
unless $self->canEdit;
|
||||
return undef
|
||||
unless $self->canEdit && $self->session->var->isAdminOn;
|
||||
if ($self->getToolbarState) {
|
||||
my $toolbar = '';
|
||||
if ($self->canEditIfLocked) {
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ sub getEditForm {
|
|||
);
|
||||
|
||||
# javascript
|
||||
$self->session->style->setScript("/extras/wobject/SQLReport/editFormDownload.js");
|
||||
$self->session->style->setScript($self->session->url->extras("wobject/SQLReport/editFormDownload.js"), {type => 'text/javascript',});
|
||||
|
||||
### /DOWNLOAD
|
||||
|
||||
|
|
|
|||
|
|
@ -308,10 +308,11 @@ sub view {
|
|||
foreach my $id (@{$p->getPageData}) {
|
||||
my $asset = WebGUI::Asset->newByDynamicClass($session, $id);
|
||||
if (defined $asset) {
|
||||
my $sku = $asset->get;
|
||||
$sku->{url} = $asset->getUrl;
|
||||
$sku->{thumbnailUrl} = $asset->getThumbnailUrl;
|
||||
$sku->{price} = sprintf("%.2f", $asset->getPrice);
|
||||
my $sku = $asset->get;
|
||||
$sku->{url} = $asset->getUrl;
|
||||
$sku->{thumbnailUrl} = $asset->getThumbnailUrl;
|
||||
$sku->{price} = sprintf("%.2f", $asset->getPrice);
|
||||
$sku->{addToCartForm} = $asset->getAddToCartForm;
|
||||
push @skus, $sku;
|
||||
}
|
||||
else {
|
||||
|
|
@ -330,6 +331,13 @@ sub view {
|
|||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_edit ( )
|
||||
|
||||
Override the superclass to add import and exprt items to the AdminConsole submenu.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_edit {
|
||||
my $self = shift;
|
||||
my $i18n = WebGUI::International->new($self->session, 'Asset_Shelf');
|
||||
|
|
|
|||
|
|
@ -112,6 +112,14 @@ sub definition {
|
|||
label => $i18n->get('Max user responses'),
|
||||
hoverHelp => $i18n->get('Max user responses help'),
|
||||
},
|
||||
surveySummaryTemplateId => {
|
||||
tab => 'display',
|
||||
fieldType => 'template',
|
||||
label => $i18n->get('Survey Summary Template'),
|
||||
hoverHelp => $i18n->get('Survey Summary Template help'),
|
||||
defaultValue => '7F-BuEHi7t9bPi008H8xZQ',
|
||||
namespace => 'Survey/Summary',
|
||||
},
|
||||
surveyTakeTemplateId => {
|
||||
tab => 'display',
|
||||
fieldType => 'template',
|
||||
|
|
@ -193,8 +201,19 @@ sub definition {
|
|||
# hoverHelp => $i18n->get('editForm workflowIdAddEntry description'),
|
||||
none => 1,
|
||||
},
|
||||
quizModeSummary => {
|
||||
fieldType => 'yesNo',
|
||||
defaultValue => 0,
|
||||
tab => 'properties',
|
||||
label => $i18n->get('Quiz mode summaries'),
|
||||
hoverHelp => $i18n->get('Quiz mode summaries help'),
|
||||
}
|
||||
);
|
||||
|
||||
#my $defaultMC = $session->
|
||||
|
||||
#%properties = ();
|
||||
|
||||
push @{$definition}, {
|
||||
assetName => $i18n->get('assetName'),
|
||||
icon => 'survey.gif',
|
||||
|
|
@ -412,6 +431,10 @@ sub www_submitObjectEdit {
|
|||
}
|
||||
elsif ( $params->{copy} ) {
|
||||
return $self->copyObject( \@address );
|
||||
}elsif( $params->{removetype} ){
|
||||
return $self->removeType(\@address);
|
||||
}elsif( $params->{addtype} ){
|
||||
return $self->addType($params->{addtype},\@address);
|
||||
}
|
||||
|
||||
# Update the addressed object
|
||||
|
|
@ -493,6 +516,51 @@ sub www_jumpTo {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 removeType ( $address )
|
||||
|
||||
Remove the requested questionType, and then reloads the Survey.
|
||||
|
||||
=head3 $address
|
||||
|
||||
Specifies which questionType to delete.
|
||||
|
||||
=cut
|
||||
|
||||
sub removeType{
|
||||
my $self = shift;
|
||||
my $address = shift;
|
||||
$self->surveyJSON->removeType($address);
|
||||
return $self->www_loadSurvey( { address => $address } );
|
||||
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 addType ( $name, $address )
|
||||
|
||||
Adds a new questionType, and then reloads the Survey.
|
||||
|
||||
=head3 $name
|
||||
|
||||
The name of the new question type.
|
||||
|
||||
=head3 $address
|
||||
|
||||
Specifies where to add the question.
|
||||
|
||||
=cut
|
||||
|
||||
sub addType{
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
my $address = shift;
|
||||
$self->surveyJSON->addType($name,$address);
|
||||
$self->persistSurveyJSON();
|
||||
return $self->www_loadSurvey( { address => $address } );
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 copyObject ( )
|
||||
|
||||
Takes the address of a survey object and creates a copy. The copy is placed at the end of this object's parent's list.
|
||||
|
|
@ -705,8 +773,8 @@ sub www_loadSurvey {
|
|||
}
|
||||
|
||||
# Generate the list of valid goto targets
|
||||
my @gotoTargets = $self->surveyJSON->getGotoTargets;
|
||||
|
||||
my $gotoTargets = $self->surveyJSON->getGotoTargets;
|
||||
|
||||
my %buttons;
|
||||
$buttons{question} = $address->[0];
|
||||
if ( @{$address} == 2 or @{$address} == 3 ) {
|
||||
|
|
@ -753,7 +821,9 @@ sub www_loadSurvey {
|
|||
$lastType = 'answer';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my $warnings = $self->surveyJSON->validateSurvey();
|
||||
|
||||
my $return = {
|
||||
address => $address, # the address of the focused object
|
||||
buttons => \%buttons, # the data to create the Add buttons
|
||||
|
|
@ -761,7 +831,8 @@ sub www_loadSurvey {
|
|||
ddhtml => $html, # the html to create the draggable html divs
|
||||
ids => \@ids, # list of all ids passed in which are draggable (for adding events)
|
||||
type => $var->{type}, # the object type
|
||||
gotoTargets => \@gotoTargets,
|
||||
gotoTargets => $gotoTargets,
|
||||
warnings => $warnings #List of warnings to display to the user
|
||||
};
|
||||
|
||||
$self->session->http->setMimeType('application/json');
|
||||
|
|
@ -883,8 +954,8 @@ sub getResponseInfoForView {
|
|||
|
||||
my ( $code, $taken );
|
||||
|
||||
my $maxTakes = $self->getValue('maxResponsesPerUser');
|
||||
my $id = $self->session->user->userId();
|
||||
my $maxResponsesPerUser = $self->getValue('maxResponsesPerUser');
|
||||
my $userId = $self->session->user->userId();
|
||||
my $anonId
|
||||
= $self->session->form->process('userid')
|
||||
|| $self->session->http->getCookies->{Survey2AnonId}
|
||||
|
|
@ -894,45 +965,45 @@ sub getResponseInfoForView {
|
|||
my $string;
|
||||
|
||||
#if there is an anonid or id is for a WG user
|
||||
if ( $anonId or $id != 1 ) {
|
||||
if ( $anonId or $userId != 1 ) {
|
||||
$string = 'userId';
|
||||
if ($anonId) {
|
||||
$string = 'anonId';
|
||||
$id = $anonId;
|
||||
$userId = $anonId;
|
||||
}
|
||||
my $responseId
|
||||
= $self->session->db->quickScalar(
|
||||
"select Survey_responseId from Survey_response where $string = ? and assetId = ? and isComplete = 0",
|
||||
[ $id, $self->getId() ] );
|
||||
[ $userId, $self->getId() ] );
|
||||
if ( !$responseId ) {
|
||||
$code = $self->session->db->quickScalar(
|
||||
"select isComplete from Survey_response where $string = ? and assetId = ? and isComplete > 0 order by endDate desc limit 1",
|
||||
[ $id, $self->getId() ]
|
||||
[ $userId, $self->getId() ]
|
||||
);
|
||||
}
|
||||
$taken
|
||||
= $self->session->db->quickScalar(
|
||||
"select count(*) from Survey_response where $string = ? and assetId = ? and isComplete > 0",
|
||||
[ $id, $self->getId() ] );
|
||||
[ $userId, $self->getId() ] );
|
||||
|
||||
}
|
||||
elsif ( $id == 1 ) {
|
||||
elsif ( $userId == 1 ) {
|
||||
my $responseId = $self->session->db->quickScalar(
|
||||
'select Survey_responseId from Survey_response where userId = ? and ipAddress = ? and assetId = ? and isComplete = 0',
|
||||
[ $id, $ip, $self->getId() ]
|
||||
[ $userId, $ip, $self->getId() ]
|
||||
);
|
||||
if ( !$responseId ) {
|
||||
$code = $self->session->db->quickScalar(
|
||||
'select isComplete from Survey_response where userId = ? and ipAddress = ? and assetId = ? and isComplete > 0 order by endDate desc limit 1',
|
||||
[ $id, $ip, $self->getId() ]
|
||||
[ $userId, $ip, $self->getId() ]
|
||||
);
|
||||
}
|
||||
$taken = $self->session->db->quickScalar(
|
||||
'select count(*) from Survey_response where userId = ? and ipAddress = ? and assetId = ? and isComplete > 0',
|
||||
[ $id, $ip, $self->getId() ]
|
||||
[ $userId, $ip, $self->getId() ]
|
||||
);
|
||||
}
|
||||
return ( $code, $taken >= $maxTakes );
|
||||
return ( $code, $maxResponsesPerUser > 0 && $taken >= $maxResponsesPerUser );
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -1081,6 +1152,14 @@ sub www_submitQuestions {
|
|||
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub getSummary{
|
||||
my $self = shift;
|
||||
my $summary = $self->responseJSON->showSummary();
|
||||
my $out = $self->processTemplate( $summary, $self->get('surveySummaryTemplateId') );
|
||||
return $out;
|
||||
# return $self->session->style->process( $out, $self->get('styleTemplateId') );
|
||||
}
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_loadQuestions
|
||||
|
|
@ -1092,7 +1171,7 @@ Determines which questions to display to the survey taker next, loads and return
|
|||
sub www_loadQuestions {
|
||||
my $self = shift;
|
||||
my $wasRestarted = shift;
|
||||
|
||||
|
||||
if ( !$self->canTakeSurvey() ) {
|
||||
$self->session->log->debug('canTakeSurvey false, surveyEnd');
|
||||
return $self->surveyEnd();
|
||||
|
|
@ -1110,6 +1189,12 @@ sub www_loadQuestions {
|
|||
|
||||
if ( $self->responseJSON->surveyEnd() ) {
|
||||
$self->session->log->debug('Response surveyEnd, so calling surveyEnd');
|
||||
if ( $self->get('quizModeSummary') ) {
|
||||
if(! $self->session->form->param('shownsummary')){
|
||||
my $json = to_json( { type => 'summary', summary => $self->getSummary() });
|
||||
return $json;
|
||||
}
|
||||
}
|
||||
return $self->surveyEnd();
|
||||
}
|
||||
|
||||
|
|
@ -1191,7 +1276,7 @@ sub surveyEnd {
|
|||
}
|
||||
}
|
||||
}
|
||||
$url = $self->session->url->gateway($url);
|
||||
$url = $self->session->url->gateway($url) if($url !~ /^http:/i);
|
||||
#$self->session->http->setRedirect($url);
|
||||
#$self->session->http->setMimeType('application/json');
|
||||
my $json = to_json( { type => 'forward', url => $url } );
|
||||
|
|
@ -1208,17 +1293,18 @@ Sends the processed template and questions structure to the client
|
|||
|
||||
sub prepareShowSurveyTemplate {
|
||||
my ( $self, $section, $questions ) = @_;
|
||||
my %multipleChoice = (
|
||||
'Multiple Choice', 1, 'Gender', 1, 'Yes/No', 1, 'True/False', 1, 'Ideology', 1,
|
||||
'Race', 1, 'Party', 1, 'Education', 1, 'Scale', 1, 'Agree/Disagree', 1,
|
||||
'Oppose/Support', 1, 'Importance', 1, 'Likelihood', 1, 'Certainty', 1, 'Satisfaction', 1,
|
||||
'Confidence', 1, 'Effectiveness', 1, 'Concern', 1, 'Risk', 1, 'Threat', 1,
|
||||
'Security', 1
|
||||
);
|
||||
# my %multipleChoice = (
|
||||
# 'Multiple Choice', 1, 'Gender', 1, 'Yes/No', 1, 'True/False', 1, 'Ideology', 1,
|
||||
# 'Race', 1, 'Party', 1, 'Education', 1, 'Scale', 1, 'Agree/Disagree', 1,
|
||||
# 'Oppose/Support', 1, 'Importance', 1, 'Likelihood', 1, 'Certainty', 1, 'Satisfaction', 1,
|
||||
# 'Confidence', 1, 'Effectiveness', 1, 'Concern', 1, 'Risk', 1, 'Threat', 1,
|
||||
# 'Security', 1
|
||||
# );
|
||||
my %textArea = ( 'TextArea', 1 );
|
||||
my %text = ( 'Text', 1, 'Email', 1, 'Phone Number', 1, 'Text Date', 1, 'Currency', 1 );
|
||||
my %slider = ( 'Slider', 1, 'Dual Slider - Range', 1, 'Multi Slider - Allocate', 1 );
|
||||
my %dateType = ( 'Date', 1, 'Date Range', 1 );
|
||||
my %dateShort = ( 'Year Month', 1 );
|
||||
my %fileUpload = ( 'File Upload', 1 );
|
||||
my %hidden = ( 'Hidden', 1 );
|
||||
|
||||
|
|
@ -1227,7 +1313,7 @@ sub prepareShowSurveyTemplate {
|
|||
elsif ( $text{ $q->{questionType} } ) { $q->{textType} = 1; }
|
||||
elsif ( $textArea{ $q->{questionType} } ) { $q->{textAreaType} = 1; }
|
||||
elsif ( $hidden{ $q->{questionType} } ) { $q->{hidden} = 1; }
|
||||
elsif ( $multipleChoice{ $q->{questionType} } ) {
|
||||
elsif ( $self->surveyJSON->multipleChoiceTypes->{ $q->{questionType} } ) {
|
||||
$q->{multipleChoice} = 1;
|
||||
if ( $q->{maxAnswers} > 1 ) {
|
||||
$q->{maxMoreOne} = 1;
|
||||
|
|
@ -1236,6 +1322,26 @@ sub prepareShowSurveyTemplate {
|
|||
elsif ( $dateType{ $q->{questionType} } ) {
|
||||
$q->{dateType} = 1;
|
||||
}
|
||||
elsif ( $dateShort{ $q->{questionType} } ) {
|
||||
$q->{dateShort} = 1;
|
||||
foreach my $a(@{$q->{answers}}){
|
||||
$a->{months} = [
|
||||
{'month' => ''},
|
||||
{'month' => 'January'},
|
||||
{'month' => 'February'},
|
||||
{'month' => 'March'},
|
||||
{'month' => 'April'},
|
||||
{'month' => 'May'},
|
||||
{'month' => 'June'},
|
||||
{'month' => 'July'},
|
||||
{'month' => 'August'},
|
||||
{'month' => 'September'},
|
||||
{'month' => 'October'},
|
||||
{'month' => 'November'},
|
||||
{'month' => 'December'}
|
||||
];
|
||||
}
|
||||
}
|
||||
elsif ( $slider{ $q->{questionType} } ) {
|
||||
$q->{slider} = 1;
|
||||
if ( $q->{questionType} eq 'Dual Slider - Range' ) {
|
||||
|
|
@ -1331,7 +1437,7 @@ sub persistResponseJSON {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 responseId
|
||||
=head2 responseIdCookies
|
||||
|
||||
Mutator for the responseIdCookies that determines whether cookies are used as
|
||||
part of the L<"responseId"> lookup process.
|
||||
|
|
@ -1412,7 +1518,7 @@ sub responseId {
|
|||
}
|
||||
|
||||
if ( !$responseId ) {
|
||||
my $allowedTakes = $self->get('maxResponsesPerUser');
|
||||
my $maxResponsesPerUser = $self->get('maxResponsesPerUser');
|
||||
my $haveTaken;
|
||||
|
||||
if ( $id == 1 ) {
|
||||
|
|
@ -1428,7 +1534,7 @@ sub responseId {
|
|||
[ $id, $self->getId() ] );
|
||||
}
|
||||
|
||||
if ( $haveTaken < $allowedTakes ) {
|
||||
if ( $maxResponsesPerUser == 0 || $haveTaken < $maxResponsesPerUser ) {
|
||||
$responseId = $self->session->db->setRow(
|
||||
'Survey_response',
|
||||
'Survey_responseId', {
|
||||
|
|
@ -1450,7 +1556,7 @@ sub responseId {
|
|||
$self->persistResponseJSON();
|
||||
}
|
||||
else {
|
||||
$self->session->log->debug("haveTaken ($haveTaken) >= allowedTakes ($allowedTakes)");
|
||||
$self->session->log->debug("haveTaken ($haveTaken) >= maxResponsesPerUser ($maxResponsesPerUser)");
|
||||
}
|
||||
}
|
||||
$self->{responseId} = $responseId;
|
||||
|
|
@ -1475,25 +1581,26 @@ sub canTakeSurvey {
|
|||
return 0;
|
||||
}
|
||||
|
||||
my $maxTakes = $self->getValue('maxResponsesPerUser');
|
||||
my $ip = $self->session->env->getIp;
|
||||
my $id = $self->session->user->userId();
|
||||
my $takenCount = 0;
|
||||
my $maxResponsesPerUser = $self->getValue('maxResponsesPerUser');
|
||||
my $ip = $self->session->env->getIp;
|
||||
my $userId = $self->session->user->userId();
|
||||
my $takenCount = 0;
|
||||
|
||||
if ( $id == 1 ) {
|
||||
if ( $userId == 1 ) {
|
||||
$takenCount = $self->session->db->quickScalar(
|
||||
'select count(*) from Survey_response where userId = ? and ipAddress = ? '
|
||||
. 'and assetId = ? and isComplete > ?', [ $id, $ip, $self->getId(), 0 ]
|
||||
. 'and assetId = ? and isComplete > ?', [ $userId, $ip, $self->getId(), 0 ]
|
||||
);
|
||||
}
|
||||
else {
|
||||
$takenCount
|
||||
= $self->session->db->quickScalar(
|
||||
'select count(*) from Survey_response where userId = ? and assetId = ? and isComplete > ?',
|
||||
[ $id, $self->getId(), 0 ] );
|
||||
[ $userId, $self->getId(), 0 ] );
|
||||
}
|
||||
|
||||
if ( $takenCount >= $maxTakes ) {
|
||||
# A maxResponsesPerUser value of 0 implies unlimited
|
||||
if ( $maxResponsesPerUser > 0 && $takenCount >= $maxResponsesPerUser ) {
|
||||
$self->{canTake} = 0;
|
||||
}
|
||||
else {
|
||||
|
|
@ -1642,6 +1749,13 @@ sub www_viewStatisticalOverview {
|
|||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_exportTransposedResults ()
|
||||
|
||||
Exports transposed results in a tab deliniated file.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_exportSimpleResults {
|
||||
my $self = shift;
|
||||
|
||||
|
|
@ -1660,7 +1774,7 @@ sub www_exportSimpleResults {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_exportTransposedResults (){
|
||||
=head2 www_exportTransposedResults ()
|
||||
|
||||
Returns transposed results as a tabbed file.
|
||||
|
||||
|
|
|
|||
217
lib/WebGUI/Asset/Wobject/Survey/ExpressionEngine.pm
Normal file
217
lib/WebGUI/Asset/Wobject/Survey/ExpressionEngine.pm
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
package WebGUI::Asset::Wobject::Survey::ExpressionEngine;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Package WebGUI::Asset::Wobject::Survey::ExpressionEngine
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This class is used to process Survey gotoExpressions.
|
||||
|
||||
See L<run> for more details.
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use Params::Validate qw(:all);
|
||||
use Safe;
|
||||
use Data::Dumper;
|
||||
use List::Util qw/sum/;
|
||||
Params::Validate::validation_options( on_fail => sub { WebGUI::Error::InvalidParam->throw( error => shift ) } );
|
||||
|
||||
# We need these as semi-globals so that utility subs (which are shared with the safe compartment)
|
||||
# can access them.
|
||||
my $session;
|
||||
my $values;
|
||||
my $scores;
|
||||
my $jump_count;
|
||||
my $validate;
|
||||
my $validTargets;
|
||||
|
||||
=head2 value
|
||||
|
||||
Utility sub that gives expressions access to recorded response values
|
||||
|
||||
value(question_variable) returns the recorded response value for the answer to question_variable
|
||||
|
||||
=cut
|
||||
|
||||
sub value($) {
|
||||
my $key = shift;
|
||||
my $value = $values->{$key};
|
||||
$session->log->debug("[$key] resolves to [$value]");
|
||||
return $value; # scalar variable, so no need to clone
|
||||
}
|
||||
|
||||
=head2 score
|
||||
|
||||
Utility sub that gives expressions access to recorded response scores.
|
||||
|
||||
score(question_variable) returns the score for the answer selected for question_variable
|
||||
score(section_variable) returns the summed score for the answers to all the questions in section_variable
|
||||
|
||||
=cut
|
||||
|
||||
sub score($) {
|
||||
my $key = shift;
|
||||
my $score = $scores->{$key};
|
||||
$session->log->debug("[$key] resolves to [$score]");
|
||||
return $score; # scalar variable, so no need to clone
|
||||
}
|
||||
|
||||
=head2 jump
|
||||
|
||||
Utility sub shared with Safe compartment so that expressions can call individual jump tests.
|
||||
|
||||
Throws an exception containing the jump target when a jump matches, thus allowing L<run> to
|
||||
catch the first successful jump.
|
||||
|
||||
=cut
|
||||
|
||||
sub jump(&$) {
|
||||
my ( $sub, $target ) = @_;
|
||||
$jump_count++;
|
||||
|
||||
# If $validTargets known, make sure target is valid
|
||||
if ($validTargets && !exists $validTargets->{$target}) {
|
||||
$session->log->debug("Invalid target [$target]");
|
||||
if ($validate) {
|
||||
die("Invalid jump target \"$target\""); # bail and report error
|
||||
} else {
|
||||
return; # skip jump but continue with expression
|
||||
}
|
||||
}
|
||||
|
||||
if ( $sub->() ) {
|
||||
$session->log->debug("jump call #$jump_count is truthy");
|
||||
die( { jump => $target } );
|
||||
}
|
||||
else {
|
||||
$session->log->debug("jump call #$jump_count is falsey");
|
||||
}
|
||||
}
|
||||
|
||||
=head2 avg
|
||||
|
||||
Utility sub shared with Safe compartment to allows expressions to easily compute the average of a list
|
||||
|
||||
=cut
|
||||
|
||||
sub avg {
|
||||
my @vals = @_;
|
||||
return sum(@vals) / @vals;
|
||||
}
|
||||
|
||||
=head2 run ( $session, $expression, $opts )
|
||||
|
||||
Class method.
|
||||
|
||||
Evaluates the given expression in a Safe compartment.
|
||||
|
||||
=head3 session
|
||||
|
||||
A WebGUI::Session
|
||||
|
||||
=head3 expression
|
||||
|
||||
The expression to run.
|
||||
|
||||
A gotoExpression is essentially a perl expression that gets evaluated in a Safe compartment.
|
||||
|
||||
To access Section/Question recorded response values, the expression calls L<value>.
|
||||
To access Section/Question recorded response scores, the expression calls L<score>.
|
||||
To trigger a jump, the expression calls L<jump>. The first truthy jump succeeds.
|
||||
We also give expressions access to some useful utility subs such as avg(), and all of the
|
||||
handy subs from List::Util (min, max, sum, etc..).
|
||||
|
||||
A very simple expression that checks if the response to s1q1 is 0 might look like:
|
||||
|
||||
jump { value(s1q1) == 0 } target
|
||||
|
||||
A more complicated gotoExpression with two possible jumps might look like:
|
||||
|
||||
jump { value(q1) > 5 and value(s2q1) =~ m/textmatch/ } target1;
|
||||
jump { avg(value(q1), value(q2), value(q3)) > 10 } target2;
|
||||
|
||||
=head3 opts (optional)
|
||||
|
||||
Supported options are:
|
||||
|
||||
=over 3
|
||||
|
||||
=item * values
|
||||
|
||||
Hashref of values to make available to the expression via the L<value> utility sub
|
||||
|
||||
=item * scores
|
||||
|
||||
Hashref of scores to make available to the expression via the L<score> utility sub
|
||||
|
||||
=item* validTargets
|
||||
|
||||
A hashref of valid jump targets. If this is provided, all L<jump> calls will fail unless
|
||||
the specified target is a key in the hashref.
|
||||
|
||||
=item * validate
|
||||
|
||||
Return errors rather than just logging them (useful for displaying survey validation errors to users)
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub run {
|
||||
my $class = shift;
|
||||
my ( $s, $expression, $opts )
|
||||
= validate_pos( @_, { isa => 'WebGUI::Session' }, { type => SCALAR }, { type => HASHREF, default => {} } );
|
||||
|
||||
# Init package globals
|
||||
( $session, $values, $scores, $jump_count, $validate, $validTargets ) = ( $s, $opts->{values}, $opts->{scores}, 0, $opts->{validate}, $opts->{validTargets} );
|
||||
|
||||
if (!$session->config->get('enableSurveyExpressionEngine')) {
|
||||
$session->log->debug('enableSurveyExpressionEngine config option disabled, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
# Create the Safe compartment
|
||||
my $compartment = Safe->new();
|
||||
|
||||
# Share our utility subs with the compartment
|
||||
$compartment->share('&value');
|
||||
$compartment->share('&score');
|
||||
$compartment->share('&jump');
|
||||
$compartment->share('&avg');
|
||||
|
||||
# Give them all of List::Util too
|
||||
$compartment->share_from('List::Util', ['&first', '&max', '&maxstr', '&min', '&minstr', '&reduce', '&shuffle', '&sum',]);
|
||||
|
||||
$session->log->debug("Expression is: \"$expression\"");
|
||||
$compartment->reval($expression);
|
||||
|
||||
# See if we ran the engine just to check for errors
|
||||
if ($opts->{validate}) {
|
||||
if ($@ && ref $@ ne 'HASH') {
|
||||
my $error = $@;
|
||||
$error =~ s/(.*?) at .*/$1/s; # don't reveal too much
|
||||
return $error;
|
||||
}
|
||||
return; # no validation errors
|
||||
}
|
||||
|
||||
# A successful jump triggers a hashref containing the jump target to be thrown
|
||||
if ( ref $@ && ref $@ eq 'HASH' && $@->{jump} ) {
|
||||
my $jump = $@->{jump};
|
||||
$session->log->debug("Returning [$jump]");
|
||||
return $jump;
|
||||
}
|
||||
|
||||
# Log all other errors (for example compile errors from bad expressions)
|
||||
if ($@) {
|
||||
$session->log->error($@);
|
||||
}
|
||||
|
||||
# Return undef on failure
|
||||
return;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -28,7 +28,7 @@ As a whole, this class represents the complete state of a user's response to a S
|
|||
At the heart of this class is a perl hash that can be serialized
|
||||
as JSON to the database to allow for storage and retrieval of the complete state
|
||||
of a survey response.
|
||||
|
||||
|
||||
Survey instances that allow users to record multiple responses will persist multiple
|
||||
instances of this class to the database (one per distinct user response).
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ number of questions answered (L<"questionsAnswered">) and the Survey start time
|
|||
This package is not intended to be used by any other Asset in WebGUI.
|
||||
|
||||
=head2 surveyOrder
|
||||
|
||||
|
||||
This data strucutre is an array (reference) of Survey addresses (see
|
||||
L<WebGUI::Asset::Wobject::Survey::SurveyJSON/Address Parameter>), stored in the order
|
||||
in which items are presented to the user.
|
||||
|
|
@ -70,7 +70,7 @@ is stored in this hash reference.
|
|||
|
||||
Questions keys are constructed by hypenating the relevant L<"sIndex"> and L<"qIndex">.
|
||||
Answer keys are constructed by hypenating the relevant L<"sIndex">, L<"qIndex"> and L<aIndex|"aIndexes">.
|
||||
|
||||
|
||||
Question entries only contain a comment field:
|
||||
{
|
||||
...
|
||||
|
|
@ -79,7 +79,7 @@ Question entries only contain a comment field:
|
|||
}
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
Answers entries contain: value (the recorded value), time and comment fields.
|
||||
|
||||
{
|
||||
|
|
@ -98,6 +98,7 @@ use strict;
|
|||
use JSON;
|
||||
use Params::Validate qw(:all);
|
||||
use List::Util qw(shuffle);
|
||||
use Safe;
|
||||
Params::Validate::validation_options( on_fail => sub { WebGUI::Error::InvalidParam->throw( error => shift ) } );
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -430,9 +431,9 @@ Processes and records submitted survey responses in the L<"responses"> data stru
|
|||
Does terminal handling, and branch processing, and advances the L<"lastResponse"> index
|
||||
if all required questions have been answered.
|
||||
|
||||
=head3 $responses
|
||||
=head3 $submittedResponses
|
||||
|
||||
A hash ref of form param data. Each element should look like:
|
||||
A hash ref of submitted form param data. Each element should look like:
|
||||
|
||||
{
|
||||
"questionId-comment" => "question comment",
|
||||
|
|
@ -459,11 +460,11 @@ gotoExpression in the set of questions wins.
|
|||
|
||||
sub recordResponses {
|
||||
my $self = shift;
|
||||
my ($responses) = validate_pos( @_, { type => HASHREF } );
|
||||
my ($submittedResponses) = validate_pos( @_, { type => HASHREF } );
|
||||
|
||||
# Build a lookup table of non-multiple choice question types
|
||||
my %knownTypes = map {$_ => 1} $self->survey->specialQuestionTypes;
|
||||
|
||||
my %knownTypes = map {$_ => 1} @{$self->survey->specialQuestionTypes};
|
||||
|
||||
# We want to record responses against the "next" response section and questions, since these are
|
||||
# the items that have just been displayed to the user.
|
||||
my $section = $self->nextResponseSection();
|
||||
|
|
@ -517,37 +518,40 @@ sub recordResponses {
|
|||
}
|
||||
|
||||
# Record Question comment
|
||||
$self->responses->{ $question->{id} }->{comment} = $responses->{ $question->{id} . 'comment' };
|
||||
$self->responses->{ $question->{id} }->{comment} = $submittedResponses->{ $question->{id} . 'comment' };
|
||||
|
||||
# Process Answers in Question..
|
||||
for my $answer ( @{ $question->{answers} } ) {
|
||||
|
||||
# Pluck the values out of the responses hash that we want to record..
|
||||
my $answerValue = $responses->{ $answer->{id} };
|
||||
my $answerComment = $responses->{ $answer->{id} . 'comment' };
|
||||
my $submittedAnswerResponse = $submittedResponses->{ $answer->{id} };
|
||||
my $submittedAnswerComment = $submittedResponses->{ $answer->{id} . 'comment' };
|
||||
|
||||
# Proceed if we're satisfied that response is valid..
|
||||
if ( defined $answerValue && $answerValue =~ /\S/ ) {
|
||||
# Proceed if we're satisfied that the submitted answer response is valid..
|
||||
if ( defined $submittedAnswerResponse && $submittedAnswerResponse =~ /\S/ ) {
|
||||
$aAnswered = 1;
|
||||
if ($knownTypes{$question->{questionType}}) {
|
||||
$self->responses->{ $answer->{id} }->{value} = $answerValue;
|
||||
} else {
|
||||
# Unknown type, must be a multi-choice bundle
|
||||
# For Multi-choice, use recordedAnswer instead of answerValue
|
||||
$self->responses->{ $answer->{id} }->{value} = $answer->{recordedAnswer};
|
||||
}
|
||||
$self->responses->{ $answer->{id} }->{time} = time;
|
||||
$self->responses->{ $answer->{id} }->{comment} = $answerComment;
|
||||
|
||||
# Now, decide what to record. For multi-choice questions, use recordedAnswer.
|
||||
# Otherwise, we use the (raw) submitted response (e.g. text input, date input etc..)
|
||||
$self->responses->{ $answer->{id} }->{value}
|
||||
= $knownTypes{ $question->{questionType} }
|
||||
? $submittedAnswerResponse
|
||||
: $answer->{recordedAnswer};
|
||||
|
||||
$self->responses->{ $answer->{id} }->{time} = time;
|
||||
$self->responses->{ $answer->{id} }->{comment} = $submittedAnswerComment;
|
||||
|
||||
# Handle terminal Answers..
|
||||
if ( $answer->{terminal} ) {
|
||||
$terminal = 1;
|
||||
$terminalUrl = $answer->{terminalUrl};
|
||||
}
|
||||
|
||||
# ..and also gotos..
|
||||
elsif ( $answer->{goto} =~ /\w/ ) {
|
||||
$goto = $answer->{goto};
|
||||
}
|
||||
|
||||
# .. and also gotoExpressions..
|
||||
elsif ( $answer->{gotoExpression} =~ /\w/ ) {
|
||||
$gotoExpression = $answer->{gotoExpression};
|
||||
|
|
@ -645,89 +649,26 @@ indicates that we should branch.
|
|||
|
||||
=head3 $gotoExpression
|
||||
|
||||
The gotoExpression.
|
||||
|
||||
A gotoExpression is a string representing a list of expressions (one per line) of the form:
|
||||
target: expression
|
||||
target: expression
|
||||
...
|
||||
|
||||
This subroutine iterates through the list, processing each line and, all things being
|
||||
well, evaluates the expression. The first expression to evaluate to true triggers a
|
||||
call to goto($target).
|
||||
|
||||
The expression is a simple subset of the formula language used in spreadsheet programs
|
||||
such as Excel, OpenOffice, Google Docs etc..
|
||||
|
||||
Here is an example using section variables S1 and S2 as jump targets and question
|
||||
variables Q1-3 in the expression. It jumps to S1 if the user's answer to Q1 has a value
|
||||
of 3, jumps to S2 if Q2 + Q3 < 10, and otherwise doesn't branch at all (the default).
|
||||
S1: Q1 = 3
|
||||
S2: Q2 + Q3 < 10
|
||||
|
||||
Arguments are evaluated as follows:
|
||||
|
||||
Numeric arguments evaluate as numbers
|
||||
|
||||
=over 4
|
||||
|
||||
=item * No support for strings (and hence no string matching)
|
||||
|
||||
=item * Question variable names (e.g. Q1) evaluate to the numeric value associated with
|
||||
user's answer to that question, or undefined if the user has not answered that question
|
||||
|
||||
=back
|
||||
|
||||
Binary comparisons operators: = != < <= >= >
|
||||
|
||||
=over 4
|
||||
|
||||
=item * return boolean values based on perl's equivalent numeric comparison operators
|
||||
|
||||
=back
|
||||
|
||||
Simple math operators: + - * /
|
||||
|
||||
=over 4
|
||||
|
||||
=item * return numeric values
|
||||
|
||||
=back
|
||||
|
||||
Later we may add Boolean operators: AND( x; y; z; ... ), OR( x; y; z; ... ), NOT( x ), with args separated by
|
||||
semicolons (presumably because spreadsheet formulas use commas to indicate cell ranges)
|
||||
|
||||
Later still you may be able to say AVG(section1) or SUM(section3) and have those functions automatically
|
||||
compute their result over the set of all questions in the given section.
|
||||
But for now those things can be done manually using the limited subset defined.
|
||||
The gotoExpression. See L<WebGUI::Asset::Wobject::Survey::ExpressionEngine> for more info.
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
sub processGotoExpression {
|
||||
my $self = shift;
|
||||
my ($expression) = validate_pos(@_, {type => SCALAR});
|
||||
|
||||
my $responses = $self->recordedResponses();
|
||||
|
||||
# Parse gotoExpressions one after the other (first one that's true wins)
|
||||
foreach my $line (split /\n/, $expression) {
|
||||
my $processed = $self->parseGotoExpression($line, $responses);
|
||||
|
||||
next if !$processed;
|
||||
|
||||
# (ab)use perl's eval to evaluate the processed expression
|
||||
my $result = eval "$processed->{expression}"; ## no critic
|
||||
$self->session->log->warn($@) if $@; ## no critic
|
||||
|
||||
if ($result) {
|
||||
$self->session->log->debug("Truthy, goto [$processed->{target}]");
|
||||
$self->processGoto($processed->{target});
|
||||
return $processed;
|
||||
} else {
|
||||
$self->session->log->debug('Falsy, not branching');
|
||||
next;
|
||||
}
|
||||
|
||||
# Prepare the ingredients..
|
||||
my $values = $self->responseValuesByVariableName;
|
||||
my $scores = $self->responseScoresByVariableName;
|
||||
my %validTargets = map { $_ => 1 } @{$self->survey->getGotoTargets};
|
||||
|
||||
use WebGUI::Asset::Wobject::Survey::ExpressionEngine;
|
||||
my $engine = "WebGUI::Asset::Wobject::Survey::ExpressionEngine";
|
||||
if (my $jump = $engine->run($self->session, $expression, { values => $values, scores => $scores, validTargets => \%validTargets} )) {
|
||||
$self->session->log->debug("Hit. Jumping to [$jump]");
|
||||
$self->processGoto($jump);
|
||||
}
|
||||
$self->session->log->debug("No hits, falling through");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -735,111 +676,129 @@ sub processGotoExpression {
|
|||
|
||||
=head2 recordedResponses
|
||||
|
||||
Returns a hash (reference) of question responses. The hash keys are
|
||||
question variable names. The hash values are the corresponding answer
|
||||
values selected by the user.
|
||||
Returns an array or response information in this response's survey order.
|
||||
|
||||
=cut
|
||||
|
||||
sub recordedResponses {
|
||||
sub recordedResponses{
|
||||
my $self = shift;
|
||||
|
||||
my $responses= {
|
||||
# questionName => response answer value
|
||||
};
|
||||
|
||||
# Populate %responses with the user's data..
|
||||
my $responses= [
|
||||
# {answer info hash}
|
||||
];
|
||||
# Populate @$responses with the user's data..
|
||||
for my $address ( @{ $self->surveyOrder } ) {
|
||||
my $question = $self->survey->question( $address );
|
||||
my ($sIndex, $qIndex) = (sIndex($address), qIndex($address));
|
||||
for my $aIndex (aIndexes($address)) {
|
||||
my $question = $self->survey->question([$sIndex,$qIndex]);
|
||||
my $answerId = $self->answerId($sIndex, $qIndex, $aIndex);
|
||||
if ( defined $self->responses->{$answerId} ) {
|
||||
my $answer = $self->survey->answer( [ $sIndex, $qIndex, $aIndex ] );
|
||||
$responses->{$question->{variable}}
|
||||
= $answer->{value} =~ /\w/ ? $answer->{value}
|
||||
: $question->{value}
|
||||
;
|
||||
push(@$responses, {
|
||||
value => $answer->{value} =~ /\w/ ? $answer->{value} : $question->{value},
|
||||
recordedAnswer => $answer->{recordedAnswer},
|
||||
isCorrect => $answer->{isCorrect},
|
||||
answerText => $answer->{text},
|
||||
address => [$sIndex,$qIndex,$aIndex],
|
||||
questionText => $question->{text},
|
||||
questionValue => $question->{value},
|
||||
questionType => $question->{questionType}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $responses;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 parseGotoExpression( ( $expression, $responses)
|
||||
=head2 responseValuesByVariableName
|
||||
|
||||
Parses a single gotoExpression. Returns undef if processing fails, or the following hashref
|
||||
if things work out well:
|
||||
{ target => $target, expression => $expression }
|
||||
Returns a lookup table to question variable names and recorded response values.
|
||||
|
||||
=head3 $expression
|
||||
|
||||
The expression to process
|
||||
|
||||
=head3 $responses
|
||||
|
||||
Hashref that maps questionNames to response values
|
||||
|
||||
=head3 Explanation:
|
||||
|
||||
Uses the following simple strategy:
|
||||
|
||||
First, parse the expression as:
|
||||
target: expression
|
||||
|
||||
Replace each questionName with its response value (from the $responses hashref)
|
||||
|
||||
Massage the expression into valid perl
|
||||
|
||||
Check that only valid tokens remain. This last step ensures that any invalid questionNames in
|
||||
the expression generate an error because our list of valid tokens doesn't include a-z
|
||||
Only questions with a defined variable name set are included. Values come from
|
||||
the L<responses> hash.
|
||||
|
||||
=cut
|
||||
|
||||
sub parseGotoExpression {
|
||||
my $self = shift;
|
||||
my ($expression, $responses) = validate_pos(@_, { type => SCALAR }, { type => HASHREF, default => {} });
|
||||
|
||||
$self->session->log->debug("Parsing gotoExpression: $expression");
|
||||
|
||||
# Valid gotoExpression tokens are..
|
||||
my $tokens = qr{\s|[-0-9=!<>+*/.()]};
|
||||
|
||||
my ( $target, $rest ) = $expression =~ /\s* ([^:]+?) \s* : \s* (.*)/x;
|
||||
|
||||
$self->session->log->debug("Parsed as Target: [$target], Expression: [$rest]");
|
||||
|
||||
if ( !defined $target ) {
|
||||
$self->session->log->warn('Target undefined');
|
||||
return;
|
||||
sub responseValuesByVariableName {
|
||||
my $self = shift;
|
||||
|
||||
my %lookup;
|
||||
while (my ($address, $response) = each %{$self->responses}) {
|
||||
next if (!$response || !$address);
|
||||
|
||||
# Turn responses s-q-a string into an address array
|
||||
my @address = split /-/, $address;
|
||||
|
||||
# Filter out the non-answer entries
|
||||
next unless @address == 3;
|
||||
|
||||
# Grab the corresponding question
|
||||
my $question = $self->survey->question([@address]);
|
||||
|
||||
# Filter out questions without defined variable names
|
||||
next if !$question || !defined $question->{variable};
|
||||
|
||||
# Add variable => value to our hash
|
||||
$lookup{$question->{variable}} = $response->{value};
|
||||
}
|
||||
return \%lookup;
|
||||
}
|
||||
|
||||
if ( !defined $rest || $rest eq q{} ) {
|
||||
$self->session->log->warn('Expression undefined');
|
||||
return;
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 responseScoresByVariableName
|
||||
|
||||
Returns a lookup table to question variable names and recorded response values.
|
||||
|
||||
Only questions with a defined variable name set are included. Scores come from
|
||||
the L<responses> hash.
|
||||
|
||||
=cut
|
||||
|
||||
sub responseScoresByVariableName {
|
||||
my $self = shift;
|
||||
|
||||
my %lookup;
|
||||
while (my ($address, $response) = each %{$self->responses}) {
|
||||
next if (!$response || !$address);
|
||||
|
||||
# Turn responses s-q-a string into an address array
|
||||
my @address = split /-/, $address;
|
||||
|
||||
# Filter out the non-answer entries
|
||||
next unless @address == 3;
|
||||
|
||||
# Grab the corresponding question
|
||||
my $question = $self->survey->question([@address]);
|
||||
|
||||
# Filter out questions without defined variable names
|
||||
next if !$question || !defined $question->{variable};
|
||||
|
||||
# Grab the corresponding answer
|
||||
my $answer = $self->survey->answer([@address]);
|
||||
|
||||
# Add variable => score to our hash
|
||||
$lookup{$question->{variable}} = $answer->{value};
|
||||
}
|
||||
|
||||
# Replace each questionName with its response value
|
||||
while ( my ( $questionName, $response ) = each %{$responses} ) {
|
||||
$rest =~ s/$questionName/$response/g;
|
||||
|
||||
# Add section score totals
|
||||
for my $s (@{$self->survey->sections}) {
|
||||
next unless $s->{variable};
|
||||
|
||||
my $score = 0;
|
||||
for my $q (@{$s->{questions}}) {
|
||||
next unless $q->{variable};
|
||||
next unless exists $lookup{$q->{variable}};
|
||||
|
||||
$lookup{$s->{variable}} += $lookup{$q->{variable}};
|
||||
}
|
||||
}
|
||||
|
||||
# convert '=' to '==' but don't touch '!=', '<=' or '>='
|
||||
$rest =~ s/(?<![!<>])=(?!=)/==/g;
|
||||
|
||||
if ( $rest !~ /^$tokens+$/ ) {
|
||||
$self->session->log->warn("Contains invalid tokens: $rest");
|
||||
return;
|
||||
}
|
||||
|
||||
$self->session->log->debug("Processed as: $rest");
|
||||
|
||||
return {
|
||||
target => $target,
|
||||
expression => $rest,
|
||||
};
|
||||
|
||||
return \%lookup;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -915,11 +874,12 @@ sub nextQuestions {
|
|||
my $section = $self->nextResponseSection();
|
||||
my $sectionIndex = $self->nextResponseSectionIndex;
|
||||
my $questionsPerPage = $self->survey->section( [ $self->nextResponseSectionIndex ] )->{questionsPerPage};
|
||||
|
||||
# Get all of the existing question responses (so that we can do Section and Question [[var]] replacements
|
||||
my $recordedResponses = $self->recordedResponses();
|
||||
my $responseValuesByVariableName = $self->responseValuesByVariableName();
|
||||
|
||||
# Do text replacement
|
||||
$section->{text} = $self->getTemplatedText($section->{text}, $recordedResponses);
|
||||
$section->{text} = $self->getTemplatedText($section->{text}, $responseValuesByVariableName);
|
||||
|
||||
# Collect all the questions to be shown on the next page..
|
||||
my @questions;
|
||||
|
|
@ -942,7 +902,7 @@ sub nextQuestions {
|
|||
my %questionCopy = %{$self->survey->question( $address )};
|
||||
|
||||
# Do text replacement
|
||||
$questionCopy{text} = $self->getTemplatedText($questionCopy{text}, $recordedResponses);
|
||||
$questionCopy{text} = $self->getTemplatedText($questionCopy{text}, $responseValuesByVariableName);
|
||||
|
||||
# Add any extra fields we want..
|
||||
$questionCopy{id} = $self->questionId($sIndex, $qIndex);
|
||||
|
|
@ -954,7 +914,7 @@ sub nextQuestions {
|
|||
my %answerCopy = %{ $self->survey->answer( [ $sIndex, $qIndex, $aIndex ] ) };
|
||||
|
||||
# Do text replacement
|
||||
$answerCopy{text} = $self->getTemplatedText($answerCopy{text}, $recordedResponses);
|
||||
$answerCopy{text} = $self->getTemplatedText($answerCopy{text}, $responseValuesByVariableName);
|
||||
|
||||
# Add any extra fields we want..
|
||||
$answerCopy{id} = $self->answerId($sIndex, $qIndex, $aIndex);
|
||||
|
|
@ -1086,7 +1046,116 @@ sub aIndexes {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 returnResponsesForReporting
|
||||
=head2 showSummary ( [$sectionAddresses] )
|
||||
|
||||
showSummary returns the current responses summary for the entire response, if
|
||||
no address is passed in, or just the sections addressed by $sectionAddresses.
|
||||
|
||||
For each section, the total correct, wrong, time taken, and points are returned. And each
|
||||
question is listed with the text, given score, user response, and if it was correct.
|
||||
This list is meant for a template and only what is needed should be shown.
|
||||
|
||||
A summary of the entire suvey,
|
||||
|
||||
=cut
|
||||
|
||||
sub showSummary{
|
||||
my $self = shift;
|
||||
my $sectionAddies = shift;#array of section addresses
|
||||
|
||||
my $all = 0;
|
||||
$all = 1 if(! $sectionAddies);
|
||||
|
||||
my ($summaries);
|
||||
|
||||
my $responses = $self->recordedResponses();
|
||||
my %goodSection;
|
||||
map{$goodSection{$_} = 1} @$sectionAddies;
|
||||
|
||||
return if(! $responses);
|
||||
|
||||
my ($sectionIndex, $questionIndex, $answerIndex) = (-1, -1, -1);
|
||||
my ($currentSection,$currentQuestion) = (-1, -1);
|
||||
|
||||
($summaries->{totalCorrect},$summaries->{totalIncorrect}) = (0,0);
|
||||
|
||||
for my $response (@$responses){
|
||||
if(! $all and ! $goodSection{$response->{address}->[0]}){next;}
|
||||
if($response->{isCorrect}){
|
||||
$summaries->{totalCorrect}++;
|
||||
}else{
|
||||
$summaries->{totalIncorrect}++;
|
||||
}
|
||||
$summaries->{totalAnswers}++;
|
||||
if($currentSection != $response->{address}->[0]){
|
||||
$summaries->{totalSections}++;
|
||||
$sectionIndex++;
|
||||
$questionIndex = -1;
|
||||
$answerIndex = -1;
|
||||
$currentQuestion = -1;
|
||||
$currentSection = $response->{address}->[0];
|
||||
_loadSectionIntoSummary(\%{$summaries->{sections}->[$sectionIndex]},$response);
|
||||
}
|
||||
if($currentQuestion != $response->{address}->[1]){
|
||||
$summaries->{totalQuestions}++;
|
||||
$questionIndex++;
|
||||
$answerIndex = -1;
|
||||
$currentQuestion = $response->{address}->[1];
|
||||
_loadQuestionIntoSummary(\%{$summaries->{sections}->[$sectionIndex]->{questions}->[$questionIndex]},$response);
|
||||
}
|
||||
$answerIndex++;
|
||||
_loadAnswerIntoSummary(\%{$summaries->{sections}->[$sectionIndex]->{questions}->[$questionIndex]->{answers}->[$answerIndex]},
|
||||
$response,
|
||||
$self->survey->{multipleChoiceTypes});
|
||||
}
|
||||
return $summaries;
|
||||
}
|
||||
sub _loadAnswerIntoSummary{
|
||||
my $node = shift;
|
||||
my $response = shift;
|
||||
my $types = shift;
|
||||
|
||||
$node->{id} = $response->{address}->[2] + 1;
|
||||
if($response->{isCorrect}){
|
||||
$node->{iscorrect} = 1;
|
||||
$node->{score} = $response->{value};
|
||||
}else{
|
||||
$node->{iscorrect} = 0;
|
||||
$node->{score} = 0;
|
||||
}
|
||||
$node->{text} = $response->{answerText};
|
||||
|
||||
#test if it is a multiple choide type
|
||||
if($types->{$response->{questionType}}){
|
||||
$node->{value} = $response->{value};
|
||||
}else{
|
||||
$node->{value} = $response->{recordedValue};
|
||||
}
|
||||
}
|
||||
sub _loadQuestionIntoSummary{
|
||||
my $node = shift;
|
||||
my $response = shift;
|
||||
$node->{id} = $response->{address}->[1] + 1;
|
||||
$node->{text} = $response->{questionText};
|
||||
}
|
||||
sub _loadSectionIntoSummary{
|
||||
my $node = shift;
|
||||
my $response = shift;
|
||||
$node->{id} = $response->{address}->[0] + 1;
|
||||
$node->{inCorrect} = 0 if(!defined $node->{section}->{inCorrect});
|
||||
$node->{score} = 0 if(!defined $node->{section}->{score});
|
||||
$node->{correct} = 0 if(!defined $node->{section}->{correct});
|
||||
if($response->{isCorrect}){
|
||||
$node->{score} += $response->{value};
|
||||
$node->{correct}++;
|
||||
}else{
|
||||
$node->{inCorrect}++;
|
||||
}
|
||||
|
||||
}
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 returnResponseForReporting
|
||||
|
||||
Used to extract JSON responses for use in reporting results.
|
||||
|
||||
|
|
@ -1096,7 +1165,7 @@ recorded value, and the id of the answer.
|
|||
|
||||
=cut
|
||||
|
||||
# TODO: This sub should make use of recordedResponses
|
||||
# TODO: This sub should make use of responseValuesByVariableName
|
||||
|
||||
sub returnResponseForReporting {
|
||||
my $self = shift;
|
||||
|
|
|
|||
|
|
@ -48,79 +48,18 @@ likely operate on the question indexed by:
|
|||
|
||||
use strict;
|
||||
use JSON;
|
||||
use Data::Dumper;
|
||||
use Params::Validate qw(:all);
|
||||
Params::Validate::validation_options( on_fail => sub { WebGUI::Error::InvalidParam->throw( error => shift ) } );
|
||||
|
||||
# N.B. We're currently using Storable::dclone instead of Clone::clone
|
||||
# because Colin uncovered some Clone bugs in Perl 5.10
|
||||
#use Clone qw/clone/;
|
||||
use Storable qw/dclone/;
|
||||
use Clone qw/clone/;
|
||||
|
||||
# The maximum value of questionsPerPage is currently hardcoded here
|
||||
my $MAX_QUESTIONS_PER_PAGE = 20;
|
||||
|
||||
my %MULTI_CHOICE_BUNDLES = (
|
||||
'Agree/Disagree' => [ 'Strongly disagree', (q{}) x 5, 'Strongly agree' ],
|
||||
Certainty => [ 'Not at all certain', (q{}) x 9, 'Extremely certain' ],
|
||||
Concern => [ 'Not at all concerned', (q{}) x 9, 'Extremely concerned' ],
|
||||
Confidence => [ 'Not at all confident', (q{}) x 9, 'Extremely confident' ],
|
||||
Education => [
|
||||
'Elementary or some high school',
|
||||
'High school/GED',
|
||||
'Some college/vocational school',
|
||||
'College graduate',
|
||||
'Some graduate work',
|
||||
'Master\'s degree',
|
||||
'Doctorate (of any type)',
|
||||
'Other degree (verbatim)',
|
||||
],
|
||||
Effectiveness => [ 'Not at all effective', (q{}) x 9, 'Extremely effective' ],
|
||||
Gender => [qw( Male Female )],
|
||||
Ideology => [
|
||||
'Strongly liberal',
|
||||
'Liberal',
|
||||
'Somewhat liberal',
|
||||
'Middle of the road',
|
||||
'Slightly conservative',
|
||||
'Conservative',
|
||||
'Strongly conservative'
|
||||
],
|
||||
Importance => [ 'Not at all important', (q{}) x 9, 'Extremely important' ],
|
||||
Likelihood => [ 'Not at all likely', (q{}) x 9, 'Extremely likely' ],
|
||||
'Oppose/Support' => [ 'Strongly oppose', (q{}) x 5, 'Strongly support' ],
|
||||
Party =>
|
||||
[ 'Democratic party', 'Republican party (or GOP)', 'Independent party', 'Other party (verbatim)' ],
|
||||
Race =>
|
||||
[ 'American Indian', 'Asian', 'Black', 'Hispanic', 'White non-Hispanic', 'Something else (verbatim)' ],
|
||||
Risk => [ 'No risk', (q{}) x 9, 'Extreme risk' ],
|
||||
Satisfaction => [ 'Not at all satisfied', (q{}) x 9, 'Extremely satisfied' ],
|
||||
Security => [ 'Not at all secure', (q{}) x 9, 'Extremely secure' ],
|
||||
Threat => [ 'No threat', (q{}) x 9, 'Extreme threat' ],
|
||||
'True/False' => [qw( True False )],
|
||||
'Yes/No' => [qw( Yes No )],
|
||||
Scale => [q{}],
|
||||
'Multiple Choice' => [q{}],
|
||||
);
|
||||
|
||||
my @SPECIAL_QUESTION_TYPES = (
|
||||
'Dual Slider - Range',
|
||||
'Multi Slider - Allocate',
|
||||
'Slider',
|
||||
'Currency',
|
||||
'Email',
|
||||
'Phone Number',
|
||||
'Text',
|
||||
'Text Date',
|
||||
'TextArea',
|
||||
'File Upload',
|
||||
'Date',
|
||||
'Date Range',
|
||||
'Hidden',
|
||||
);
|
||||
|
||||
sub specialQuestionTypes {
|
||||
return @SPECIAL_QUESTION_TYPES;
|
||||
}
|
||||
#sub specialQuestionTypes {
|
||||
# return @SPECIAL_QUESTION_TYPES;
|
||||
#}
|
||||
|
||||
=head2 new ( $session, json )
|
||||
|
||||
|
|
@ -153,6 +92,9 @@ sub new {
|
|||
|
||||
bless $self, $class;
|
||||
|
||||
#Load question types
|
||||
$self->loadTypes();
|
||||
|
||||
# Initialise the survey data structure if empty..
|
||||
if ( $self->totalSections == 0 ) {
|
||||
$self->newObject( [] );
|
||||
|
|
@ -160,6 +102,78 @@ sub new {
|
|||
return $self;
|
||||
}
|
||||
|
||||
=head2 loadTypes
|
||||
|
||||
Loads the Multiple Choice and Special Question types
|
||||
|
||||
=cut
|
||||
|
||||
sub loadTypes {
|
||||
my $self = shift;
|
||||
@{$self->{specialQuestionTypes}} = (
|
||||
'Dual Slider - Range',
|
||||
'Multi Slider - Allocate',
|
||||
'Slider',
|
||||
'Currency',
|
||||
'Email',
|
||||
'Phone Number',
|
||||
'Text',
|
||||
'Text Date',
|
||||
'TextArea',
|
||||
'File Upload',
|
||||
'Date',
|
||||
'Date Range',
|
||||
'Year Month',
|
||||
'Hidden',
|
||||
);
|
||||
my $refs = $self->session->db->buildArrayRefOfHashRefs("SELECT questionType, answers FROM Survey_questionTypes");
|
||||
map($self->{multipleChoiceTypes}->{$_->{questionType}} = [split/,/,$_->{answers}], @$refs);
|
||||
}
|
||||
|
||||
sub addType {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
my $address = shift;
|
||||
my $obj = $self->getObject($address);
|
||||
my @answers;
|
||||
for my $ans(@{$obj->{answers}}){
|
||||
push(@answers,$ans->{text});
|
||||
}
|
||||
my $ansString = join(',',@answers);
|
||||
$self->session->db->write("INSERT INTO Survey_questionTypes VALUES(?,?) ON DUPLICATE KEY UPDATE answers = ?",[$name,$ansString,$ansString]);
|
||||
$self->question($address)->{questionType} = $name;
|
||||
}
|
||||
|
||||
|
||||
sub removeType {
|
||||
my $self = shift;
|
||||
my $address = shift;
|
||||
my $obj = $self->getObject($address);
|
||||
$self->session->db->write("DELETE FROM Survey_questionTypes WHERE questionType = ?",[$obj->{questionType}]);
|
||||
}
|
||||
|
||||
=head2 specialQuestionTypes
|
||||
|
||||
Returns the arrayref to the special question types
|
||||
|
||||
=cut
|
||||
|
||||
sub specialQuestionTypes {
|
||||
my $self = shift;
|
||||
return $self->{specialQuestionTypes};
|
||||
}
|
||||
|
||||
=head2 multipleChoiceTypes
|
||||
|
||||
Returns the hashref to the multiple choice types
|
||||
|
||||
=cut
|
||||
|
||||
sub multipleChoiceTypes {
|
||||
my $self = shift;
|
||||
return $self->{multipleChoiceTypes};
|
||||
}
|
||||
|
||||
=head2 freeze
|
||||
|
||||
Serialize this Perl object into a JSON string. The serialized object is made up of the survey and sections
|
||||
|
|
@ -350,13 +364,13 @@ sub getObject {
|
|||
return if !$count;
|
||||
|
||||
if ( $count == 1 ) {
|
||||
return dclone $self->sections->[ sIndex($address) ];
|
||||
return clone $self->sections->[ sIndex($address) ];
|
||||
}
|
||||
elsif ( $count == 2 ) {
|
||||
return dclone $self->sections->[ sIndex($address) ]->{questions}->[ qIndex($address) ];
|
||||
return clone $self->sections->[ sIndex($address) ]->{questions}->[ qIndex($address) ];
|
||||
}
|
||||
else {
|
||||
return dclone $self->sections->[ sIndex($address) ]->{questions}->[ qIndex($address) ]->{answers}
|
||||
return clone $self->sections->[ sIndex($address) ]->{questions}->[ qIndex($address) ]->{answers}
|
||||
->[ aIndex($address) ];
|
||||
}
|
||||
}
|
||||
|
|
@ -403,12 +417,14 @@ sub getGotoTargets {
|
|||
|
||||
# Valid goto targets are all of the section variable names..
|
||||
my @section_vars = map {$_->{variable}} @{$self->sections};
|
||||
|
||||
|
||||
# ..and all of the question variable names..
|
||||
my @question_vars = map {$_->{variable}} @{$self->questions};
|
||||
|
||||
|
||||
# ..excluding the ones that are empty
|
||||
return grep { $_ ne q{} } (@section_vars, @question_vars);
|
||||
my @grep = grep { $_ ne q{} } (@section_vars, @question_vars);
|
||||
return \@grep;
|
||||
#return grep { $_ ne q{} } (@section_vars, @question_vars);
|
||||
}
|
||||
|
||||
=head2 getSectionEditVars ( $address )
|
||||
|
|
@ -512,7 +528,6 @@ sub getQuestionEditVars {
|
|||
|
||||
# Change questionType from a single element into an array of hashrefs which list the available
|
||||
# question types and which one is currently selected for this question..
|
||||
|
||||
for my $qType ($self->getValidQuestionTypes) {
|
||||
push @{ $var{questionType} }, {
|
||||
text => $qType,
|
||||
|
|
@ -529,7 +544,8 @@ A convenience method. Returns a list of question types.
|
|||
=cut
|
||||
|
||||
sub getValidQuestionTypes {
|
||||
return sort (@SPECIAL_QUESTION_TYPES, keys %MULTI_CHOICE_BUNDLES);
|
||||
my $self = shift;
|
||||
return sort (@{$self->{specialQuestionTypes}}, keys %{$self->{multipleChoiceTypes}});
|
||||
}
|
||||
|
||||
=head2 getAnswerEditVars ( $address )
|
||||
|
|
@ -761,14 +777,14 @@ sub copy {
|
|||
|
||||
if ( $count == 1 ) {
|
||||
# Clone the indexed section onto the end of the list of sections..
|
||||
push @{ $self->sections }, dclone $self->section($address);
|
||||
push @{ $self->sections }, clone $self->section($address);
|
||||
|
||||
# Update $address with the index of the newly created section
|
||||
$address->[0] = $self->lastSectionIndex;
|
||||
}
|
||||
elsif ( $count == 2 ) {
|
||||
# Clone the indexed question onto the end of the list of questions..
|
||||
push @{ $self->questions($address) }, dclone $self->question($address);
|
||||
push @{ $self->questions($address) }, clone $self->question($address);
|
||||
|
||||
# Update $address with the index of the newly created question
|
||||
$address->[1] = $self->lastQuestionIndex($address);
|
||||
|
|
@ -1002,7 +1018,7 @@ sub getMultiChoiceBundle {
|
|||
my $self = shift;
|
||||
my ($type) = validate_pos( @_, { type => SCALAR | UNDEF } );
|
||||
|
||||
return $MULTI_CHOICE_BUNDLES{$type};
|
||||
return $self->{multipleChoiceTypes}->{$type};
|
||||
}
|
||||
|
||||
=head2 addAnswersToQuestion ($address, $answers, $verbatims)
|
||||
|
|
@ -1047,7 +1063,7 @@ sub addAnswersToQuestion {
|
|||
$self->update(
|
||||
\@address_copy,
|
||||
{ text => $answers->[$answer_index],
|
||||
recordedAnswer => $answer_index + 1,
|
||||
recordedAnswer => $answer_index + 1, # 1-indexed
|
||||
verbatim => $verbatims->{$answer_index},
|
||||
}
|
||||
);
|
||||
|
|
@ -1176,6 +1192,123 @@ sub totalAnswers {
|
|||
}
|
||||
}
|
||||
|
||||
=head2 validateSurvey ()
|
||||
|
||||
Returns an array of messages to inform a user what is logically wrong with the Survey
|
||||
|
||||
=cut
|
||||
|
||||
sub validateSurvey{
|
||||
my $self = shift;
|
||||
#check all goto's
|
||||
#bad goto expressions
|
||||
#check that all survey is able to be seen
|
||||
|
||||
my @messages;
|
||||
|
||||
#set up valid goto targets
|
||||
my $gotoTargets = $self->getGotoTargets();
|
||||
my $goodTargets;
|
||||
my $duplicateTargets;
|
||||
for my $g (@{$gotoTargets}) {
|
||||
$goodTargets->{$g}++;
|
||||
$duplicateTargets->{$g}++ if $goodTargets->{$g} > 1;
|
||||
}
|
||||
|
||||
#step through each section validating it.
|
||||
my $sections = $self->sections();
|
||||
|
||||
for(my $s = 0; $s <= $#$sections; $s++){
|
||||
my $sNum = $s + 1;
|
||||
my $section = $self->section([$s]);
|
||||
if(! $self->validateGoto($section,$goodTargets)){
|
||||
push @messages,"Section $sNum has invalid Jump target: \"$section->{goto}\"";
|
||||
}
|
||||
if(! $self->validateGotoInfiniteLoop($section)){
|
||||
push @messages,"Section $sNum jumps to itself.";
|
||||
}
|
||||
if(my $error = $self->validateGotoExpression($section,$goodTargets)){
|
||||
push @messages,"Section $sNum has invalid Jump Expression: \"$section->{gotoExpression}\". Error: $error";
|
||||
}
|
||||
if (my $var = $section->{variable}) {
|
||||
if (my $count = $duplicateTargets->{$var}) {
|
||||
push @messages, "Section $sNum variable name $var is re-used in $count other place(s).";
|
||||
}
|
||||
}
|
||||
|
||||
#step through each question validating it.
|
||||
my $questions = $self->questions([$s]);
|
||||
for(my $q = 0; $q <= $#$questions; $q++){
|
||||
my $qNum = $q + 1;
|
||||
my $question = $self->question([$s,$q]);
|
||||
if(! $self->validateGoto($question,$goodTargets)){
|
||||
push @messages,"Section $sNum Question $qNum has invalid Jump target: \"$question->{goto}\"";
|
||||
}
|
||||
if(! $self->validateGotoInfiniteLoop($question)){
|
||||
push @messages,"Section $sNum Question $qNum jumps to itself.";
|
||||
}
|
||||
if(my $error = $self->validateGotoExpression($question,$goodTargets)){
|
||||
push @messages,"Section $sNum Question $qNum has invalid Jump Expression: \"$question->{gotoExpression}\". Error: $error";
|
||||
}
|
||||
if($#{$question->{answers}} < 0){
|
||||
push @messages,"Section $sNum Question $qNum does not have any answers.";
|
||||
}
|
||||
if(! $question->{text} =~ /\w/){
|
||||
push @messages,"Section $sNum Question $qNum does not have any text.";
|
||||
}
|
||||
if (my $var = $question->{variable}) {
|
||||
if (my $count = $duplicateTargets->{$var}) {
|
||||
push @messages, "Section $sNum Question $qNum variable name $var is re-used in $count other place(s).";
|
||||
}
|
||||
}
|
||||
|
||||
#step through each answer validating it.
|
||||
my $answers = $self->answers([$s,$q]);
|
||||
for(my $a = 0; $a <= $#$answers; $a++){
|
||||
my $aNum = $a + 1;
|
||||
my $answer = $self->answer([$s,$q,$a]);
|
||||
if(! $self->validateGoto($answer,$goodTargets)){
|
||||
push @messages,"Section $sNum Question $qNum Answer $aNum has invalid Jump target: \"$answer->{goto}\"";
|
||||
}
|
||||
if(! $self->validateGotoInfiniteLoop($answer)){
|
||||
push @messages,"Section $sNum Question $qNum Answer $aNum jumps to itself.";
|
||||
}
|
||||
if(my $error = $self->validateGotoExpression($answer,$goodTargets)){
|
||||
push @messages,"Section $sNum Question $qNum Answer $aNum has invalid Jump Expression: \"$answer->{gotoExpression}\". Error: $error";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return \@messages;
|
||||
}
|
||||
|
||||
sub validateGoto{
|
||||
my $self = shift;
|
||||
my $object = shift;
|
||||
my $goodTargets = shift;
|
||||
return 0 if($object->{goto} =~ /\w/ && ! exists($goodTargets->{$object->{goto}}));
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub validateGotoInfiniteLoop{
|
||||
my $self = shift;
|
||||
my $object = shift;
|
||||
return 0 if($object->{goto} =~ /\w/ and $object->{goto} eq $object->{variable});
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub validateGotoExpression{
|
||||
my $self = shift;
|
||||
my $object = shift;
|
||||
my $goodTargets = shift;
|
||||
return unless $object->{gotoExpression};
|
||||
|
||||
use WebGUI::Asset::Wobject::Survey::ExpressionEngine;
|
||||
my $engine = "WebGUI::Asset::Wobject::Survey::ExpressionEngine";
|
||||
return $engine->run($self->session, $object->{gotoExpression}, { validate => 1, validTargets => $goodTargets } );
|
||||
}
|
||||
|
||||
=head2 section ($address)
|
||||
|
||||
Returns a reference to one section.
|
||||
|
|
@ -1208,9 +1341,9 @@ sub session {
|
|||
|
||||
Returns a reference to all the questions from a particular section.
|
||||
|
||||
=head3 $address
|
||||
=head3 $address (optional)
|
||||
|
||||
See L<"Address Parameter">.
|
||||
See L<"Address Parameter">. If not defined, returns all questions.
|
||||
|
||||
=cut
|
||||
|
||||
|
|
@ -1218,7 +1351,13 @@ sub questions {
|
|||
my $self = shift;
|
||||
my ($address) = validate_pos(@_, { type => ARRAYREF, optional => 1});
|
||||
|
||||
return $self->sections->[ $address->[0] ]->{questions};
|
||||
if ($address) {
|
||||
return $self->sections->[ $address->[0] ]->{questions};
|
||||
} else {
|
||||
my $questions;
|
||||
push @$questions, @{$_->{questions} || []} for @{$self->sections};
|
||||
return $questions;
|
||||
}
|
||||
}
|
||||
|
||||
=head2 question ($address)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ use WebGUI::Cache;
|
|||
use WebGUI::Exception;
|
||||
use WebGUI::HTML;
|
||||
use WebGUI::International;
|
||||
use base 'WebGUI::Asset::Wobject';
|
||||
use Class::C3;
|
||||
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
|
||||
use WebGUI::Macro;
|
||||
use XML::FeedPP;
|
||||
|
||||
|
|
@ -116,7 +117,7 @@ sub definition {
|
|||
className=>'WebGUI::Asset::Wobject::SyndicatedContent',
|
||||
properties=>\%properties
|
||||
});
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
return $class->next::method($session, $definition);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -129,6 +130,7 @@ Combines all feeds into a single XML::FeedPP object.
|
|||
|
||||
sub generateFeed {
|
||||
my $self = shift;
|
||||
my $limit = shift || $self->get('maxHeadlines');
|
||||
my $feed = XML::FeedPP::Atom->new();
|
||||
my $log = $self->session->log;
|
||||
|
||||
|
|
@ -173,8 +175,8 @@ sub generateFeed {
|
|||
# sort them by date
|
||||
$feed->sort_item();
|
||||
|
||||
# limit the feed to the maxium number of headlines
|
||||
$feed->limit_item($self->get('maxHeadlines'));
|
||||
# limit the feed to the maximum number of headlines (or the feed generator limit).
|
||||
$feed->limit_item($limit);
|
||||
|
||||
# mark this asset as updated
|
||||
$self->update({}) if ($newlyCached);
|
||||
|
|
@ -184,6 +186,52 @@ sub generateFeed {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getFeed ()
|
||||
|
||||
Override the one in the parent...
|
||||
|
||||
=cut
|
||||
|
||||
sub getFeed {
|
||||
my $self = shift;
|
||||
my $feed = shift;
|
||||
foreach my $item ($self->generateFeed( $self->get('itemsPerFeed') )->get_item) {
|
||||
my $set_permalink_false = 0;
|
||||
my $new_item = $feed->add_item( $item );
|
||||
if (!$new_item->guid) {
|
||||
if ($new_item->link) {
|
||||
$new_item->guid( $new_item->link );
|
||||
} else {
|
||||
$new_item->guid( $self->session->id->generate );
|
||||
$set_permalink_false = 1;
|
||||
}
|
||||
}
|
||||
$new_item->guid( $new_item->guid, isPermaLink => 0 ) if $set_permalink_false;
|
||||
}
|
||||
$feed->title( $self->get('feedTitle') || $self->get('title') );
|
||||
$feed->description( $self->get('feedDescription') || $self->get('synopsis') );
|
||||
$feed->pubDate( $self->getContentLastModified );
|
||||
$feed->copyright( $self->get('feedCopyright') );
|
||||
$feed->link( $self->getUrl );
|
||||
# $feed->language( $lang );
|
||||
if ($self->get('feedImage')) {
|
||||
my $storage = WebGUI::Storage->get($self->session, $self->get('feedImage'));
|
||||
my @files = @{ $storage->getFiles };
|
||||
if (scalar @files) {
|
||||
$feed->image(
|
||||
$storage->getUrl( $files[0] ),
|
||||
$self->get('feedImageDescription') || $self->getTitle,
|
||||
$self->get('feedImageUrl') || $self->getUrl,
|
||||
$self->get('feedImageDescription') || $self->getTitle,
|
||||
( $storage->getSizeInPixels( $files[0] ) ) # expands to width and height
|
||||
);
|
||||
}
|
||||
}
|
||||
return $feed;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getTemplateVariables
|
||||
|
||||
Returns a hash reference of template variables.
|
||||
|
|
@ -198,11 +246,11 @@ sub getTemplateVariables {
|
|||
my ($self, $feed) = @_;
|
||||
my @items = $feed->get_item;
|
||||
my %var;
|
||||
$var{channel_title} = WebGUI::HTML::filter($feed->title, 'javascript');
|
||||
$var{channel_title} = WebGUI::HTML::filter(scalar $feed->title, 'javascript');
|
||||
$var{channel_description} = WebGUI::HTML::filter(scalar($feed->description), 'javascript');
|
||||
$var{channel_date} = WebGUI::HTML::filter(scalar($feed->get_pubDate_epoch), 'javascript');
|
||||
$var{channel_copyright} = WebGUI::HTML::filter(scalar($feed->copyright), 'javascript');
|
||||
$var{channel_link} = WebGUI::HTML::filter($feed->link, 'javascript');
|
||||
$var{channel_link} = WebGUI::HTML::filter(scalar $feed->link, 'javascript');
|
||||
my @image = $feed->image;
|
||||
$var{channel_image_url} = WebGUI::HTML::filter($image[0], 'javascript');
|
||||
$var{channel_image_title} = WebGUI::HTML::filter($image[1], 'javascript');
|
||||
|
|
@ -212,12 +260,12 @@ sub getTemplateVariables {
|
|||
$var{channel_image_height} = WebGUI::HTML::filter($image[5], 'javascript');
|
||||
foreach my $object (@items) {
|
||||
my %item;
|
||||
$item{title} = WebGUI::HTML::filter($object->title, 'javascript');
|
||||
$item{date} = WebGUI::HTML::filter($object->get_pubDate_epoch, 'javascript');
|
||||
$item{category} = WebGUI::HTML::filter($object->category, 'javascript');
|
||||
$item{author} = WebGUI::HTML::filter($object->author, 'javascript');
|
||||
$item{guid} = WebGUI::HTML::filter($object->guid, 'javascript');
|
||||
$item{link} = WebGUI::HTML::filter($object->link, 'javascript');
|
||||
$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');
|
||||
$item{author} = WebGUI::HTML::filter(scalar $object->author, 'javascript');
|
||||
$item{guid} = WebGUI::HTML::filter(scalar $object->guid, 'javascript');
|
||||
$item{link} = WebGUI::HTML::filter(scalar $object->link, 'javascript');
|
||||
$item{description} = WebGUI::HTML::filter(scalar($object->description), 'javascript');
|
||||
$item{descriptionFirst100words} = $item{description};
|
||||
$item{descriptionFirst100words} =~ s/(((\S+)\s+){100}).*/$1/s;
|
||||
|
|
@ -256,15 +304,10 @@ See WebGUI::Asset::prepareView() for details.
|
|||
|
||||
sub prepareView {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
$self->next::method;
|
||||
my $template = WebGUI::Asset::Template->new($self->session, $self->get("templateId"));
|
||||
$template->prepare($self->getMetaDataAsTemplateVariables);
|
||||
$self->{_viewTemplate} = $template;
|
||||
my $title = $self->get("title");
|
||||
my $style = $self->session->style;
|
||||
$style->setLink($self->getUrl("func=viewRss"), { rel=>'alternate', type=>'application/rss+xml', title=>$title.' (RSS)' });
|
||||
$style->setLink($self->getUrl("func=viewRdf"), { rel=>'alternate', type=>'application/rdf+xml', title=>$title.' (RDF)' });
|
||||
$style->setLink($self->getUrl("func=viewAtom"), { rel=>'alternate', type=>'application/atom+xml', title=>$title.' (Atom)' });
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -279,7 +322,7 @@ See WebGUI::Asset::purgeCache() for details.
|
|||
sub purgeCache {
|
||||
my $self = shift;
|
||||
WebGUI::Cache->new($self->session,"view_".$self->getId)->delete;
|
||||
$self->SUPER::purgeCache;
|
||||
$self->next::method;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -318,59 +361,7 @@ See WebGUI::Asset::Wobject::www_view() for details.
|
|||
sub www_view {
|
||||
my $self = shift;
|
||||
$self->session->http->setCacheControl($self->get("cacheTimeout"));
|
||||
$self->SUPER::www_view(@_);
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_viewAtom ( )
|
||||
|
||||
Emit an Atom 0.3 feed.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_viewAtom {
|
||||
my $self = shift;
|
||||
my $feed = $self->generateFeed;
|
||||
my $atom = XML::FeedPP::Atom->new;
|
||||
$atom->merge($feed);
|
||||
$self->session->http->setMimeType('application/atom+xml');
|
||||
return $atom->to_string;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_viewRdf ( )
|
||||
|
||||
Emit an RSS 1.0 / RDF feed.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_viewRdf {
|
||||
my $self = shift;
|
||||
my $feed = $self->generateFeed;
|
||||
my $rdf = XML::FeedPP::RDF->new;
|
||||
$rdf->merge($feed);
|
||||
$self->session->http->setMimeType('application/rdf+xml');
|
||||
return $rdf->to_string;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_viewRss ( )
|
||||
|
||||
Emit an RSS 2.0 feed.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_viewRss {
|
||||
my $self = shift;
|
||||
my $feed = $self->generateFeed;
|
||||
my $rss = XML::FeedPP::RSS->new;
|
||||
$rss->merge($feed);
|
||||
$self->session->http->setMimeType('application/rss+xml');
|
||||
return $rss->to_string;
|
||||
$self->next::method(@_);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -412,6 +403,20 @@ sub www_viewRSS10 {
|
|||
return $self->www_viewRdf;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_viewRSS ( )
|
||||
|
||||
Deprecated. Use www_viewRss() instead.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_viewRSS {
|
||||
my $self = shift;
|
||||
return $self->www_viewRss;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_viewRSS20 ( )
|
||||
|
|
|
|||
|
|
@ -308,6 +308,42 @@ sub duplicate {
|
|||
return $newAsset;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 duplicateThing ( thingId )
|
||||
|
||||
Duplicates a thing.
|
||||
|
||||
=head3 thingId
|
||||
|
||||
The id of the Thing that will be duplicated.
|
||||
|
||||
=cut
|
||||
|
||||
sub duplicateThing {
|
||||
|
||||
my $self = shift;
|
||||
my $oldThingId = shift;
|
||||
my $db = $self->session->db;
|
||||
|
||||
my $thingProperties = $self->getThing($oldThingId);
|
||||
$thingProperties->{thingId} = 'new';
|
||||
$thingProperties->{label} = $thingProperties->{label}.' (copy)';
|
||||
|
||||
my $newThingId = $self->addThing($thingProperties);
|
||||
my $fields = $db->buildArrayRefOfHashRefs('select * from Thingy_fields where assetId=? and thingId=?'
|
||||
,[$self->getId,$oldThingId]);
|
||||
foreach my $field (@$fields) {
|
||||
# set thingId to newly created thing's id.
|
||||
$field->{thingId} = $newThingId;
|
||||
$self->addField($field,0);
|
||||
}
|
||||
|
||||
return $newThingId;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 deleteField ( fieldId , thingId )
|
||||
|
|
@ -641,7 +677,10 @@ sub getEditFieldForm {
|
|||
}
|
||||
|
||||
my $dialogPrefix;
|
||||
if ($fieldId eq "new"){
|
||||
if ($field->{oldFieldId}){
|
||||
$dialogPrefix = "edit_".$field->{oldFieldId}."_Dialog_copy";
|
||||
}
|
||||
elsif($fieldId eq "new"){
|
||||
$dialogPrefix = "addDialog";
|
||||
}
|
||||
else{
|
||||
|
|
@ -1436,6 +1475,26 @@ sub www_deleteFieldConfirm {
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_duplicateThing ( )
|
||||
|
||||
Duplicates a Thing.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_duplicateThing {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $thingId = $session->form->process("thingId");
|
||||
return $session->privilege->insufficient() unless $self->canEdit;
|
||||
|
||||
$self->duplicateThing($thingId);
|
||||
|
||||
return $self->www_manage;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_copyThingData( )
|
||||
|
|
@ -1714,7 +1773,10 @@ sub www_editThing {
|
|||
." <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='".$i18n->get('Edit','Icon')."' type='button'>"
|
||||
."?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'>"
|
||||
."<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";
|
||||
|
||||
|
|
@ -2055,12 +2117,19 @@ Returns the html for a pop-up dialog to add or edit a field.
|
|||
|
||||
sub www_editField {
|
||||
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my (%properties,$thingId,$fieldId,$dialogBody);
|
||||
return $self->session->privilege->insufficient() unless $self->canEdit;
|
||||
$fieldId = $self->session->form->process("fieldId");
|
||||
$thingId = $self->session->form->process("thingId");
|
||||
%properties = $self->session->db->quickHash("select * from Thingy_fields where thingId=".$self->session->db->quote($thingId)." and fieldId = ".$self->session->db->quote($fieldId)." and assetId = ".$self->session->db->quote($self->get("assetId")));
|
||||
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->get("assetId")]);
|
||||
if($session->form->process("copy")){
|
||||
$properties{oldFieldId} = $properties{fieldId};
|
||||
$properties{fieldId} = 'new';
|
||||
$properties{label} = $properties{label}.' (copy)';
|
||||
}
|
||||
$dialogBody = $self->getEditFieldForm(\%properties);
|
||||
$self->session->output->print($dialogBody->print);
|
||||
return "chunked";
|
||||
|
|
@ -2868,6 +2937,8 @@ sub www_manage {
|
|||
"",$i18n->get('delete thing warning')),
|
||||
'thing_editUrl' => $session->url->append($url, 'func=editThing;thingId='.$thing->{thingId}),
|
||||
'thing_editIcon' => $session->icon->edit('func=editThing;thingId='.$thing->{thingId}),
|
||||
'thing_copyUrl' => $session->url->append($url, 'func=duplicateThing;thingId='.$thing->{thingId}),
|
||||
'thing_copyIcon' => $session->icon->copy('func=duplicateThing;thingId='.$thing->{thingId}),
|
||||
'thing_addUrl' => $session->url->append($url,
|
||||
'func=editThingData;thingId='.$thing->{thingId}.';thingDataId=new'),
|
||||
'thing_searchUrl' => $session->url->append($url, 'func=search;thingId='.$thing->{thingId}),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ package WebGUI::Asset::Wobject::WikiMaster;
|
|||
# http://www.plainblack.com info@plainblack.com
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
use base 'WebGUI::Asset::Wobject';
|
||||
use Class::C3;
|
||||
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
|
||||
use strict;
|
||||
use Tie::IxHash;
|
||||
use WebGUI::International;
|
||||
|
|
@ -70,6 +71,7 @@ sub appendRecentChanges {
|
|||
username=>$user->username,
|
||||
date=>$self->session->datetime->epochToHuman($asset->get("revisionDate")),
|
||||
isAvailable=>$isAvailable,
|
||||
assetId=>$id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -139,7 +141,7 @@ sub autolinkHtml {
|
|||
#-------------------------------------------------------------------
|
||||
sub canAdminister {
|
||||
my $self = shift;
|
||||
return $self->session->user->isInGroup($self->get('groupToAdminister')) || $self->SUPER::canEdit;
|
||||
return $self->session->user->isInGroup($self->get('groupToAdminister')) || $self->WebGUI::Asset::Wobject::canEdit;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -164,7 +166,7 @@ sub canEdit {
|
|||
) &&
|
||||
$self->canEditPages
|
||||
) || # account for new posts
|
||||
$self->SUPER::canEdit()
|
||||
$self->next::method()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -337,13 +339,44 @@ sub definition {
|
|||
properties => \%properties,
|
||||
};
|
||||
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
return $class->next::method($session, $definition);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getRssFeedItems ()
|
||||
|
||||
Returns an array reference of hash references. Each hash reference has a title,
|
||||
description, link, and date field. The date field can be either an epoch date, an RFC 1123
|
||||
date, or a ISO date in the format of YYYY-MM-DD HH:MM::SS. Optionally specify an
|
||||
author, and a guid field.
|
||||
|
||||
=cut
|
||||
|
||||
sub getRssFeedItems {
|
||||
my $self = shift;
|
||||
my $vars = {};
|
||||
$self->appendRecentChanges( $vars, $self->get('itemsPerFeed') );
|
||||
my $var = [];
|
||||
foreach my $item ( @{ $vars->{recentChanges} } ) {
|
||||
my $asset = WebGUI::Asset->newByDynamicClass( $self->session, $item->{assetId} );
|
||||
push @{ $var }, {
|
||||
'link' => $asset->getUrl,
|
||||
'guid' => $item->{ 'assetId' } . $asset->get( 'revisionDate' ),
|
||||
'title' => $asset->getTitle,
|
||||
'description' => $item->{ 'actionTaken' },
|
||||
'date' => $item->{ 'date' },
|
||||
'author' => $item->{ 'username' },
|
||||
};
|
||||
}
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub prepareView {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView;
|
||||
$self->next::method;
|
||||
$self->{_frontPageTemplate} =
|
||||
WebGUI::Asset::Template->new($self->session, $self->get('frontPageTemplateId'));
|
||||
$self->{_frontPageTemplate}->prepare;
|
||||
|
|
@ -355,7 +388,7 @@ sub processPropertiesFromFormPost {
|
|||
my $groupsChanged =
|
||||
(($self->session->form->process('groupIdView') ne $self->get('groupIdView'))
|
||||
or ($self->session->form->process('groupIdEdit') ne $self->get('groupIdEdit')));
|
||||
my $ret = $self->SUPER::processPropertiesFromFormPost(@_);
|
||||
my $ret = $self->next::method(@_);
|
||||
if ($groupsChanged) {
|
||||
foreach my $child (@{$self->getLineage(['children'], {returnObjects => 1})}) {
|
||||
$child->update({ groupIdView => $self->get('groupIdView'),
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ use WebGUI::International;
|
|||
use WebGUI::Utility;
|
||||
use base 'WebGUI::Asset::Wobject';
|
||||
|
||||
# To get an installer for your wobject, add the Installable AssetAspect
|
||||
# See WebGUI::AssetAspect::Installable and sbin/installClass.pl for more
|
||||
# details
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 definition ( )
|
||||
|
|
@ -29,46 +33,43 @@ getEditForm method is unnecessary/redundant/useless.
|
|||
=cut
|
||||
|
||||
sub definition {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $definition = shift;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_NewWobject');
|
||||
my %properties;
|
||||
tie %properties, 'Tie::IxHash';
|
||||
%properties = (
|
||||
templateId =>{
|
||||
|
||||
#See the list of field/control types in /lib/WebGUI/Form/
|
||||
fieldType=>"template",
|
||||
|
||||
defaultValue=>'NewWobjectTmpl00000001',
|
||||
tab=>"display",
|
||||
|
||||
#www_editSave will ignore anyone's attempts to update this field if this is set to 1
|
||||
noFormPost=>0,
|
||||
|
||||
#This is an option specific to the template fieldType.
|
||||
namespace=>"NewWobject",
|
||||
|
||||
#This is what will appear when the user hovers the mouse over the label
|
||||
# of your form field.
|
||||
hoverHelp=>$i18n->get('templateId label description'),
|
||||
|
||||
# This is the text that will appear to the left of your form field.
|
||||
label=>$i18n->get('templateId label'),
|
||||
}
|
||||
);
|
||||
push(@{$definition}, {
|
||||
assetName=>$i18n->get('assetName'),
|
||||
icon=>'newWobject.gif',
|
||||
autoGenerateForms=>1,
|
||||
tableName=>'NewWobject',
|
||||
className=>'WebGUI::Asset::Wobject::NewWobject',
|
||||
properties=>\%properties
|
||||
});
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
}
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $definition = shift;
|
||||
my $i18n = WebGUI::International->new( $session, 'Asset_NewWobject' );
|
||||
tie my %properties, 'Tie::IxHash', (
|
||||
templateId => {
|
||||
|
||||
#See the list of field/control types in /lib/WebGUI/Form/
|
||||
fieldType => "template",
|
||||
|
||||
defaultValue => 'NewWobjectTmpl00000001',
|
||||
tab => "display",
|
||||
|
||||
#www_editSave will ignore anyone's attempts to update this field if this is set to 1
|
||||
noFormPost => 0,
|
||||
|
||||
#This is an option specific to the template fieldType.
|
||||
namespace => "NewWobject",
|
||||
|
||||
#This is what will appear when the user hovers the mouse over the label
|
||||
# of your form field.
|
||||
hoverHelp => $i18n->get('templateId label description'),
|
||||
|
||||
# This is the text that will appear to the left of your form field.
|
||||
label => $i18n->get('templateId label'),
|
||||
}
|
||||
);
|
||||
push @{$definition}, {
|
||||
assetName => $i18n->get('assetName'),
|
||||
icon => 'newWobject.gif',
|
||||
autoGenerateForms => 1,
|
||||
tableName => 'NewWobject',
|
||||
className => 'WebGUI::Asset::Wobject::NewWobject',
|
||||
properties => \%properties
|
||||
};
|
||||
return $class->SUPER::definition( $session, $definition );
|
||||
} ## end sub definition
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
|
|
@ -81,9 +82,9 @@ wobject instances, you will need to duplicate them here.
|
|||
=cut
|
||||
|
||||
sub duplicate {
|
||||
my $self = shift;
|
||||
my $newAsset = $self->SUPER::duplicate(@_);
|
||||
return $newAsset;
|
||||
my $self = shift;
|
||||
my $newAsset = $self->SUPER::duplicate(@_);
|
||||
return $newAsset;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -96,16 +97,16 @@ This method is optional if you set autoGenerateForms=1 in the definition.
|
|||
=cut
|
||||
|
||||
sub getEditForm {
|
||||
my $self = shift;
|
||||
my $tabform = $self->SUPER::getEditForm();
|
||||
my $self = shift;
|
||||
my $tabform = $self->SUPER::getEditForm();
|
||||
|
||||
$tabform->getTab("display")->template(
|
||||
-value=>$self->getValue("templateId"),
|
||||
-label=>WebGUI::International::get("template_label","Asset_NewWobject"),
|
||||
-namespace=>"NewWobject"
|
||||
);
|
||||
|
||||
return $tabform;
|
||||
$tabform->getTab("display")->template(
|
||||
value => $self->getValue("templateId"),
|
||||
label => WebGUI::International::get( "template_label", "Asset_NewWobject" ),
|
||||
namespace => "NewWobject"
|
||||
);
|
||||
|
||||
return $tabform;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -117,14 +118,13 @@ See WebGUI::Asset::prepareView() for details.
|
|||
=cut
|
||||
|
||||
sub prepareView {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
my $template = WebGUI::Asset::Template->new($self->session, $self->get("templateId"));
|
||||
$template->prepare;
|
||||
$self->{_viewTemplate} = $template;
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
my $template = WebGUI::Asset::Template->new( $self->session, $self->get("templateId") );
|
||||
$template->prepare($self->getMetaDataAsTemplateVariables);
|
||||
$self->{_viewTemplate} = $template;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 purge ( )
|
||||
|
|
@ -137,10 +137,11 @@ wobject instances, you will need to purge them here.
|
|||
=cut
|
||||
|
||||
sub purge {
|
||||
my $self = shift;
|
||||
#purge your wobject-specific data here. This does not include fields
|
||||
# you create for your NewWobject asset/wobject table.
|
||||
return $self->SUPER::purge;
|
||||
my $self = shift;
|
||||
|
||||
#purge your wobject-specific data here. This does not include fields
|
||||
# you create for your NewWobject asset/wobject table.
|
||||
return $self->SUPER::purge;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -153,16 +154,16 @@ to be displayed within the page style.
|
|||
=cut
|
||||
|
||||
sub view {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
|
||||
#This automatically creates template variables for all of your wobject's properties.
|
||||
my $var = $self->get;
|
||||
|
||||
#This is an example of debugging code to help you diagnose problems.
|
||||
#WebGUI::ErrorHandler::warn($self->get("templateId"));
|
||||
|
||||
return $self->processTemplate($var, undef, $self->{_viewTemplate});
|
||||
#This automatically creates template variables for all of your wobject's properties.
|
||||
my $var = $self->get;
|
||||
|
||||
#This is an example of debugging code to help you diagnose problems.
|
||||
#$session->log->warn($self->get("templateId"));
|
||||
|
||||
return $self->processTemplate( $var, undef, $self->{_viewTemplate} );
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -183,60 +184,6 @@ adminConsole views.
|
|||
# return $self->getAdminConsole->render($self->getEditForm->print, $i18n->get("edit title"));
|
||||
#}
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Everything below here is to make it easier to install your custom
|
||||
# wobject, but has nothing to do with wobjects in general
|
||||
#-------------------------------------------------------------------
|
||||
# cd /data/WebGUI/lib
|
||||
# perl -MWebGUI::Asset::Wobject::NewWobject -e install www.example.com.conf [ /path/to/WebGUI ]
|
||||
# - or -
|
||||
# perl -MWebGUI::Asset::Wobject::NewWobject -e uninstall www.example.com.conf [ /path/to/WebGUI ]
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
|
||||
use base 'Exporter';
|
||||
our @EXPORT = qw(install uninstall);
|
||||
use WebGUI::Session;
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub install {
|
||||
my $config = $ARGV[0];
|
||||
my $home = $ARGV[1] || "/data/WebGUI";
|
||||
die "usage: perl -MWebGUI::Asset::Wobject::NewWobject -e install www.example.com.conf\n" unless ($home && $config);
|
||||
print "Installing asset.\n";
|
||||
my $session = WebGUI::Session->open($home, $config);
|
||||
$session->config->addToArray("assets","WebGUI::Asset::Wobject::NewWobject");
|
||||
$session->db->write("create table NewWobject (
|
||||
assetId varchar(22) binary not null,
|
||||
revisionDate bigint not null,
|
||||
primary key (assetId, revisionDate)
|
||||
)");
|
||||
$session->var->end;
|
||||
$session->close;
|
||||
print "Done. Please restart Apache.\n";
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub uninstall {
|
||||
my $config = $ARGV[0];
|
||||
my $home = $ARGV[1] || "/data/WebGUI";
|
||||
die "usage: perl -MWebGUI::Asset::Wobject::NewWobject -e uninstall www.example.com.conf\n" unless ($home && $config);
|
||||
print "Uninstalling asset.\n";
|
||||
my $session = WebGUI::Session->open($home, $config);
|
||||
$session->config->deleteFromArray("assets","WebGUI::Asset::Wobject::NewWobject");
|
||||
my $rs = $session->db->read("select assetId from asset where className='WebGUI::Asset::Wobject::NewWobject'");
|
||||
while (my ($id) = $rs->array) {
|
||||
my $asset = WebGUI::Asset->new($session, $id, "WebGUI::Asset::Wobject::NewWobject");
|
||||
$asset->purge if defined $asset;
|
||||
}
|
||||
$session->db->write("drop table NewWobject");
|
||||
$session->var->end;
|
||||
$session->close;
|
||||
print "Done. Please restart Apache.\n";
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
#vim:ft=perl
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ use Tie::IxHash;
|
|||
use base 'WebGUI::Asset';
|
||||
use WebGUI::Utility;
|
||||
|
||||
|
||||
# To get an installer for your wobject, add the Installable AssetAspect
|
||||
# See WebGUI::AssetAspect::Installable and sbin/installClass.pl for more
|
||||
# details
|
||||
|
||||
=head1 NAME
|
||||
|
||||
|
|
@ -40,21 +42,19 @@ These methods are available from this class:
|
|||
|
||||
=cut
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 addRevision
|
||||
|
||||
This method exists for demonstration purposes only. The superclass
|
||||
handles revisions to NewAsset Assets.
|
||||
This method exists for demonstration purposes only. The superclass
|
||||
handles revisions to NewAsset Assets.
|
||||
|
||||
=cut
|
||||
|
||||
sub addRevision {
|
||||
my $self = shift;
|
||||
my $newSelf = $self->SUPER::addRevision(@_);
|
||||
return $newSelf;
|
||||
my $self = shift;
|
||||
my $newSelf = $self->SUPER::addRevision(@_);
|
||||
return $newSelf;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -73,66 +73,68 @@ A hash reference passed in from a subclass definition.
|
|||
=cut
|
||||
|
||||
sub definition {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $definition = shift;
|
||||
my %properties;
|
||||
tie %properties, 'Tie::IxHash';
|
||||
my $i18n = WebGUI::International->new($session, "Asset_NewAsset");
|
||||
%properties = (
|
||||
templateId => {
|
||||
# Determines which tab this property appears in
|
||||
tab=>"display",
|
||||
#See the list of field/control types in /lib/WebGUI/Form/
|
||||
fieldType=>"template",
|
||||
defaultValue=>'NewAssetTmpl0000000001',
|
||||
#www_editSave will ignore anyone's attempts to update this field if this is set to 1
|
||||
noFormPost=>0,
|
||||
#This is an option specific to the template fieldType.
|
||||
namespace=>"NewAsset",
|
||||
#This is what will appear when the user hovers the mouse over the label
|
||||
# of your form field.
|
||||
hoverHelp=>$i18n->get('templateId label description'),
|
||||
# This is the text that will appear to the left of your form field.
|
||||
label=>$i18n->get('templateId label')
|
||||
},
|
||||
foo => {
|
||||
tab=>"properties",
|
||||
fieldType=>"text",
|
||||
defaultValue=>undef,
|
||||
label=>$i18n->get("foo label"),
|
||||
hoverHelp=>$i18n->get("foo label help")
|
||||
}
|
||||
);
|
||||
push(@{$definition}, {
|
||||
assetName=>$i18n->get('assetName'),
|
||||
icon=>'NewAsset.gif',
|
||||
autoGenerateForms=>1,
|
||||
tableName=>'NewAsset',
|
||||
className=>'WebGUI::Asset::NewAsset',
|
||||
properties=>\%properties
|
||||
});
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
}
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $definition = shift;
|
||||
my $i18n = WebGUI::International->new( $session, "Asset_NewAsset" );
|
||||
tie my %properties, 'Tie::IxHash', (
|
||||
templateId => {
|
||||
|
||||
# Determines which tab this property appears in
|
||||
tab => "display",
|
||||
|
||||
#See the list of field/control types in /lib/WebGUI/Form/
|
||||
fieldType => "template",
|
||||
defaultValue => 'NewAssetTmpl0000000001',
|
||||
|
||||
#www_editSave will ignore anyone's attempts to update this field if this is set to 1
|
||||
noFormPost => 0,
|
||||
|
||||
#This is an option specific to the template fieldType.
|
||||
namespace => "NewAsset",
|
||||
|
||||
#This is what will appear when the user hovers the mouse over the label
|
||||
# of your form field.
|
||||
hoverHelp => $i18n->get('templateId label description'),
|
||||
|
||||
# This is the text that will appear to the left of your form field.
|
||||
label => $i18n->get('templateId label')
|
||||
},
|
||||
foo => {
|
||||
tab => "properties",
|
||||
fieldType => "text",
|
||||
defaultValue => undef,
|
||||
label => $i18n->get("foo label"),
|
||||
hoverHelp => $i18n->get("foo label help")
|
||||
},
|
||||
);
|
||||
push @{$definition}, {
|
||||
assetName => $i18n->get('assetName'),
|
||||
icon => 'NewAsset.gif',
|
||||
autoGenerateForms => 1,
|
||||
tableName => 'NewAsset',
|
||||
className => 'WebGUI::Asset::NewAsset',
|
||||
properties => \%properties,
|
||||
};
|
||||
return $class->SUPER::definition( $session, $definition );
|
||||
} ## end sub definition
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 duplicate
|
||||
|
||||
This method exists for demonstration purposes only. The superclass
|
||||
handles duplicating NewAsset Assets. This method will be called
|
||||
whenever a copy action is executed
|
||||
This method exists for demonstration purposes only. The superclass
|
||||
handles duplicating NewAsset Assets. This method will be called
|
||||
whenever a copy action is executed
|
||||
|
||||
=cut
|
||||
|
||||
sub duplicate {
|
||||
my $self = shift;
|
||||
my $newAsset = $self->SUPER::duplicate(@_);
|
||||
return $newAsset;
|
||||
my $self = shift;
|
||||
my $newAsset = $self->SUPER::duplicate(@_);
|
||||
return $newAsset;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 indexContent ( )
|
||||
|
|
@ -142,12 +144,11 @@ Making private. See WebGUI::Asset::indexContent() for additonal details.
|
|||
=cut
|
||||
|
||||
sub indexContent {
|
||||
my $self = shift;
|
||||
my $indexer = $self->SUPER::indexContent;
|
||||
$indexer->setIsPublic(0);
|
||||
my $self = shift;
|
||||
my $indexer = $self->SUPER::indexContent;
|
||||
$indexer->setIsPublic(0);
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 prepareView ( )
|
||||
|
|
@ -157,14 +158,13 @@ See WebGUI::Asset::prepareView() for details.
|
|||
=cut
|
||||
|
||||
sub prepareView {
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
my $template = WebGUI::Asset::Template->new($self->session, $self->get("templateId"));
|
||||
$template->prepare;
|
||||
$self->{_viewTemplate} = $template;
|
||||
my $self = shift;
|
||||
$self->SUPER::prepareView();
|
||||
my $template = WebGUI::Asset::Template->new( $self->session, $self->get("templateId") );
|
||||
$template->prepare($self->getMetaDataAsTemplateVariables);
|
||||
$self->{_viewTemplate} = $template;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 processPropertiesFromFormPost ( )
|
||||
|
|
@ -176,11 +176,10 @@ when /yourAssetUrl?func=editSave is requested/posted.
|
|||
=cut
|
||||
|
||||
sub processPropertiesFromFormPost {
|
||||
my $self = shift;
|
||||
$self->SUPER::processPropertiesFromFormPost;
|
||||
my $self = shift;
|
||||
$self->SUPER::processPropertiesFromFormPost;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 purge ( )
|
||||
|
|
@ -194,8 +193,8 @@ asset instances, you will need to purge them here.
|
|||
=cut
|
||||
|
||||
sub purge {
|
||||
my $self = shift;
|
||||
return $self->SUPER::purge;
|
||||
my $self = shift;
|
||||
return $self->SUPER::purge;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -207,8 +206,8 @@ This method is called when data is purged by the system.
|
|||
=cut
|
||||
|
||||
sub purgeRevision {
|
||||
my $self = shift;
|
||||
return $self->SUPER::purgeRevision;
|
||||
my $self = shift;
|
||||
return $self->SUPER::purgeRevision;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -220,13 +219,12 @@ method called by the container www_view method.
|
|||
=cut
|
||||
|
||||
sub view {
|
||||
my $self = shift;
|
||||
my $var = $self->get; # $var is a hash reference.
|
||||
$var->{controls} = $self->getToolbar;
|
||||
return $self->processTemplate($var,undef, $self->{_viewTemplate});
|
||||
my $self = shift;
|
||||
my $var = $self->get; # $var is a hash reference.
|
||||
$var->{controls} = $self->getToolbar;
|
||||
return $self->processTemplate( $var, undef, $self->{_viewTemplate} );
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_edit ( )
|
||||
|
|
@ -238,69 +236,14 @@ the module.
|
|||
=cut
|
||||
|
||||
sub www_edit {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
return $session->privilege->insufficient() unless $self->canEdit;
|
||||
return $session->privilege->locked() unless $self->canEditIfLocked;
|
||||
my $i18n = WebGUI::International->new($session, 'Asset_NewAsset');
|
||||
return $self->getAdminConsole->render($self->getEditForm->print, $i18n->get('edit asset'));
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
return $session->privilege->insufficient() unless $self->canEdit;
|
||||
return $session->privilege->locked() unless $self->canEditIfLocked;
|
||||
my $i18n = WebGUI::International->new( $session, 'Asset_NewAsset' );
|
||||
return $self->getAdminConsole->render( $self->getEditForm->print, $i18n->get('edit asset') );
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Everything below here is to make it easier to install your custom
|
||||
# asset, but has nothing to do with assets in general
|
||||
#-------------------------------------------------------------------
|
||||
# cd /data/WebGUI/lib
|
||||
# perl -MWebGUI::Asset::NewAsset -e install www.example.com.conf [ /path/to/WebGUI ]
|
||||
# - or -
|
||||
# perl -MWebGUI::Asset::NewAsset -e uninstall www.example.com.conf [ /path/to/WebGUI ]
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
|
||||
use base 'Exporter';
|
||||
our @EXPORT = qw(install uninstall);
|
||||
use WebGUI::Session;
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
sub install {
|
||||
my $config = $ARGV[0];
|
||||
my $home = $ARGV[1] || "/data/WebGUI";
|
||||
die "usage: perl -MWebGUI::Asset::NewAsset -e install www.example.com.conf\n" unless ($home && $config);
|
||||
print "Installing asset.\n";
|
||||
my $session = WebGUI::Session->open($home, $config);
|
||||
$session->config->addToArray("assets","WebGUI::Asset::NewAsset");
|
||||
$session->db->write("create table NewAsset (
|
||||
assetId varchar(22) binary not null,
|
||||
revisionDate bigint not null,
|
||||
primary key (assetId, revisionDate)
|
||||
)");
|
||||
$session->var->end;
|
||||
$session->close;
|
||||
print "Done. Please restart Apache.\n";
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
sub uninstall {
|
||||
my $config = $ARGV[0];
|
||||
my $home = $ARGV[1] || "/data/WebGUI";
|
||||
die "usage: perl -MWebGUI::Asset::NewAsset -e uninstall www.example.com.conf\n" unless ($home && $config);
|
||||
print "Uninstalling asset.\n";
|
||||
my $session = WebGUI::Session->open($home, $config);
|
||||
$session->config->deleteFromArray("assets","WebGUI::Asset::NewAsset");
|
||||
my $rs = $session->db->read("select assetId from asset where className='WebGUI::Asset::NewAsset'");
|
||||
while (my ($id) = $rs->array) {
|
||||
my $asset = WebGUI::Asset->new($session, $id, "WebGUI::Asset::NewAsset");
|
||||
$asset->purge if defined $asset;
|
||||
}
|
||||
$session->db->write("drop table NewAsset");
|
||||
$session->var->end;
|
||||
$session->close;
|
||||
print "Done. Please restart Apache.\n";
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
#vim:ft=perl
|
||||
|
|
|
|||
500
lib/WebGUI/AssetAspect/RssFeed.pm
Normal file
500
lib/WebGUI/AssetAspect/RssFeed.pm
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
package WebGUI::AssetAspect::RssFeed;
|
||||
|
||||
=head1 LEGAL
|
||||
|
||||
-------------------------------------------------------------------
|
||||
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
|
||||
-------------------------------------------------------------------
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use Class::C3;
|
||||
use WebGUI::Exception;
|
||||
use WebGUI::Storage;
|
||||
use XML::FeedPP;
|
||||
use Path::Class::File;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Package WebGUI::AssetAspect::RssFeed
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is an aspect which exposes an asset's items as an RSS or Atom feed.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Class::C3;
|
||||
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset);
|
||||
|
||||
And then wherever you would call $self->SUPER::someMethodName call $self->next::method instead.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
These methods are available from this class:
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 definition
|
||||
|
||||
Extends the definition to add the RSS fields.
|
||||
|
||||
=cut
|
||||
|
||||
sub definition {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $definition = shift;
|
||||
my $i18n = WebGUI::International->new($session,'AssetAspect_RssFeed');
|
||||
my %properties;
|
||||
tie %properties, 'Tie::IxHash';
|
||||
%properties = (
|
||||
itemsPerFeed => {
|
||||
noFormPost => 0,
|
||||
fieldType => "integer",
|
||||
defaultValue => 25,
|
||||
tab => "rss",
|
||||
label => $i18n->get('itemsPerFeed'),
|
||||
hoverHelp => $i18n->get('itemsPerFeed hoverHelp')
|
||||
},
|
||||
feedCopyright => {
|
||||
noFormPost => 0,
|
||||
fieldType => "text",
|
||||
defaultValue => "",
|
||||
tab => "rss",
|
||||
label => $i18n->get('feedCopyright'),
|
||||
hoverHelp => $i18n->get('feedCopyright hoverHelp')
|
||||
},
|
||||
feedTitle => {
|
||||
noFormPost => 0,
|
||||
fieldType => "text",
|
||||
defaultValue => "",
|
||||
tab => "rss",
|
||||
label => $i18n->get('feedTitle'),
|
||||
hoverHelp => $i18n->get('feedTitle hoverHelp')
|
||||
},
|
||||
feedDescription => {
|
||||
noFormPost => 0,
|
||||
fieldType => "textarea",
|
||||
defaultValue => "",
|
||||
tab => "rss",
|
||||
label => $i18n->get('feedDescription'),
|
||||
hoverHelp => $i18n->get('feedDescription hoverHelp')
|
||||
},
|
||||
feedImage => {
|
||||
noFormPost => 0,
|
||||
fieldType => "image",
|
||||
tab => "rss",
|
||||
label => $i18n->get('feedImage'),
|
||||
hoverHelp => $i18n->get('feedImage hoverHelp')
|
||||
},
|
||||
feedImageLink => {
|
||||
noFormPost => 0,
|
||||
fieldType => "url",
|
||||
defaultValue => "",
|
||||
tab => "rss",
|
||||
label => $i18n->get('feedImageLink'),
|
||||
hoverHelp => $i18n->get('feedImageLink hoverHelp')
|
||||
},
|
||||
feedImageDescription => {
|
||||
noFormPost => 0,
|
||||
fieldType => "text",
|
||||
defaultValue => "",
|
||||
tab => "rss",
|
||||
label => $i18n->get('feedImageDescription'),
|
||||
hoverHelp => $i18n->get('feedImageDescription hoverHelp')
|
||||
},
|
||||
feedHeaderLinks => {
|
||||
fieldType => "checkList",
|
||||
allowEmpty => 1,
|
||||
defaultValue => "rss\natom",
|
||||
tab => "rss",
|
||||
options => do {
|
||||
my %headerLinksOptions;
|
||||
tie %headerLinksOptions, 'Tie::IxHash';
|
||||
%headerLinksOptions = (
|
||||
rss => $i18n->get('rssLinkOption'),
|
||||
atom => $i18n->get('atomLinkOption'),
|
||||
rdf => $i18n->get('rdfLinkOption'),
|
||||
);
|
||||
\%headerLinksOptions;
|
||||
},
|
||||
label => $i18n->get('feedHeaderLinks'),
|
||||
hoverHelp => $i18n->get('feedHeaderLinks hoverHelp')
|
||||
},
|
||||
);
|
||||
push(@{$definition}, {
|
||||
autoGenerateForms => 1,
|
||||
tableName => 'assetAspectRssFeed',
|
||||
className => 'WebGUI::AssetAspect::RssFeed',
|
||||
properties => \%properties
|
||||
});
|
||||
return $class->next::method($session, $definition);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 exportAssetCollateral ()
|
||||
|
||||
Extended from WebGUI::Asset and exports the www_viewRss() and
|
||||
www_viewAtom() methods with filenames generated by
|
||||
getStaticAtomFeedUrl() and getStaticRssFeedUrl().
|
||||
|
||||
This method will be called with the following parameters:
|
||||
|
||||
=head3 basePath
|
||||
|
||||
A L<Path::Class> object representing the base filesystem path for this
|
||||
particular asset.
|
||||
|
||||
=head3 params
|
||||
|
||||
A hashref with the quiet, userId, depth, and indexFileName parameters from
|
||||
L<WebGUI::Asset/exportAsHtml>.
|
||||
|
||||
=cut
|
||||
|
||||
sub exportAssetCollateral {
|
||||
# Lots of copy/paste here from AssetExportHtml.pm, since none of the methods there were
|
||||
# directly useful without ginormous refactoring.
|
||||
my $self = shift;
|
||||
my $basepath = shift;
|
||||
my $args = shift;
|
||||
my $reportSession = shift;
|
||||
|
||||
my $reporti18n = WebGUI::International->new($self->session, 'Asset');
|
||||
|
||||
my $basename = $basepath->basename;
|
||||
my $filedir;
|
||||
my $filenameBase;
|
||||
|
||||
# We want our .rss and .atom files to "appear" at the same level as the asset.
|
||||
if ($basename eq 'index.html') {
|
||||
# Get the 2nd ancestor, since the asset url had no dot in it (and it therefore
|
||||
# had its own directory created for it).
|
||||
$filedir = $basepath->parent->parent->absolute->stringify;
|
||||
# Get the parent dir's *path* (essentially the name of the dir) relative to
|
||||
# its own parent dir.
|
||||
$filenameBase = $basepath->parent->relative( $basepath->parent->parent )->stringify;
|
||||
} else {
|
||||
# Get the 1st ancestor, since the asset is a file recognized by apache, so
|
||||
# we want our files in the same dir.
|
||||
$filedir = $basepath->parent->absolute->stringify;
|
||||
# just use the basename.
|
||||
$filenameBase = $basename;
|
||||
}
|
||||
|
||||
if ( $reportSession && !$args->{quiet} ) {
|
||||
$reportSession->output->print('<br />');
|
||||
}
|
||||
|
||||
foreach my $ext (qw( rss atom )) {
|
||||
my $dest = Path::Class::File->new($filedir, $filenameBase . '.' . $ext);
|
||||
|
||||
# tell the user which asset we're exporting.
|
||||
if ( $reportSession && !$args->{quiet} ) {
|
||||
my $message = sprintf $reporti18n->get('exporting page'), $dest->absolute->stringify;
|
||||
$reportSession->output->print(
|
||||
' ' . $message . '<br />');
|
||||
}
|
||||
my $exportSession = WebGUI::Session->open(
|
||||
$self->session->config->getWebguiRoot,
|
||||
$self->session->config->getFilename,
|
||||
undef,
|
||||
undef,
|
||||
$self->session->getId,
|
||||
);
|
||||
|
||||
# open another session as the user doing the exporting...
|
||||
my $selfdupe = WebGUI::Asset->newByDynamicClass( $exportSession, $self->getId );
|
||||
|
||||
# next, get the contents, open the file, and write the contents to the file.
|
||||
my $fh = eval { $dest->open('>:utf8') };
|
||||
if($@) {
|
||||
WebGUI::Error->throw(error => "can't open " . $dest->absolute->stringify . " for writing: $!");
|
||||
$exportSession->close;
|
||||
}
|
||||
$exportSession->asset($selfdupe);
|
||||
$exportSession->output->setHandle($fh);
|
||||
my $contents;
|
||||
if ($ext eq 'rss') {
|
||||
$contents = $selfdupe->www_viewRss;
|
||||
}
|
||||
else {
|
||||
$contents = $selfdupe->www_viewAtom;
|
||||
} # add more for more extensions.
|
||||
|
||||
# chunked content is already printed, no need to print it again
|
||||
unless($contents eq 'chunked') {
|
||||
$exportSession->output->print($contents);
|
||||
}
|
||||
|
||||
$exportSession->close;
|
||||
|
||||
# tell the user we did this asset collateral correctly
|
||||
if ( $reportSession && !$args->{quiet} ) {
|
||||
$reportSession->output->print($reporti18n->get('done'));
|
||||
}
|
||||
}
|
||||
return $self->next::method($basepath, $args, $reportSession);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getRssFeedItems ()
|
||||
|
||||
This method should throw an exception if it's not overridden. Its intention is
|
||||
to be overridden by whatever class is using it and should return an array
|
||||
reference of hash references. Each hash reference should contain at minimum a title,
|
||||
description, link, and date field. The date field can be either an epoch date, an RFC 1123
|
||||
date, or a ISO date in the format of YYYY-MM-DD HH:MM::SS. Optionally specify an
|
||||
author, and a guid field.
|
||||
|
||||
=cut
|
||||
|
||||
sub getRssFeedItems {
|
||||
WebGUI::Error::OverrideMe->throw();
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getAtomFeedUrl ()
|
||||
|
||||
Returns $self->getUrl('func=viewAtom').
|
||||
|
||||
=cut
|
||||
|
||||
sub getAtomFeedUrl {
|
||||
shift->getUrl("func=viewAtom");
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getRdfFeedUrl ()
|
||||
|
||||
Returns $self->getUrl('func=viewRdf').
|
||||
|
||||
=cut
|
||||
|
||||
sub getRdfFeedUrl {
|
||||
shift->getUrl("func=viewRdf");
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getRssFeedUrl ()
|
||||
|
||||
Returns $self->getUrl('func=viewRss').
|
||||
|
||||
=cut
|
||||
|
||||
sub getRssFeedUrl {
|
||||
shift->getUrl("func=viewRss");
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getStaticAtomFeedUrl ()
|
||||
|
||||
Returns the current asset's URL with .atom concatenated onto it.
|
||||
|
||||
=cut
|
||||
|
||||
sub getStaticAtomFeedUrl {
|
||||
my $self = shift;
|
||||
my $url = $self->get("url") . '.atom';
|
||||
$url = $self->session->url->gateway($url);
|
||||
if ($self->get("encryptPage")) {
|
||||
$url = $self->session->url->getSiteURL . $url;
|
||||
$url =~ s/^http:/https:/;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getStaticRdfFeedUrl ()
|
||||
|
||||
Returns the current asset's URL with .rdf concatenated onto it.
|
||||
|
||||
=cut
|
||||
|
||||
sub getStaticRdfFeedUrl {
|
||||
my $self = shift;
|
||||
my $url = $self->get("url") . '.rdf';
|
||||
$url = $self->session->url->gateway($url);
|
||||
if ($self->get("encryptPage")) {
|
||||
$url = $self->session->url->getSiteURL . $url;
|
||||
$url =~ s/^http:/https:/;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getStaticRssFeedUrl ()
|
||||
|
||||
Returns the current asset's URL with .rss concatenated onto it.
|
||||
|
||||
=cut
|
||||
|
||||
sub getStaticRssFeedUrl {
|
||||
my $self = shift;
|
||||
my $url = $self->get("url") . '.rss';
|
||||
$url = $self->session->url->gateway($url);
|
||||
if ($self->get("encryptPage")) {
|
||||
$url = $self->session->url->getSiteURL . $url;
|
||||
$url =~ s/^http:/https:/;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getFeed ()
|
||||
|
||||
Adds the syndicated items to the feed; returns the stringified edition.
|
||||
TODO: convert dates?
|
||||
|
||||
=cut
|
||||
|
||||
sub getFeed {
|
||||
my $self = shift;
|
||||
my $feed = shift;
|
||||
foreach my $item ( @{ $self->getRssFeedItems } ) {
|
||||
my $set_permalink_false = 0;
|
||||
my $new_item = $feed->add_item( %{ $item } );
|
||||
if (!$new_item->guid) {
|
||||
if ($new_item->link) {
|
||||
$new_item->guid( $new_item->link );
|
||||
} else {
|
||||
$new_item->guid( $self->session->id->generate );
|
||||
$set_permalink_false = 1;
|
||||
}
|
||||
}
|
||||
$new_item->guid( $new_item->guid, isPermaLink => 0 ) if $set_permalink_false;
|
||||
}
|
||||
$feed->title( $self->get('feedTitle') || $self->get('title') );
|
||||
$feed->description( $self->get('feedDescription') || $self->get('synopsis') );
|
||||
$feed->pubDate( $self->getContentLastModified );
|
||||
$feed->copyright( $self->get('feedCopyright') );
|
||||
$feed->link( $self->getUrl );
|
||||
# $feed->language( $lang );
|
||||
if ($self->get('feedImage')) {
|
||||
my $storage = WebGUI::Storage->get($self->session, $self->get('feedImage'));
|
||||
my @files = @{ $storage->getFiles };
|
||||
if (scalar @files) {
|
||||
$feed->image(
|
||||
$storage->getUrl( $files[0] ),
|
||||
$self->get('feedImageDescription') || $self->getTitle,
|
||||
$self->get('feedImageUrl') || $self->getUrl,
|
||||
$self->get('feedImageDescription') || $self->getTitle,
|
||||
( $storage->getSizeInPixels( $files[0] ) ) # expands to width and height
|
||||
);
|
||||
}
|
||||
}
|
||||
return $feed;
|
||||
}
|
||||
|
||||
sub prepareView {
|
||||
my $self = shift;
|
||||
$self->addHeaderLinks;
|
||||
return $self->next::method(@_);
|
||||
}
|
||||
|
||||
sub addHeaderLinks {
|
||||
my $self = shift;
|
||||
my $style = $self->session->style;
|
||||
my $title = $self->get('feedTitle') || $self->get("title");
|
||||
my %feeds = map { $_ => 1 } split /\n/, $self->get('feedHeaderLinks');
|
||||
my $addType = keys %feeds > 1;
|
||||
if ($feeds{rss}) {
|
||||
$style->setLink($self->getRssFeedUrl, {
|
||||
rel => 'alternate',
|
||||
type => 'application/rss+xml',
|
||||
title => $title . ( $addType ? ' (RSS)' : ''),
|
||||
});
|
||||
}
|
||||
if ($feeds{atom}) {
|
||||
$style->setLink($self->getAtomFeedUrl, {
|
||||
rel => 'alternate',
|
||||
type => 'application/atom+xml',
|
||||
title => $title . ( $addType ? ' (Atom)' : ''),
|
||||
});
|
||||
}
|
||||
if ($feeds{rdf}) {
|
||||
$style->setLink($self->getRdfFeedUrl, {
|
||||
rel => 'alternate',
|
||||
type => 'application/rdf+xml',
|
||||
title => $title . ( $addType ? ' (RDF)' : ''),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_viewAtom ()
|
||||
|
||||
Return Atom view of the syndicated items.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_viewAtom {
|
||||
my $self = shift;
|
||||
$self->session->http->setMimeType('application/atom+xml');
|
||||
return $self->getFeed( XML::FeedPP::Atom->new )->to_string;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_viewRdf ()
|
||||
|
||||
Return Rdf view of the syndicated items.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_viewRdf {
|
||||
my $self = shift;
|
||||
$self->session->http->setMimeType('application/rdf+xml');
|
||||
return $self->getFeed( XML::FeedPP::RDF->new )->to_string;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_viewRss ()
|
||||
|
||||
Return RSS view of the syndicated items.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_viewRss {
|
||||
my $self = shift;
|
||||
$self->session->http->setMimeType('application/rss+xml');
|
||||
return $self->getFeed( XML::FeedPP::RSS->new )->to_string;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getEditTabs ()
|
||||
|
||||
Adds an RSS tab to the Edit Tabs.
|
||||
|
||||
=cut
|
||||
|
||||
sub getEditTabs {
|
||||
my $self = shift;
|
||||
my $i18n = WebGUI::International->new($self->session,'AssetAspect_RssFeed');
|
||||
return ($self->next::method, ['rss', $i18n->get('RSS tab'), 1]);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
81
lib/WebGUI/AssetCollateral/Sku/Ad/Ad.pm
Normal file
81
lib/WebGUI/AssetCollateral/Sku/Ad/Ad.pm
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package WebGUI::AssetCollateral::Sku::Ad::Ad;
|
||||
|
||||
=head1 LEGAL
|
||||
|
||||
-------------------------------------------------------------------
|
||||
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
|
||||
-------------------------------------------------------------------
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
use strict;
|
||||
use base 'WebGUI::Crud';
|
||||
|
||||
#------------------------------------------------
|
||||
|
||||
=head1 crud_definition
|
||||
|
||||
defines the field this crud will contain
|
||||
|
||||
userID = the id of the user that purchased the ad
|
||||
transactionItemid = the id if the transaction item that completes this purchase
|
||||
adId = th id if the ad purchased
|
||||
clicksPurchased = the number of clicks the user purchased
|
||||
impressionsPurchased = the number of impressions the user purchased
|
||||
dateOfPurchase = the date of purchase
|
||||
storedImage = storage for the image
|
||||
isDeleted = boolean that indicates whether the ad has been deleted from the system
|
||||
|
||||
=cut
|
||||
|
||||
sub crud_definition {
|
||||
my ($class, $session) = @_;
|
||||
my $definition = $class->SUPER::crud_definition($session);
|
||||
$definition->{tableName} = 'adSkuPurchase';
|
||||
$definition->{tableKey} = 'adSkuPurchaseId';
|
||||
$definition->{properties} = {
|
||||
userId => {
|
||||
fieldType => 'user',
|
||||
defaultValue => undef,
|
||||
},
|
||||
transactionItemId => {
|
||||
fieldType => 'guid',
|
||||
defaultValue => undef,
|
||||
},
|
||||
adId => {
|
||||
fieldType => 'guid',
|
||||
defaultValue => undef,
|
||||
},
|
||||
clicksPurchased => {
|
||||
fieldType => 'integer',
|
||||
defaultValue => undef,
|
||||
},
|
||||
impressionsPurchased => {
|
||||
fieldType => 'integer',
|
||||
defaultValue => undef,
|
||||
},
|
||||
dateOfPurchase => {
|
||||
fieldType => 'date',
|
||||
defaultValue => undef,
|
||||
},
|
||||
storedImage => {
|
||||
fieldType => 'guid',
|
||||
defaultValue => undef,
|
||||
},
|
||||
isDeleted => {
|
||||
fieldType => 'yesNo',
|
||||
defaultValue => 0,
|
||||
},
|
||||
};
|
||||
return $definition;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
|
@ -317,8 +317,6 @@ sub exportAsHtml {
|
|||
# tell the user which asset we're exporting.
|
||||
unless ($quiet) {
|
||||
my $message = sprintf $i18n->get('exporting page'), $fullPath;
|
||||
$exportSession->var->end;
|
||||
$exportSession->close;
|
||||
$self->session->output->print($message);
|
||||
}
|
||||
|
||||
|
|
@ -335,7 +333,7 @@ sub exportAsHtml {
|
|||
|
||||
# next, tell the asset that we're exporting, so that it can export any
|
||||
# of its collateral or other extra data.
|
||||
eval { $asset->exportAssetCollateral($asset->exportGetUrlAsPath, $args) };
|
||||
eval { $asset->exportAssetCollateral($asset->exportGetUrlAsPath, $args, $session) };
|
||||
if($@) {
|
||||
$returnCode = 0;
|
||||
$message = $@;
|
||||
|
|
@ -389,7 +387,7 @@ sub exportAsHtml {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 exportAssetCollateral ( basePath, params )
|
||||
=head2 exportAssetCollateral ( basePath, params, [ session ] )
|
||||
|
||||
Plug in point for complicated assets (like the CS, the Calendar) to manage
|
||||
exporting their collateral data like other views, children threads and posts,
|
||||
|
|
@ -410,6 +408,10 @@ particular asset.
|
|||
A hashref with the quiet, userId, depth, and indexFileName parameters from
|
||||
L</exportAsHtml>.
|
||||
|
||||
=head3 session
|
||||
|
||||
The session doing the full export. Can be used to report status messages.
|
||||
|
||||
=cut
|
||||
|
||||
sub exportAssetCollateral {
|
||||
|
|
@ -541,7 +543,7 @@ sub exportGetUrlAsPath {
|
|||
my $fileTypes = $config->get('exportBinaryExtensions');
|
||||
|
||||
# get the asset's URL as a URI::URL object for easy parsing of components
|
||||
my $url = URI::URL->new($config->get("sitename")->[0] . $self->getUrl);
|
||||
my $url = URI::URL->new($self->session->url->getSiteURL . $self->getUrl);
|
||||
my @pathComponents = $url->path_components;
|
||||
shift @pathComponents; # first item is the empty string
|
||||
my $filename = pop @pathComponents;
|
||||
|
|
|
|||
|
|
@ -829,7 +829,6 @@ sub setParent {
|
|||
return 0 if ($newParent->getId eq $self->get("parentId")); # don't move it to where it already is
|
||||
return 0 if ($newParent->getId eq $self->getId); # don't move it to itself
|
||||
my $oldLineage = $self->get("lineage");
|
||||
return 0 unless $newParent->canEdit;
|
||||
my $lineage = $newParent->get("lineage").$newParent->getNextChildRank;
|
||||
return 0 if ($lineage =~ m/^$oldLineage/); # can't move it to its own child
|
||||
$self->session->db->beginTransaction;
|
||||
|
|
|
|||
|
|
@ -125,6 +125,15 @@ Imports the data exported by the exportAssetData method. If the asset already ex
|
|||
|
||||
A hash reference containing the exported data.
|
||||
|
||||
=head3 options
|
||||
|
||||
A hash reference of options to change how the import works
|
||||
|
||||
=head4 inheritPermissions
|
||||
|
||||
Forces the all assets in the package to inherit ownerUserId, groupIdView and groupIdEdit
|
||||
from the asset where it is deployed.
|
||||
|
||||
=cut
|
||||
|
||||
sub importAssetData {
|
||||
|
|
@ -212,7 +221,7 @@ sub importAssetCollateralData {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 importPackage ( storageLocation )
|
||||
=head2 importPackage ( storageLocation, options )
|
||||
|
||||
Imports the data from a webgui package file.
|
||||
|
||||
|
|
@ -220,6 +229,10 @@ Imports the data from a webgui package file.
|
|||
|
||||
A reference to a WebGUI::Storage object that contains a webgui package file.
|
||||
|
||||
=head3 options
|
||||
|
||||
A hashref of options that are passed onto importAssetData.
|
||||
|
||||
=cut
|
||||
|
||||
sub importPackage {
|
||||
|
|
|
|||
|
|
@ -298,11 +298,14 @@ sub createAccountSave {
|
|||
$self->saveParams($userId,$self->authMethod,$properties);
|
||||
|
||||
if ($self->getSetting("sendWelcomeMessage")){
|
||||
my $authInfo = "\n\n".$i18n->get(50).": ".$username;
|
||||
$authInfo .= "\n".$i18n->get(51).": ".$password if($password);
|
||||
$authInfo .= "\n\n";
|
||||
WebGUI::Inbox->new($self->session)->addMessage({
|
||||
message => $self->getSetting("welcomeMessage").$authInfo,
|
||||
my $var;
|
||||
$var->{welcomeMessage} = $self->getSetting("welcomeMessage");
|
||||
$var->{newUser_username} = $username;
|
||||
$var->{newUser_password} = $password;
|
||||
my $message = WebGUI::Asset::Template->new($self->session,$self->getSetting('welcomeMessageTemplate'))->process($var);
|
||||
WebGUI::Macro::process($self->session,\$message);
|
||||
WebGUI::Inbox->new($self->session)->addMessage({
|
||||
message => $message,
|
||||
subject => $i18n->get(870),
|
||||
userId => $self->userId,
|
||||
status => 'completed',
|
||||
|
|
|
|||
|
|
@ -273,10 +273,13 @@ sub createAccountSave {
|
|||
to => $profile->{email},
|
||||
subject => $i18n->get('email address validation email subject','AuthWebGUI')
|
||||
});
|
||||
$mail->addText(
|
||||
$i18n->get('email address validation email body','AuthWebGUI') . "\n\n"
|
||||
. $session->url->page("op=auth;method=validateEmail;key=".$key, 'full') . "\n\n"
|
||||
);
|
||||
my $var;
|
||||
$var->{newUser_username} = $username;
|
||||
$var->{activationUrl} = $session->url->page("op=auth;method=validateEmail;key=".$key, 'full');
|
||||
my $text =
|
||||
WebGUI::Asset::Template->new($self->session,$self->getSetting('accountActivationTemplate'))->process($var);
|
||||
WebGUI::Macro::process($self->session,\$text);
|
||||
$mail->addText($text);
|
||||
$mail->addFooter;
|
||||
$mail->send;
|
||||
$self->user->status("Deactivated");
|
||||
|
|
@ -494,7 +497,7 @@ sub editUserSettingsForm {
|
|||
-label => $i18n->get(868,'WebGUI'),
|
||||
-hoverHelp => $i18n->get('868 help','WebGUI'),
|
||||
);
|
||||
$f->textarea(
|
||||
$f->HTMLArea(
|
||||
-name => "webguiWelcomeMessage",
|
||||
-value => $self->session->setting->get("webguiWelcomeMessage"),
|
||||
-label => $i18n->get(869,'WebGUI'),
|
||||
|
|
@ -574,7 +577,21 @@ sub editUserSettingsForm {
|
|||
-label => $i18n->get("password recovery template"),
|
||||
-hoverHelp => $i18n->get("password recovery template help")
|
||||
);
|
||||
return $f->printRowsOnly;
|
||||
$f->template(
|
||||
-name => "webguiWelcomeMessageTemplate",
|
||||
-value => $self->session->setting->get("webguiWelcomeMessageTemplate"),
|
||||
-namespace => "Auth/WebGUI/Welcome",
|
||||
-label => $i18n->get("welcome message template"),
|
||||
-hoverHelp => $i18n->get("welcome message template help")
|
||||
);
|
||||
$f->template(
|
||||
-name => "webguiAccountActivationTemplate",
|
||||
-value => $self->session->setting->get("webguiAccountActivationTemplate"),
|
||||
-namespace => "Auth/WebGUI/Activation",
|
||||
-label => $i18n->get("account activation template"),
|
||||
-hoverHelp => $i18n->get("account activation template help")
|
||||
);
|
||||
return $f->printRowsOnly;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -625,6 +642,8 @@ sub editUserSettingsFormSave {
|
|||
$s->set("webguiExpiredPasswordTemplate", $f->process("webguiExpiredPasswordTemplate","template"));
|
||||
$s->set("webguiLoginTemplate", $f->process("webguiLoginTemplate","template"));
|
||||
$s->set("webguiPasswordRecoveryTemplate", $f->process("webguiPasswordRecoveryTemplate","template"));
|
||||
$s->set("webguiWelcomeMessageTemplate", $f->process("webguiWelcomeMessageTemplate","template"));
|
||||
$s->set("webguiAccountActivationTemplate", $f->process("webguiAccountActivationTemplate","template"));
|
||||
|
||||
if (@errors) {
|
||||
return \@errors;
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ sub getFolder {
|
|||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getNamepsaceRoot ( )
|
||||
=head2 getNamespaceRoot ( )
|
||||
|
||||
Figures out what the cache root for this namespace should be. A class method.
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,17 @@ sub handler {
|
|||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 formatXML ( content )
|
||||
|
||||
Escape XML entities, &, <, >, ' and ".
|
||||
|
||||
=head3 content
|
||||
|
||||
The content that will have XML entities escaped.
|
||||
|
||||
=cut
|
||||
|
||||
sub formatXML {
|
||||
my $content = shift;
|
||||
$content =~ s/&/&/g;
|
||||
|
|
|
|||
190
lib/WebGUI/Form/AdSpace.pm
Normal file
190
lib/WebGUI/Form/AdSpace.pm
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
package WebGUI::Form::AdSpace;
|
||||
|
||||
=head1 LEGAL
|
||||
|
||||
-------------------------------------------------------------------
|
||||
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
|
||||
-------------------------------------------------------------------
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base 'WebGUI::Form::SelectList';
|
||||
use WebGUI::International;
|
||||
use WebGUI::SQL;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Package WebGUI::Form::AdSpace
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Creates a group chooser field for AdSpace values.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
This is a subclass of WebGUI::Form::SelectList.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
The following methods are specifically available from this class. Check the superclass for additional methods.
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 areOptionsSettable ( )
|
||||
|
||||
Returns 0.
|
||||
|
||||
=cut
|
||||
|
||||
sub areOptionsSettable {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 definition ( [ additionalTerms ] )
|
||||
|
||||
See the super class for additional details.
|
||||
|
||||
=head3 additionalTerms
|
||||
|
||||
The following additional parameters have been added via this sub class.
|
||||
|
||||
=head4 size
|
||||
|
||||
How many rows should be displayed at once? Defaults to 1.
|
||||
|
||||
=head4 defaultValue
|
||||
|
||||
This will be used if no value is specified. Should be passed as an array reference. Defaults to 1.
|
||||
|
||||
=cut
|
||||
|
||||
sub definition {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $definition = shift || [];
|
||||
push(@{$definition}, {
|
||||
size=>{
|
||||
defaultValue=>1
|
||||
},
|
||||
});
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getDatabaseFieldType ( )
|
||||
|
||||
Returns "CHAR(22) BINARY".
|
||||
|
||||
=cut
|
||||
|
||||
sub getDatabaseFieldType {
|
||||
return "CHAR(22) BINARY";
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getName ( session )
|
||||
|
||||
Returns the human readable name of this control.
|
||||
|
||||
=cut
|
||||
|
||||
sub getName {
|
||||
my ($self, $session) = @_;
|
||||
return WebGUI::International->new($session, 'WebGUI')->get('Ad Space control name');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getValueAsHtml ( )
|
||||
|
||||
Formats as a name.
|
||||
|
||||
=cut
|
||||
|
||||
sub getValueAsHtml {
|
||||
my $self = shift;
|
||||
my $item = WebGUI::AdSpace->new($self->session, $self->getOriginalValue);
|
||||
if (defined $item) {
|
||||
return $item->name;
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 isDynamicCompatible ( )
|
||||
|
||||
A class method that returns a boolean indicating whether this control is compatible with the DynamicField control.
|
||||
|
||||
=cut
|
||||
|
||||
sub isDynamicCompatible {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 toHtml ( )
|
||||
|
||||
Returns a group pull-down field. A group pull down provides a select list that provides name value pairs for all the groups in the WebGUI system.
|
||||
|
||||
=cut
|
||||
|
||||
sub toHtml {
|
||||
my $self = shift;
|
||||
my $options = { map { $_->getId => $_->get('name') } ( @{ WebGUI::AdSpace->getAdSpaces($self->session) } ) };
|
||||
$self->set('defaultValue', ( keys %{$options} )[0] );
|
||||
$self->set('options', $options );
|
||||
return $self->SUPER::toHtml();
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 toHtmlAsHidden ( )
|
||||
|
||||
Creates a series of hidden fields representing the data in the list.
|
||||
|
||||
=cut
|
||||
|
||||
sub toHtmlAsHidden {
|
||||
my $self = shift;
|
||||
my $options = { map { $_->getId => $_->get('name') } ( @{ WebGUI::AdSpace->getAdSpaces($self->session) } ) };
|
||||
$self->set('defaultValue', ( keys %{$options} )[0] );
|
||||
$self->set('options', $options );
|
||||
return $self->SUPER::toHtmlAsHidden();
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 toHtmlWithWrapper ( )
|
||||
|
||||
Renders the form field to HTML as a table row complete with labels, subtext, hoverhelp, etc. Also adds a manage icon next to the field if the current user is in the admins group.
|
||||
|
||||
=cut
|
||||
|
||||
sub toHtmlWithWrapper {
|
||||
my $self = shift;
|
||||
if ($self->session->user->isAdmin) {
|
||||
my $subtext = $self->session->icon->manage("op=manageAdSpaces");
|
||||
$self->set("subtext",$subtext . $self->get("subtext"));
|
||||
}
|
||||
return $self->SUPER::toHtmlWithWrapper;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
|
|
@ -182,6 +182,12 @@ sub toHtml {
|
|||
return $self->SUPER::toHtml.'<p style="display:inline;vertical-align:middle;"><img src="'.$storage->getUrl($filename).'" style="border-style:none;vertical-align:middle;" alt="captcha" /></p>';
|
||||
}
|
||||
|
||||
=head2 getErrorMessage ( )
|
||||
|
||||
Returns an internationalized error message based on which kind of captcha is being used.
|
||||
|
||||
=cut
|
||||
|
||||
sub getErrorMessage {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ sub toHtml {
|
|||
my $output = "";
|
||||
|
||||
# Do our superclass's job
|
||||
my $value = $self->fixMacros($self->fixTags($self->fixSpecialCharacters($self->getOriginalValue)));
|
||||
my $value = $self->fixMacros($self->fixTags($self->fixSpecialCharacters(scalar $self->getOriginalValue)));
|
||||
my $width = $self->get('width') || 400;
|
||||
my $height = $self->get('height') || 150;
|
||||
my ($style, $url) = $self->session->quick(qw(style url));
|
||||
|
|
|
|||
|
|
@ -196,6 +196,9 @@ sub definition {
|
|||
idPrefix=>{
|
||||
defaultValue=>undef
|
||||
},
|
||||
allowEmpty=>{
|
||||
defaultValue => 0,
|
||||
},
|
||||
});
|
||||
return $definition;
|
||||
}
|
||||
|
|
@ -686,7 +689,7 @@ Renders the form field to HTML as a hidden field rather than whatever field type
|
|||
sub toHtmlAsHidden {
|
||||
my $self = shift;
|
||||
return '<input type="hidden" name="'.$self->get("name").'" value="'.
|
||||
$self->fixQuotes($self->fixMacros($self->fixSpecialCharacters($self->getOriginalValue()))).'" />'."\n";
|
||||
$self->fixQuotes($self->fixMacros($self->fixSpecialCharacters(scalar $self->getOriginalValue()))).'" />'."\n";
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
|
|||
173
lib/WebGUI/Form/Keywords.pm
Normal file
173
lib/WebGUI/Form/Keywords.pm
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
package WebGUI::Form::Keywords;
|
||||
|
||||
=head1 LEGAL
|
||||
|
||||
-------------------------------------------------------------------
|
||||
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
|
||||
-------------------------------------------------------------------
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use base 'WebGUI::Form::Text';
|
||||
use WebGUI::International;
|
||||
use JSON ();
|
||||
use WebGUI::Keyword;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Package WebGUI::Form::Keywords
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Creates a keywords chooser field with multiple select and autocomplete.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
This is a subclass of WebGUI::Form::SelectList.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
The following methods are specifically available from this class. Check the superclass for additional methods.
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getDatabaseFieldType ( )
|
||||
|
||||
Returns "CHAR(22) BINARY".
|
||||
|
||||
=cut
|
||||
|
||||
sub getDatabaseFieldType {
|
||||
return "CHAR(255)";
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getName ( session )
|
||||
|
||||
Returns the human readable name of this control.
|
||||
|
||||
=cut
|
||||
|
||||
sub getName {
|
||||
my ($self, $session) = @_;
|
||||
return WebGUI::International->new($session, 'Asset')->get('keywords');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 isDynamicCompatible ( )
|
||||
|
||||
A class method that returns a boolean indicating whether this control is compatible with the DynamicField control.
|
||||
|
||||
=cut
|
||||
|
||||
sub isDynamicCompatible {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 toHtml ( )
|
||||
|
||||
Returns a keyword pull-down field. A keyword pull down provides a select list that provides name value pairs for all the keywords in the WebGUI system.
|
||||
|
||||
=cut
|
||||
|
||||
sub toHtml {
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $style = $session->style;
|
||||
my $url = $session->url;
|
||||
|
||||
$style->setLink($url->extras("yui/build/autocomplete/assets/skins/sam/autocomplete.css"), {rel=>"stylesheet", type=>"text/css"});
|
||||
$style->setScript($url->extras("yui/build/yahoo-dom-event/yahoo-dom-event.js"), {type=>"text/javascript"});
|
||||
$style->setScript($url->extras("yui/build/datasource/datasource-min.js"), {type=>"text/javascript"});
|
||||
$style->setScript($url->extras("yui/build/autocomplete/autocomplete-min.js"), {type=>"text/javascript"});
|
||||
$style->setRawHeadTags('<style type="text/css">.yui-skin-sam.webgui-keywords-autocomplete .yui-ac-input { position: static; width: auto }</style>');
|
||||
|
||||
my $name = $self->generateIdParameter($self->get('name'));
|
||||
my $autocompleteDiv = $self->privateName('autocomplete');
|
||||
my $pageUrl = $url->page;
|
||||
my $output
|
||||
= '<div class="yui-skin-sam webgui-keywords-autocomplete"><div>' . $self->SUPER::toHtml
|
||||
. '<div id="' . $autocompleteDiv . '"></div>'
|
||||
. '<script type="text/javascript">' . <<"END_SCRIPT" . '</script></div></div>';
|
||||
(function() {
|
||||
var oDS = new YAHOO.util.XHRDataSource('$pageUrl');
|
||||
oDS.responseType = YAHOO.util.XHRDataSource.TYPE_JSON;
|
||||
oDS.responseSchema = {
|
||||
resultsList : "keywords",
|
||||
};
|
||||
|
||||
var oAC = new YAHOO.widget.AutoComplete("$name", "$autocompleteDiv", oDS);
|
||||
oAC.queryDelay = 0.5;
|
||||
oAC.maxResultsDisplayed = 20;
|
||||
oAC.minQueryLength = 3;
|
||||
oAC.delimChar = [','];
|
||||
|
||||
oAC.generateRequest = function(sQuery) {
|
||||
return "?op=formHelper;class=Keywords;sub=searchAsJSON;search=" + sQuery ;
|
||||
};
|
||||
})();
|
||||
END_SCRIPT
|
||||
return $output;
|
||||
}
|
||||
|
||||
sub www_searchAsJSON {
|
||||
my $session = shift;
|
||||
my $search = $session->form->param('search');
|
||||
my $keyword = WebGUI::Keyword->new($session);
|
||||
|
||||
my $keywords = $keyword->findKeywords({search => $search, limit => 20});
|
||||
$session->http->setMimeType('application/json');
|
||||
|
||||
return JSON::to_json({keywords => $keywords});
|
||||
}
|
||||
|
||||
sub getDefaultValue {
|
||||
my $self = shift;
|
||||
return _formatKeywordsAsWanted($self->SUPER::getDefaultValue(@_));
|
||||
}
|
||||
|
||||
sub getOriginalValue {
|
||||
my $self = shift;
|
||||
return _formatKeywordsAsWanted($self->SUPER::getOriginalValue(@_));
|
||||
}
|
||||
|
||||
sub getValue {
|
||||
my $self = shift;
|
||||
return _formatKeywordsAsWanted($self->SUPER::getValue(@_));
|
||||
}
|
||||
|
||||
sub _formatKeywordsAsWanted {
|
||||
my @keywords;
|
||||
if (@_ == 1 && ref $_[0] eq 'ARRAY') {
|
||||
@keywords = @{ $_[0] };
|
||||
}
|
||||
else {
|
||||
for my $param (@_) {
|
||||
for my $keyword (split /,/, $param) {
|
||||
$keyword =~ s/^\s+//;
|
||||
$keyword =~ s/\s+$//;
|
||||
push @keywords, $keyword;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wantarray) {
|
||||
return @keywords;
|
||||
}
|
||||
return join(', ', @keywords);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
|
@ -220,7 +220,7 @@ sub getValue {
|
|||
@values = $self->session->form->param($self->get("name"));
|
||||
}
|
||||
}
|
||||
if (scalar @values < 1) {
|
||||
if (scalar @values < 1 && ! $self->get('allowEmpty')) {
|
||||
@values = $self->getDefaultValue;
|
||||
}
|
||||
return wantarray ? @values : join("\n",@values);
|
||||
|
|
@ -262,18 +262,17 @@ Returns the either the "value" ore "defaultValue" passed in to the object in tha
|
|||
sub getOriginalValue {
|
||||
my $self = shift;
|
||||
my @values = ();
|
||||
foreach my $value ($self->get("value")) {
|
||||
if (scalar @values < 1 && defined $value) {
|
||||
if (ref $value eq "ARRAY") {
|
||||
@values = @{$value};
|
||||
}
|
||||
else {
|
||||
$value =~ s/\r//g;
|
||||
@values = split "\n", $value;
|
||||
}
|
||||
my $value = $self->get("value");
|
||||
if (defined $value) {
|
||||
if (ref $value eq "ARRAY") {
|
||||
@values = @{$value};
|
||||
}
|
||||
else {
|
||||
$value =~ s/\r//g;
|
||||
@values = split "\n", $value;
|
||||
}
|
||||
}
|
||||
if (@values) {
|
||||
if (@values || ($self->get('allowEmpty') && defined $value) ) {
|
||||
return wantarray ? @values : join("\n",@values);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ sub isDynamicCompatible {
|
|||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 new
|
||||
=head2 getOptions
|
||||
|
||||
Create a new WebGUI::Form::SelectRichEditor object and populate it with all
|
||||
the available Rich Text Editor assets.
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ Renders the form field to HTML as a table row. The row is not displayed because
|
|||
|
||||
sub toHtmlWithWrapper {
|
||||
my $self = shift;
|
||||
my $value = $self->fixMacros($self->fixQuotes($self->fixSpecialCharacters($self->getOriginalValue))) || '';
|
||||
my $value = $self->fixMacros($self->fixQuotes($self->fixSpecialCharacters(scalar $self->getOriginalValue))) || '';
|
||||
if ($value) {
|
||||
my $manageButton = $self->session->icon->manage("op=editGroup;gid=".$value);
|
||||
$self->set("subtext",$manageButton . $self->get("subtext"));
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ Renders an input tag of type text.
|
|||
|
||||
sub toHtml {
|
||||
my $self = shift;
|
||||
my $value = $self->fixMacros($self->fixQuotes($self->fixSpecialCharacters($self->getOriginalValue)));
|
||||
my $value = $self->fixMacros($self->fixQuotes($self->fixSpecialCharacters(scalar $self->getOriginalValue)));
|
||||
return '<input id="'.$self->get('id').'" type="text" name="'.$self->get("name").'" value="'.$value.'" size="'.$self->get("size").'" maxlength="'.$self->get("maxlength").'" '.$self->get("extras").' />';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ Renders an input tag of type text.
|
|||
|
||||
sub toHtml {
|
||||
my $self = shift;
|
||||
my $value = $self->fixMacros($self->fixTags($self->fixSpecialCharacters($self->getOriginalValue)));
|
||||
my $value = $self->fixMacros($self->fixTags($self->fixSpecialCharacters(scalar $self->getOriginalValue)));
|
||||
my $width = $self->get('width') || 400;
|
||||
my $height = $self->get('height') || 150;
|
||||
my ($style, $url) = $self->session->quick(qw(style url));
|
||||
|
|
@ -195,6 +195,14 @@ sub toHtml {
|
|||
return $out;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getValueAsHtml
|
||||
|
||||
Returns the form value as text, encoding HTML entities.
|
||||
|
||||
=cut
|
||||
|
||||
sub getValueAsHtml {
|
||||
my $self = shift;
|
||||
my $value = $self->SUPER::getValueAsHtml(@_);
|
||||
|
|
|
|||
|
|
@ -442,6 +442,18 @@ sub splitTag {
|
|||
return @result if wantarray;
|
||||
return $result[0];
|
||||
}
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 WebGUI::HTML::splitHeadBody($html);
|
||||
|
||||
splits an block of HTML into a HEAD and a BODY section
|
||||
|
||||
=head3 html
|
||||
|
||||
The block of HTML text that will be disected
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
sub splitHeadBody {
|
||||
my $html = shift;
|
||||
|
|
|
|||
29
lib/WebGUI/Help/Asset_Carousel.pm
Normal file
29
lib/WebGUI/Help/Asset_Carousel.pm
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package WebGUI::Help::Asset_Carousel;
|
||||
use strict;
|
||||
|
||||
our $HELP = {
|
||||
|
||||
'search template' => {
|
||||
title => 'carousel template help title',
|
||||
body => '',
|
||||
isa => [
|
||||
{ namespace => "Asset_Wobject",
|
||||
tag => "wobject template variables",
|
||||
},
|
||||
],
|
||||
variables => [
|
||||
{ 'name' => 'item_loop',
|
||||
'variables' => [
|
||||
{ 'name' => 'text' },
|
||||
{ 'name' => 'itemId'},
|
||||
{ 'name' => 'sequenceNumber'},
|
||||
],
|
||||
}
|
||||
],
|
||||
related => [],
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
1;
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ our $HELP = {
|
|||
{ 'name' => 'page.isChild' },
|
||||
{ 'name' => 'page.isParent' },
|
||||
{ 'name' => 'page.isCurrent' },
|
||||
{ 'name' => 'page.isDescendent' },
|
||||
{ 'name' => 'page.isDescendant' },
|
||||
{ 'name' => 'page.isAncestor' },
|
||||
{ 'name' => 'page.inBranchRoot' },
|
||||
{ 'name' => 'page.isSibling' },
|
||||
|
|
|
|||
|
|
@ -136,11 +136,7 @@ our $HELP = {
|
|||
private => 1,
|
||||
title => 'post asset variables title',
|
||||
body => '',
|
||||
isa => [
|
||||
{ tag => 'asset template asset variables',
|
||||
namespace => 'Asset'
|
||||
},
|
||||
],
|
||||
isa => [ ],
|
||||
variables => [
|
||||
{ 'name' => 'storageId' },
|
||||
{ 'name' => 'threadId' },
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
package WebGUI::Help::Asset_RSSFromParent;
|
||||
use strict;
|
||||
|
||||
our $HELP = {
|
||||
'rss from parent' => {
|
||||
title => 'rss from parent title',
|
||||
body => 'rss from parent body',
|
||||
|
||||
# use the following to inherit stuff other help entries
|
||||
isa => [
|
||||
{ tag => 'template variables',
|
||||
namespace => 'Asset_Template'
|
||||
},
|
||||
],
|
||||
fields => [ #This array is used to list hover help for form fields.
|
||||
],
|
||||
variables => [
|
||||
{ 'name' => 'title',
|
||||
'description' => 'title.parent'
|
||||
},
|
||||
{ 'name' => 'link',
|
||||
'description' => 'title.parent'
|
||||
},
|
||||
{ 'name' => 'description',
|
||||
'description' => 'description.parent'
|
||||
},
|
||||
{ 'name' => 'generator' },
|
||||
{ 'name' => 'lastBuildDate' },
|
||||
{ 'name' => 'webMaster' },
|
||||
{ 'name' => 'docs' },
|
||||
{ 'name' => 'item_loop',
|
||||
variables => [
|
||||
{ 'name' => 'title',
|
||||
'description' => 'title.item'
|
||||
},
|
||||
{ 'name' => 'link',
|
||||
'description' => 'title.item'
|
||||
},
|
||||
{ 'name' => 'description',
|
||||
'description' => 'description.item'
|
||||
},
|
||||
{ 'name' => 'guid' },
|
||||
{ 'name' => 'pubDate' },
|
||||
]
|
||||
},
|
||||
],
|
||||
related => [ ##This lists other help articles that are related to this one
|
||||
],
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
1; ##All perl modules must return true
|
||||
|
|
@ -21,8 +21,11 @@ our $HELP = {
|
|||
variables => [
|
||||
{ name => "shelves" , required=>1},
|
||||
{ name => "products" , required=>1, variables => [
|
||||
{ name => "url",
|
||||
description => 'product_url', },
|
||||
{ name => "thumbnailUrl" },
|
||||
{ name => "price" },
|
||||
{ name => "addToCartForm" },
|
||||
],
|
||||
},
|
||||
{ name => "templateId", description=>"shelf template help" },
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ our $HELP = {
|
|||
{ 'name' => 'thing_deleteUrl' },
|
||||
{ 'name' => 'thing_searchUrl' },
|
||||
{ 'name' => 'thing_addUrl' },
|
||||
{ 'name' => 'thing_copyUrl' },
|
||||
{ 'name' => 'thing_copyIcon' },
|
||||
]
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -163,6 +163,28 @@ our $HELP = {
|
|||
related => [],
|
||||
},
|
||||
|
||||
'webgui welcome message template' => {
|
||||
title => 'welcome message template title',
|
||||
body => '',
|
||||
variables => [
|
||||
{ 'name' => 'welcomeMessage' },
|
||||
{ 'name' => 'newUser_username' },
|
||||
{ 'name' => 'newUser_password' },
|
||||
],
|
||||
fields => [],
|
||||
related => []
|
||||
},
|
||||
|
||||
'account activation template' => {
|
||||
title => 'account activation template title',
|
||||
body => '',
|
||||
variables => [
|
||||
{ 'name' => 'newUser_username' },
|
||||
{ 'name' => 'activationUrl' },
|
||||
],
|
||||
fields => [],
|
||||
related => []
|
||||
},
|
||||
};
|
||||
|
||||
1;
|
||||
|
|
|
|||
|
|
@ -163,14 +163,9 @@ sub create {
|
|||
$preface = sprintf($i18n->get('from user preface'), $fromUser->username);
|
||||
}
|
||||
my $msg = (defined $properties->{emailMessage}) ? $properties->{emailMessage} : $self->{_properties}{message};
|
||||
if ($msg =~ m/\<.*\>/) {
|
||||
$msg = '<p>' . $preface . '</p><br />'.$msg if($preface ne "");
|
||||
$mail->addHtml($msg);
|
||||
} else {
|
||||
$msg = $preface."\n\n".$msg if($preface ne "");
|
||||
$mail->addText($msg);
|
||||
}
|
||||
$mail->addFooter;
|
||||
$msg = '<p>' . $preface . '</p><br />'.$msg if($preface ne "");
|
||||
$mail->addHtml($msg);
|
||||
$mail->addFooter;
|
||||
$mail->queue;
|
||||
}
|
||||
$self->{_session} = $session;
|
||||
|
|
|
|||
|
|
@ -88,6 +88,67 @@ sub deleteKeyword {
|
|||
$self->session->db->write("delete from assetKeyword where keyword=?", [$options->{keyword}]);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 findKeywords ( $options )
|
||||
|
||||
Find keywords.
|
||||
|
||||
=head3 $options
|
||||
|
||||
A hashref of options to change the behavior of the method.
|
||||
|
||||
=head4 asset
|
||||
|
||||
Find all keywords for all assets below an asset, providing a WebGUI::Asset object.
|
||||
|
||||
=head4 assetId
|
||||
|
||||
Find all keywords for all assets below an asset, providing an assetId.
|
||||
|
||||
=head4 search
|
||||
|
||||
Find all keywords using the SQL clause LIKE. This can be used in tandem with asset or assetId.
|
||||
|
||||
=head4 limit
|
||||
|
||||
Limit the number of keywords that are returned.
|
||||
|
||||
=cut
|
||||
|
||||
sub findKeywords {
|
||||
my $self = shift;
|
||||
my $options = shift;
|
||||
|
||||
my $sql = 'SELECT keyword FROM assetKeyword';
|
||||
my @where;
|
||||
my @placeholders;
|
||||
my $parentAsset;
|
||||
if ($options->{asset}) {
|
||||
$parentAsset = $options->{asset};
|
||||
}
|
||||
if ($options->{assetId}) {
|
||||
$parentAsset = WebGUI::Asset->new($self->session, $options->{assetId});
|
||||
}
|
||||
if ($parentAsset) {
|
||||
$sql .= ' INNER JOIN asset USING (assetId)';
|
||||
push @where, 'lineage LIKE ?';
|
||||
push @placeholders, $parentAsset->get('lineage') . '%';
|
||||
}
|
||||
if ($options->{search}) {
|
||||
push @where, 'keyword LIKE ?';
|
||||
push @placeholders, '%' . $options->{search} . '%';
|
||||
}
|
||||
if (@where) {
|
||||
$sql .= ' WHERE ' . join(' AND ', @where);
|
||||
}
|
||||
$sql .= ' GROUP BY keyword';
|
||||
if ($options->{limit}) {
|
||||
$sql .= ' LIMIT ' . $options->{limit};
|
||||
}
|
||||
my $keywords = $self->session->db->buildArrayRef($sql, \@placeholders);
|
||||
return $keywords;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
|
|
@ -123,14 +184,32 @@ sub generateCloud {
|
|||
my $self = shift;
|
||||
my $options = shift;
|
||||
my $display = $options->{displayAsset} || $options->{startAsset};
|
||||
my $sth = $self->session->db->read("select count(*) as keywordTotal, keyword from assetKeyword
|
||||
left join asset using (assetId) where lineage like ? group by keyword order by keywordTotal desc limit 50",
|
||||
[ $options->{startAsset}->get("lineage").'%' ]);
|
||||
my $includeKeywords = $options->{includeOnlyKeywords};
|
||||
my $maxKeywords = $options->{maxKeywords} || 50;
|
||||
if ($maxKeywords > 100) {
|
||||
$maxKeywords = 100;
|
||||
}
|
||||
my $urlCallback = $options->{urlCallback};
|
||||
my $extraWhere = '';
|
||||
my @extraPlaceholders;
|
||||
if ($includeKeywords) {
|
||||
$extraWhere .= ' AND keyword IN (' . join(',', ('?') x @{$includeKeywords}) . ')';
|
||||
push @extraPlaceholders, @{$includeKeywords};
|
||||
}
|
||||
my $sth = $self->session->db->read("SELECT COUNT(*) as keywordTotal, keyword FROM assetKeyword
|
||||
LEFT JOIN asset USING (assetId) WHERE lineage LIKE ? $extraWhere
|
||||
GROUP BY keyword ORDER BY keywordTotal DESC LIMIT ?",
|
||||
[ $options->{startAsset}->get("lineage").'%', @extraPlaceholders, $maxKeywords ]);
|
||||
my $cloud = HTML::TagCloud->new(levels=>$options->{cloudLevels} || 24);
|
||||
while (my ($count, $keyword) = $sth->array) {
|
||||
$cloud->add($keyword, $display->getUrl("func=".$options->{displayFunc}.";keyword=".$keyword), $count);
|
||||
my $url
|
||||
= $urlCallback ? $display->$urlCallback($keyword)
|
||||
: $options->{displayFunc} ? $display->getUrl("func=".$options->{displayFunc}.";keyword=".$keyword)
|
||||
: $display->getUrl("keyword=".$keyword)
|
||||
;
|
||||
$cloud->add($keyword, $url, $count);
|
||||
}
|
||||
return $cloud->html_and_css($options->{maxKeywords});
|
||||
return $cloud->html_and_css($maxKeywords);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -152,13 +231,14 @@ A boolean, that if set to 1 will return the keywords as an array reference rathe
|
|||
|
||||
sub getKeywordsForAsset {
|
||||
my ($self, $options) = @_;
|
||||
my @keywords = $self->session->db->buildArray("select keyword from assetKeyword where assetId=?",
|
||||
[$options->{asset}->getId]);
|
||||
my $assetId = $options->{asset} ? $options->{asset}->getId : $options->{assetId};
|
||||
my $keywords = $self->session->db->buildArrayRef("select keyword from assetKeyword where assetId=?",
|
||||
[$assetId]);
|
||||
if ($options->{asArrayRef}) {
|
||||
return \@keywords;
|
||||
return $keywords;
|
||||
}
|
||||
else {
|
||||
return join(" ", map({ (m/\s/) ? '"' . $_ . '"' : $_ } @keywords));
|
||||
return join(', ', @$keywords);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -321,9 +401,9 @@ Either a string of space-separated keywords, or an array reference of keywords t
|
|||
sub setKeywordsForAsset {
|
||||
my $self = shift;
|
||||
my $options = shift;
|
||||
my $keywords = [];
|
||||
my $keywords;
|
||||
if (ref $options->{keywords} eq "ARRAY") {
|
||||
$keywords = $options->{keywords};
|
||||
$keywords = $options->{keywords};
|
||||
}
|
||||
else {
|
||||
$keywords = string2list($options->{keywords});
|
||||
|
|
@ -339,7 +419,7 @@ sub setKeywordsForAsset {
|
|||
next
|
||||
if $found_keywords{$keyword};
|
||||
$found_keywords{$keyword}++;
|
||||
$sth->execute([$assetId, lc($keyword)]);
|
||||
$sth->execute([$assetId, $keyword]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -352,35 +432,18 @@ Returns an array reference of phrases.
|
|||
|
||||
=head3 string
|
||||
|
||||
A scalar containing space separated phrases.
|
||||
A scalar containing comma separated phrases.
|
||||
|
||||
=cut
|
||||
|
||||
sub string2list {
|
||||
my $text = shift;
|
||||
return if (ref $text);
|
||||
my @words = ();
|
||||
my $word = '';
|
||||
my $errorFlag = 0;
|
||||
while ( defined $text and length $text and not $errorFlag) {
|
||||
if ($text =~ s/\A(?: ([^\"\s\\]+) | \\(.) )//mx) {
|
||||
$word .= $1;
|
||||
}
|
||||
elsif ($text =~ s/\A"((?:[^\"\\]|\\.)*)"//mx) {
|
||||
$word .= $1;
|
||||
}
|
||||
elsif ($text =~ s/\A\s+//m){
|
||||
push(@words, $word);
|
||||
$word = '';
|
||||
}
|
||||
elsif ($text =~ s/\A"//) {
|
||||
$errorFlag = 1;
|
||||
}
|
||||
else {
|
||||
$errorFlag = 1;
|
||||
}
|
||||
my @words = split /,/, $text;
|
||||
for my $word (@words) {
|
||||
$word =~ s/^\s+//;
|
||||
$word =~ s/\s+$//;
|
||||
}
|
||||
push(@words, $word);
|
||||
return \@words;
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue