';
return $ac->render($output);
}
#-------------------------------------------------------------------
=head2 canAdd ( session, [userId, groupId] )
Verifies that the user has the privileges necessary to add this type of asset and that the requested asset
can be added as a child of this asset. Return a boolean.
A class method.
=head3 session
The session variable.
=head3 userId
Unique hash identifier for a user. If not supplied, current user.
=head3 groupId
Only developers extending this method should use this parameter. By default WebGUI will check groups in this order, whichever is defined:
=over 4
=item *
Group id assigned in the config file for each asset.
=item *
Group assigned by the developer in the asset itself if s/he extended this method to do so.
=item *
The "turn admin on" group which is group id 12.
=back
=cut
sub canAdd {
my $className = shift;
my $session = shift;
my $userId = shift || $session->user->userId;
my $user = WebGUI::User->new($session, $userId);
my $subclassGroupId = shift;
my $addPrivsGroup = $session->config->get("assets/".$className."/addGroup");
my $groupId = $addPrivsGroup || $subclassGroupId || '12';
my $validParent = $className->validParent($session);
return $user->isInGroup($groupId) && $validParent;
}
#-------------------------------------------------------------------
=head2 canEdit ( [userId] )
Verifies group and user permissions to be able to edit asset. Returns 1 if owner is userId, otherwise returns the result checking if the user is a member of the group that can edit.
=head3 userId
Unique hash identifier for a user. If not supplied, current user.
=cut
sub canEdit {
my $self = shift;
my $userId = shift || $self->session->user->userId;
if ($userId eq $self->get("ownerUserId")) {
return 1;
}
my $user = WebGUI::User->new($self->session, $userId);
return $user->isInGroup($self->get("groupIdEdit"));
}
#-------------------------------------------------------------------
=head2 canView ( [userId] )
Verifies group and user permissions to be able to view asset. Returns 1 if user is owner of asset. Returns 1 if within the visibility date range of the asset AND user in the View group of asset. Otherwise, returns the result of the canEdit.
Only the owner and the editors can always see the asset, regardless of time/date restrictions on the asset.
=head3 userId
Unique hash identifier for a user. If not specified, uses current userId.
=cut
sub canView {
my $self = shift;
my $userId = shift;
my $user;
if (defined $userId) {
$user = WebGUI::User->new($self->session, $userId);
}
else {
$user = $self->session->user;
$userId = $user->userId();
}
if ($userId eq $self->ownerUserId) {
return 1;
}
elsif ($user->isInGroup($self->groupIdView)) {
return 1;
}
return $self->canEdit($userId);
}
#-------------------------------------------------------------------
=head2 checkView ( )
Returns error messages if a user can't view due to publishing problems,
otherwise it sets the cookie and returns undef. This is sort of a hack
until we find something better.
If SSL in enabled in the config file, and the asset has encryptPage set, and
HTTPS is set and SSLPROXY is not set in the ENV, then this page is redirected
to SSL.
=cut
sub checkView {
my $self = shift;
return $self->session->privilege->noAccess() unless $self->canView;
my ($conf, $env, $var, $http) = $self->session->quick(qw(config env var http));
if ($conf->get("sslEnabled") && $self->get("encryptPage") && ! $env->sslRequest) {
# getUrl already changes url to https if 'encryptPage'
$http->setRedirect($self->getUrl);
$http->sendHeader;
return "chunked";
}
elsif ($var->isAdminOn && $self->get("state") =~ /^trash/) { # show em trash
my $queryFrag = "func=manageTrash";
if ($self->session->form->process('revision')) {
$queryFrag .= ";revision=".$self->session->form->process('revision');
}
$http->setRedirect($self->getUrl($queryFrag));
$http->sendHeader;
return "chunked";
}
elsif ($var->isAdminOn && $self->get("state") =~ /^clipboard/) { # show em clipboard
my $queryFrag = "func=manageClipboard";
if ($self->session->form->process('revision')) {
$queryFrag .= ";revision=".$self->session->form->process('revision');
}
$http->setRedirect($self->getUrl($queryFrag));
$http->sendHeader;
return "chunked";
}
elsif ($self->get("state") ne "published") { # tell em it doesn't exist anymore
$http->setStatus("410");
my $notFound = WebGUI::Asset->getNotFound($self->session);
$self->session->asset($notFound);
return $notFound->www_view;
}
$self->logView();
return undef;
}
#-------------------------------------------------------------------
=head2 cloneFromDb ( )
Fetches a new fresh clone of this object from the database. Often used after
calling commit on version tags.
Returns the new Asset object.
=cut
sub cloneFromDb {
my $self = shift;
return WebGUI::Asset->newById($self->session,
$self->getId,
$self->revisionDate
);
}
#-------------------------------------------------------------------
=head2 drawExtraHeadTags ( )
Draw the Extra Head Tags. Done with a customDrawMethod because the Template
will override this.
=cut
sub drawExtraHeadTags {
my ($self, $params) = @_;
return WebGUI::Form::codearea($self->session, {
name => $params->{name},
value => $self->get($params->{name}),
defaultValue => undef,
});
}
#-------------------------------------------------------------------
=head2 extraHeadTags ( value )
Returns extraHeadTags
=head3 value
If specified, stores it, but also updates extraHeadTagsPacked with the packed version.
=cut
#-------------------------------------------------------------------
=head2 fixUrl ( [value] )
Returns a URL, removing invalid characters and making it unique by
adding a digit to the end if necessary. URLs are not allowed to be
children of the extrasURL, the uploadsURL, or any defined passthruURL.
If not URL is passed, a URL will be constructed from the Asset's
parent and the menuTitle.
Assets have a maximum length of 250 characters. Any URL longer than
250 characters will be truncated to the initial 220 characters.
URLs will be passed through $session->url->urlize to make them WebGUI compliant.
That includes any languages specific constraints set up in the default language pack.
=head3 value
Any text string. Most likely will have been the Asset's name or title. If the string is not passed
in, then a url will be constructed from
=cut
sub fixUrl {
my $self = shift;
my $url = shift;
# build a URL from the parent
unless ($url) {
$url = $self->getParent->url;
$url =~ s/(.*)\..*/$1/;
$url .= '/'.$self->menuTitle;
}
# if we're inheriting the URL from our parent, set that appropriately
if ($self->inheritUrlFromParent) {
# if we're inheriting the URL from our parent, set that appropriately
my @parts = split(m{/}, $url);
# don't do anything unless we need to
my $inheritUrl = $self->getParent->get('url') . '/' . $parts[-1];
$url = $inheritUrl if $url ne $inheritUrl;
}
$url = $self->session->url->urlize($url);
# fix urls used by uploads and extras
# and those beginning with http
my @badUrls = (
$self->session->config->get("extrasURL"),
$self->session->config->get("uploadsURL"),
);
foreach my $badUrl (@badUrls) {
$badUrl =~ s{ / $ }{}x; # Remove trailing slashes from the end of the URL
if ($badUrl =~ /^http/) {
$badUrl =~ s{ ^ http .* / } {}x; #Remove everything but the final path fragment from the badUrl
}
else {
$badUrl =~ s{ ^ / }{}x; #Remove leading slashes from bare URLs
}
if ($url =~ /^$badUrl/) {
$url = "_".$url;
}
}
# urls can't be longer than 250 characters
if (length($url) > 250) {
$url = substr($url,0,220);
}
# remove multiple extensions from the url if there are some
$url =~ s{
(\.\w+)* # Strip off any number of extensions
(?=/) # Followed by a slash
}{}xg; # And delete all of them in the string
# add automatic extension if we're supposed to
if ($self->session->setting->get("urlExtension") ne "" #don't add an extension if one isn't set
&& !($url =~ /\./) # don't add an extension of the url already contains a dot
&& $url ne lc($self->getId) # but don't assign it the original time
) {
$url .= ".".$self->session->setting->get("urlExtension");
}
# make sure the url isn't empty after all that filtering
if ($url eq "") {
$url = $self->getId;
}
# check to see if the url already exists or not, and increment it if it does
if ($self->urlExists($self->session, $url, {assetId=>$self->getId})) {
my @parts = split(/\./,$url);
if ($parts[0] =~ /(.*?)(\d+$)/) {
$parts[0] = $1.($2+1);
}
else {
$parts[0] .= "2";
}
$url = join(".",@parts);
$url = $self->fixUrl($url);
}
return $url;
}
#-------------------------------------------------------------------
=head2 getAdminConsole ( )
Returns a reference to a WebGUI::AdminConsole object.
=cut
sub getAdminConsole {
my $self = shift;
unless (exists $self->{_adminConsole}) {
$self->{_adminConsole} = WebGUI::AdminConsole->new($self->session,"assets");
}
$self->{_adminConsole}->setIcon($self->getIcon);
return $self->{_adminConsole};
}
#-------------------------------------------------------------------
=head2 getClassById ( $session, $assetId )
Class method that looks up a className for an object in the database, using it's assetId.
If a class cannot be found for the requested assetId, then it throws a WebGUI::Error::InvalidParam
exception.
=head3 $session
A WebGUI::Session object.
=head3 $assetId
The assetId of the object to lookup in the database.
=cut
sub getClassById {
my $class = shift;
my $session = shift;
my $assetId = shift;
# Cache the className lookup
my $assetClass = $session->stow->get("assetClass");
my $className = $assetClass->{$assetId};
return $className if $className;
$className = $session->db->quickScalar(
"select className from asset where assetId=?",
[$assetId]
);
$assetClass->{ $assetId } = $className;
$session->stow->set("assetClass", $assetClass);
return $className if $className;
WebGUI::Error::InvalidParam->throw(error => "Couldn't lookup className", param => $assetId);
}
#-------------------------------------------------------------------
=head2 getWwwCacheKey ( )
Returns a cache object specific to this asset, and whether or not the request is in SSL mode.
=cut
sub getWwwCacheKey {
my $self = shift;
my $session = $self->session;
my $method = shift;
my $cacheKey = join '_', @_, $self->getId;
if ($session->env->sslRequest) {
$cacheKey .= '_ssl';
}
return $cacheKey;
}
#-------------------------------------------------------------------
=head2 getContainer ( )
Returns a reference to the container asset. If this asset is a container it returns a reference to itself. If this asset is not attached to a container it returns its parent.
=cut
sub getContainer {
my $self = shift;
if ($self->session->config->get("assets/".$self->get("className")."/isContainer")) {
return $self;
}
else {
return $self->getParent;
}
}
#-------------------------------------------------------------------
=head2 getDefault ( session )
Constructor. Returns the default object, which is also known by some as the "Home Page". The default object is set in the settings.
=head3 session
A reference to the current session.
=cut
sub getDefault {
my $class = shift;
my $session = shift;
return $class->newById($session, $session->setting->get("defaultPage"));
}
#-------------------------------------------------------------------
=head2 getEditForm ()
Creates and returns a tabform to edit parameters of an Asset. See L for
adding additional tabs.
=cut
sub getEditForm {
my $self = shift;
my $session = $self->session;
my $i18n = WebGUI::International->new($session, "Asset");
my $ago = $i18n->get("ago");
my $tabform = WebGUI::TabForm->new($session,undef,undef,$self->getUrl());
my $overrides = $session->config->get("assets/".$self->get("className"));
# Set the appropriate URL
# If we're adding a new asset, don't set anything
if ( $session->form->get( "func" ) ne "add" ) {
$tabform->formHeader( { action => $self->getUrl, method => "POST" } );
}
if ($session->config->get("enableSaveAndCommit")) {
$tabform->submitAppend(WebGUI::Form::submit($session, {
name => "saveAndCommit",
value => $i18n->get("save and commit"),
}));
}
$tabform->submitAppend(
WebGUI::Form::submit ( $session, {
name => "saveAndReturn",
value => $i18n->get( "apply" ),
} )
);
$tabform->hidden({
name=>"func",
value=>"editSave"
});
my $assetId;
my $class;
if ($self->getId eq "new") {
$assetId = "new";
$class = $session->form->process("class","className");
}
else {
# revision history
$assetId = $self->getId;
$class = $self->get('className');
my $ac = $self->getAdminConsole;
$ac->addSubmenuItem($self->getUrl("func=manageRevisions"),$i18n->get("revisions").":");
my $rs = $session->db->read("select revisionDate from assetData where assetId=? order by revisionDate desc limit 5", [$assetId]);
while (my ($version) = $rs->array) {
my ($interval, $units) = $session->datetime->secondsToInterval(time() - $version);
$ac->addSubmenuItem($self->getUrl("func=edit;revision=".$version), $interval." ".$units." ".$ago);
}
}
if (my $proceed = $session->form->process("proceed")) {
$tabform->hidden({
name=>"proceed",
value=>$proceed,
});
if (my $returnUrl = $session->form->process('returnUrl')) {
$tabform->hidden({
name=>"returnUrl",
value=>$returnUrl,
});
}
}
# create tabs
tie my %tabs, 'Tie::IxHash';
foreach my $tabspec ($self->getEditTabs) {
$tabs{$tabspec->[0]} = {
label => $tabspec->[1],
uiLevel => $tabspec->[2],
};
}
foreach my $tab (keys %{$overrides->{tabs}}) {
foreach my $key (keys %{$overrides->{tabs}{$tab}}) {
$tabs{$tab}{$key} = $overrides->{tabs}{$tab}{$key};
}
}
foreach my $tab (keys %tabs) {
$tabform->addTab($tab, $tabs{$tab}{label}, $tabs{$tab}{uiLevel});
}
# process errors
my $errors = $session->stow->get('editFormErrors');
if ($errors) {
$tabform->getTab("properties")->readOnly(
-value=>"
Some error(s) occurred:
".join('
', @$errors).'
',
);
}
# build the definition to the generate form
my @properties = (
assetId => {
fieldType => "guid",
label => ["asset id",'Asset'],
value => $assetId,
hoverHelp => ['asset id description','Asset'],
uiLevel => 9,
tab => "meta",
},
class => {
fieldType => "className",
label => ["class name",'WebGUI'],
value => $class,
uiLevel => 9,
tab => "meta",
},
keywords => {
label => ['keywords','Asset'],
hoverHelp => ['keywords help','Asset'],
value => $self->get('keywords'),
fieldType => 'keywords',
tab => 'meta',
},
);
foreach my $property ($self->getProperties) {
push @properties, $property => $self->getProperty($property);
}
if ($session->setting->get("metaDataEnabled")) {
my $meta = $self->getMetaDataFields();
foreach my $field (keys %$meta) {
my $fieldType = $meta->{$field}{fieldType} || "text";
my $options = $meta->{$field}{possibleValues};
# Add a "Select..." option on top of a select list to prevent from
# saving the value on top of the list when no choice is made.
if("\l$fieldType" eq "selectBox") {
$options = "|" . $i18n->get("Select") . "\n" . $options;
}
push @properties, "metadata_".$meta->{$field}{fieldId} => {
tab => "meta",
label => $meta->{$field}{fieldName},
uiLevel => 5,
value => $meta->{$field}{value},
extras => qq/title="$meta->{$field}{description}"/,
options => $options,
defaultValue => $meta->{$field}{defaultValue},
fieldType => $fieldType
};
}
# add metadata management
if ($session->user->isAdmin) {
push @properties, '_metadatamanagement' => {
tab => "meta",
fieldType => "readOnly",
value => '
',
hoverHelp => $i18n->get('Add new field description'),
};
}
}
# generate the form
for (my $i = 0; $i < @properties; $i += 2) {
my $fieldName = $properties[$i];
my %fieldHash = %{$properties[$i+1]};
my %params = (name => $fieldName, value => $self->get($fieldName));
# apply config file changes
foreach my $key (keys %{$overrides->{fields}{$fieldName}}) {
$fieldHash{$key} = $overrides->{fields}{$fieldName}{$key};
}
# Kludge.
if (isIn($fieldHash{fieldType}, 'selectBox', 'workflow') and ref $params{value} ne 'ARRAY') {
$params{value} = [$params{value}];
}
%params = (%fieldHash, %params);
delete $params{tab};
delete $params{tableName};
# if there isnt a tab specified lets define one
my $tab = $fieldHash{tab} || "properties";
#draw the field
$tabform->getTab($tab)->dynamicField(%params);
}
# send back the object
return $tabform;
}
sub setupFormField {
my ($self, $tabform, $fieldName, $extraFields, $overrides) = @_;
my %params = %{$extraFields->{$fieldName}};
my $tab = delete $params{tab};
if (exists $overrides->{fields}{$fieldName}) {
my %overrideParams = %{$overrides->{fields}{$fieldName}};
my $overrideTab = delete $overrideParams{tab};
$tab = $overrideTab if defined $overrideTab;
foreach my $key (keys %overrideParams) {
$params{"-$key"} = $overrideParams{$key};
}
}
$tab ||= 'properties';
return $tabform->getTab($tab)->dynamicField(%params);
}
#-------------------------------------------------------------------
=head2 getEditTabs ()
Returns a list of arrayrefs, one per extra tab to add to the edit
form. The default is no extra tabs. Override this in a subclass to
add extra tabs.
Each array ref will have 3 fields:
=over 4
=item tabName
This is the name of the tab that you will use in the definition subroutine to
add fields to the new tab.
=item label
This should be an internationalized label that will be displayed on the tab.
=item uiLevel
This is the UI level for the tab.
=back
Please see the example below for adding 1 tab.
sub getEditTabs {
my $self = shift;
my $i18n = WebGUI::International->new($self->session,"myNamespace");
return ($self->SUPER::getEditTabs, ['myTab', $i18n->get('myTabName'), 9]);
}
=cut
sub getEditTabs {
my $self = shift;
my $i18n = WebGUI::International->new($self->session, "Asset");
return (["properties", $i18n->get("properties"), 1],
["display", $i18n->get(105), 5],
["security", $i18n->get(107), 6],
["meta", $i18n->get("Metadata"), 3]);
}
#-------------------------------------------------------------------
=head2 getExtraHeadTags ( )
Returns the extraHeadTags stored in the asset. Called in $self->session->style->generateAdditionalHeadTags if this asset is the current session asset. Also called in WebGUI::Layout::view for its child assets. Overriden in Shortcut.pm.
=cut
sub getExtraHeadTags {
my $self = shift;
return $self->usePackedHeadTags
? $self->extraHeadTagsPacked
: $self->extraHeadTags
;
}
#----------------------------------------------------------------------------
=head2 getHelpers ( )
Get the AssetHelpers for this asset.
=cut
sub getHelpers {
my ( $self ) = @_;
my $default = [
{
class => 'WebGUI::AssetHelper::EditBranch',
label => 'Edit Branch',
},
{
url => $self->getUrl( 'func=edit' ),
label => 'Edit',
},
{
url => $self->getUrl( 'func=view' ),
label => 'View',
},
];
return $default;
}
#-------------------------------------------------------------------
=head2 getIcon ( [small] )
Returns the icon located under extras/adminConsole/assets.gif
=head3 small
If this evaluates to True, then the smaller extras/adminConsole/small/assets.gif is returned.
=cut
sub getIcon {
my ($self, $small) = @_;
my $icon = $self->icon;
return $self->session->url->extras('assets/small/'.$icon) if ($small);
return $self->session->url->extras('assets/'.$icon);
}
#-------------------------------------------------------------------
=head2 getId ( )
Returns the assetId of an Asset.
=cut
sub getId {
my $self = shift;
return $self->assetId;
}
#-------------------------------------------------------------------
=head2 getImportNode ( session )
Constructor. Returns the import node asset object. This is where developers will templates, files, etc to the asset tree that have no other obvious attachment point.
=head3 session
A reference to the current session.
=cut
sub getImportNode {
my $class = shift;
my $session = shift;
return WebGUI::Asset->newById($session, "PBasset000000000000002");
}
#-------------------------------------------------------------------
=head2 getIsa ( $session, [ $offset ] )
A class method to return an iterator for getting all committed Assets by
class (and all sub-classes) as Asset objects, one at a time. When the end
of the assets is reached, then the iterator will close the database handle
that it uses and return undef.
Assets are processed in order by revisionDate. If the iterator cannot
instanciate an asset, it will not return undef. Instead, it will throw
an exception. This allows the error condition to be distinguished from the
end of the set of assets.
It should be used like this:
my $productIterator = WebGUI::Asset::Product->getIsa($session);
ASSET: while (1) {
my $product = eval { $productIterator->() };
if (my $e = Exception::Class->caught()) {
$session->log->error($@);
next ASSET;
}
last ASSET unless $product;
##Do something useful with $product
}
In upgrade scripts, the eval and exception handling are best left off, because it is a good time
to make the user aware that they have broken assets in their database.
=head3 $session
A reference to a WebGUI::Session object.
=head3 $offset
An offset, from the beginning of the results returned from the query, to really begin
returning results. This allows very large sets of results to be handled in chunks.
=head3 $options
A hashref of options to change how getIsa works.
=head4 returnAll
If set to true, then all assets will be returned, regardless of status and state.
=cut
sub getIsa {
my $class = shift;
my $session = shift;
my $offset = shift;
my $options = shift;
my $tableName = $class->tableName;
#Strategy, generate the correct set of assetIds
my $sql = "select assetId from assetData as ad ";
if ($tableName ne 'assetData') {
$sql .= "join `$tableName` using (assetId, revisionDate) ";
}
$sql .= 'WHERE ';
if (! $options->{returnAll}) {
$sql .= q{(status='approved' OR status='archived') AND };
}
$sql .= q{revisionDate = (SELECT MAX(revisionDate) FROM assetData AS a WHERE a.assetId = ad.assetId) order by revisionDate };
if (defined $offset) {
$sql .= 'LIMIT '. $offset . ',1234567890 ';
}
my $sth = $session->db->read($sql);
return sub {
my ($assetId, $revisionDate) = $sth->array;
if (!$assetId) {
$sth->finish;
return undef;
}
my $asset = eval { WebGUI::Asset->newPending($session, $assetId); };
if (!$asset) {
WebGUI::Error::ObjectNotFound->throw(id => $assetId);
}
return $asset;
};
}
#-------------------------------------------------------------------
=head2 getManagerUrl ( )
Returns the URL for the asset manager.
=cut
sub getManagerUrl {
my $self = shift;
return $self->getUrl( 'op=assetManager' );
}
#-------------------------------------------------------------------
=head2 getMedia ( session )
Constructor. Returns the media folder.
=head3 session
A reference to the current session.
=cut
sub getMedia {
my $class = shift;
my $session = shift;
return WebGUI::Asset->newById($session, "PBasset000000000000003");
}
#-------------------------------------------------------------------
=head2 getMenuTitle ( )
Returns the menu title of this asset. If it's not specified or it's "Untitled" then the asset's name will be returned instead.
=cut
sub getMenuTitle {
my $self = shift;
my $menuTitle = $self->menuTitle;
if ( $menuTitle eq '' || lc $menuTitle eq 'untitled' ) {
return $self->getName;
}
return $menuTitle;
}
#-------------------------------------------------------------------
=head2 getName ( )
Returns the human readable name of the asset.
=cut
sub getName {
my $self = shift;
return WebGUI::International->new($self->session, 'Asset')->get(@{ $self->assetName });
}
#-------------------------------------------------------------------
=head2 getNotFound ( session )
Constructor. Returns the not found object. The not found object is set in the settings.
=head3 session
A reference to the current session.
=cut
sub getNotFound {
my $class = shift;
my $session = shift;
return WebGUI::Asset->newById($session, $session->setting->get("notFoundPage"));
}
#-------------------------------------------------------------------
=head2 getPrototypeList ( )
Returns an array of all assets that the user can view and edit that are prototypes.
=cut
sub getPrototypeList {
my $self = shift;
my $session = $self->session;
my $db = $session->db;
my @prototypeIds = $db->buildArray("select distinct assetId from assetData where isPrototype=1");
my $userUiLevel = $session->user->profileField('uiLevel');
my @assets;
ID: foreach my $id (@prototypeIds) {
my $asset = WebGUI::Asset->newById($session, $id);
next ID unless defined $asset;
next ID unless $asset->get('isPrototype');
next ID unless ($asset->get('status') eq 'approved' || $asset->get('tagId') eq $session->scratch->get("versionTag"));
push @assets, $asset;
}
return \@assets;
}
#-------------------------------------------------------------------
=head2 getRoot ( session )
Constructor. Returns the root asset object.
=head3 session
A reference to the current session.
=cut
sub getRoot {
my $class = shift;
my $session = shift;
return WebGUI::Asset->newById($session, "PBasset000000000000001");
}
#-------------------------------------------------------------------
=head2 getSearchUrl ( )
Returns the URL for the search screen of the asset manager.
=cut
sub getSearchUrl {
my $self = shift;
return $self->getUrl( 'op=assetManager;method=search' );
}
#-------------------------------------------------------------------
=head2 getSeparator
Returns a very unique string that can be used for splitting head and body apart
from the style template. Made into a method in case it ever has to be changed
again.
=cut
sub getSeparator {
my $self = shift;
my $padCharacter = shift || '~';
my $pad = $padCharacter x 3;
return $pad.$self->getId.$pad
}
#-------------------------------------------------------------------
=head2 getTempspace ( session )
Constructor. Returns the tempspace folder.
=head3 session
A reference to the current session.
=cut
sub getTempspace {
my $class = shift;
my $session = shift;
return WebGUI::Asset->newById($session, "tempspace0000000000000");
}
#-------------------------------------------------------------------
=head2 getTitle ( )
Returns the title of this asset. If it's not specified or it's "Untitled" then the asset's name will be returned instead.
=cut
sub getTitle {
my $self = shift;
my $title = $self->title;
if ($title eq "" || lc($title) eq "untitled") {
return $self->getName;
}
return $title;
}
#-------------------------------------------------------------------
=head2 getToolbar ( )
Returns a toolbar with a set of icons that hyperlink to functions that delete, edit, promote, demote, cut, and copy.
=cut
sub getToolbar {
my $self = shift;
return undef unless $self->canEdit && $self->session->var->isAdminOn;
return $self->{_toolbar}
if (exists $self->{_toolbar});
my $userUiLevel = $self->session->user->profileField("uiLevel");
my $uiLevels = $self->session->config->get("assetToolbarUiLevel");
my $i18n = WebGUI::International->new($self->session, "Asset");
my $toolbar = "";
my $commit;
if ($self->canEditIfLocked) {
$toolbar .= $self->session->icon->delete('func=delete',$self->get("url"),$i18n->get(43))
if ($userUiLevel >= $uiLevels->{"delete"});
$toolbar .= $self->session->icon->edit('func=edit',$self->get("url"))
if ($userUiLevel >= $uiLevels->{"edit"});
}
else {
$toolbar .= $self->session->icon->locked('func=manageRevisions',$self->get("url"))
if ($userUiLevel >= $uiLevels->{"revisions"});
}
$toolbar .= $self->session->icon->cut('func=cut',$self->get("url"))
if ($userUiLevel >= $uiLevels->{"cut"});
if ($userUiLevel >= $uiLevels->{"copy"}) {
$toolbar .= $self->session->icon->copy('func=copy',$self->get("url"));
# if this asset has children, create a more full-featured menu for copying
if ($self->getChildCount) {
$toolbar
.= '
';
$self->{_toolbar} = $output;
return $output;
}
#-------------------------------------------------------------------
=head2 getToolbarState ( )
Returns 0 if the state is normal, and 1 if the toolbar state has been toggled. See toggleToolbar() for details.
=cut
sub getToolbarState {
my $self = shift;
return $self->{_toolbarState};
}
#-------------------------------------------------------------------
=head2 getUiLevel ( )
Returns the UI Level specified in the asset definition or from the config file if it's overridden. And if neither of those is specified, then it returns 1.
=cut
sub getUiLevel {
my $self = shift;
my $uiLevel = shift;
my $className = $self->get("className");
return $uiLevel # passed in
|| $self->session->config->get("assets/".$className."/uiLevel") # from config
|| $self->uiLevel # from definition
|| 1; # if all else fails
}
#-------------------------------------------------------------------
=head2 getUrl ( params )
Returns a URL of Asset based upon WebGUI's gateway script.
=head3 params
Name value pairs to add to the URL in the form of:
name1=value1;name2=value2;name3=value3
=cut
sub getUrl {
my $self = shift;
my $params = shift;
my $url = $self->url;
$url = $self->session->url->gateway($url,$params);
if ($self->encryptPage) {
$url = $self->session->url->getSiteURL().$url;
$url =~ s/http:/https:/;
}
return $url;
}
#-------------------------------------------------------------------
=head2 getContentLastModified
Returns the overall modification time of the object and its content in Unix
epoch format, for the purpose of the Last-Modified HTTP header. Override this
for subclasses that contain content that is not solely lastModified property,
which gets updated every time update() is called.
=cut
sub getContentLastModified {
my $self = shift;
return $self->get("lastModified");
}
#-------------------------------------------------------------------
=head2 indexContent ( )
Returns an indexer object for this asset. When this method is called the asset's base content gets stored in the index. This method is often overloaded so that a particular asset can insert additional content other than the basic properties. Such uses include indexing attached files or collateral data.
=cut
sub indexContent {
my $self = shift;
my $indexer = WebGUI::Search::Index->create($self);
$indexer->setIsPublic(0) if ($self->getId eq "PBasset000000000000001");
return $indexer;
}
#-------------------------------------------------------------------
=head2 loadModule ( $className )
Loads an asset module if it's not already in memory. This is a class method. Returns
undef on failure to load, otherwise returns the classname. Will only load classes
in the WebGUI::Asset namespace.
Throws a WebGUI::Invalid::Param error if a non-WebGUI::Asset class is requested to be
loaded. If there are compilation problems, it will throw a WebGUI::Error::Compile
exception.
=cut
sub loadModule {
my ($class, $className) = @_;
if ($className !~ /^WebGUI::Asset(?:::\w+)*$/ ) {
WebGUI::Error::InvalidParam->throw(param => $className, error => "Not a WebGUI::Asset class",);
}
(my $module = $className . '.pm') =~ s{::}{/}g;
if (eval { require $module; 1 }) {
return $className;
}
WebGUI::Error::Compile->throw(class => $className, cause => $@);
return undef;
}
#-------------------------------------------------------------------
=head2 logView ( )
Logs the view of this asset to the passive profiling mechanism. If the asset is a Layout, it will also index
all of the children (not descendents) of the Layout.
=cut
sub logView {
my $self = shift;
if ($self->session->setting->get("passiveProfilingEnabled")) {
WebGUI::PassiveProfiling::add($self->session,$self->getId);
WebGUI::PassiveProfiling::addPage($self->session,$self->getId) if ($self->get("className") eq "WebGUI::Asset::Wobject::Layout");
}
return undef;
}
#-------------------------------------------------------------------
=head2 title ( [value] )
Returns the title of the asset.
=head3 value
If specified this value will be used to set the title after it goes through some validation checking.
=cut
#-------------------------------------------------------------------
=head2 menuTitle ( [value] )
Returns the menuTitle of the asset, which is used in navigations.
=head3 value
If specified this value will be used to set the title after it goes through some validation checking.
=cut
#-------------------------------------------------------------------
=head2 new ( propertyHashRef )
Asset Constructor. This does not create an asset in the database, or look up
properties in the database, but creates a WebGUI::Asset object.
=head3 propertyHashRef
A hash reference of properties to assign to the object.
=cut
=head2 new ( session, assetId [,revisionDate ] )
Instanciator. This does not create an asset in the database, but looks up the object's
properties in the database and returns an object with the correct WebGUI::Asset subclass.
=head3 session
A reference to the current session.
=head3 assetId
The assetId of the asset you're creating an object reference for. Must not be blank.
=head3 revisionDate
An epoch date that represents a specific version of an asset. By default the most recent version will be used. If
no revision date is available it will return undef.
=cut
#-------------------------------------------------------------------
=head2 newById ( session, assetId [ , revisionDate ] )
Instances an existing Asset, by looking up the className of the asset specified by the assetId, and then calling new.
Returns undef if it can't find the classname.
=head3 session
A reference to the current session.
=head3 assetId
Must be a valid assetId.
Throws a WebGUI::Error::InvalidParam exception if the assetId is not passed.
=head3 revisionDate
An optional, specific revision date for the asset to retrieve. If not specified, the most recent one will be used.
=cut
sub newById {
my $requestedClass = shift;
my $session = shift;
my $assetId = shift;
if (!$assetId) {
WebGUI::Error::InvalidParam->throw(error => 'newById must get an assetId');
}
my $revisionDate = shift;
my $className = WebGUI::Asset->getClassById($session, $assetId);
my $class = WebGUI::Asset->loadModule($className);
return $class->new($session, $assetId, $revisionDate);
}
#-------------------------------------------------------------------
=head2 newByPropertyHashRef ( session, properties )
Constructor. This is a class method. It creates a standalone asset with no parent, with a
varying class, determined by the className entry in the properties hash ref.
The object created is not persisted to the database.
=head3 session
A reference to the current session.
=head3 properties
A hash reference of Asset properties.
=cut
sub newByPropertyHashRef {
my $class = shift;
my $session = shift;
my $properties = shift || {};
$properties->{className} //= $class;
$properties->{session} = $session;
my $className = $class->loadModule($properties->{className});
return undef unless (defined $className);
my $object = $className->new($properties);
return $object;
}
#-------------------------------------------------------------------
=head2 newByUrl ( session, [url, revisionDate] )
Instances an existing Asset, by looking up the classname of the asset specified by the url, and then calling new.
Returns undef if it can't find a classname with that url. If no URL is specified, and the requested url cannot
be found, it returns the default asset.
=head3 session
A reference to the current session.
=head3 url
Optional string representing a URL.
=head3 revisionDate
A specific revision to instanciate. By default we instanciate the newest published revision.
=cut
sub newByUrl {
my $class = shift;
my $session = shift;
my $url = shift || $session->url->getRequestedUrl;
my $revisionDate = shift;
$url = lc($url);
$url =~ s/\/$//;
$url =~ s/^\///;
$url =~ tr/'"//d;
if ($url ne "") {
my ($id) = $session->db->quickArray("select assetId from assetData where url = ? limit 1", [ $url ]);
if (!$id) {
WebGUI::Error::ObjectNotFound->throw(error => "The URL was requested, but does not exist in your asset tree.", id => $url);
}
return WebGUI::Asset->newById($session, $id, $revisionDate);
}
return WebGUI::Asset->getDefault($session);
}
#-------------------------------------------------------------------
=head2 newPending ( session, assetId )
Instances an existing Asset by assetId, ignoring the status and always selecting the most recent revision.
=head3 session
A reference to the current session.
=head3 assetId
The asset's id. If an assetId is not passed, throws a WebGUI::Error::InvalidParam exception. If
a revision cannot be found for the requested assetId, then it throws a WebGUI::Error::InvalidParam
exception.
=cut
sub newPending {
my $class = shift;
my $session = shift;
my $assetId = shift;
if (!$assetId) {
WebGUI::Error::InvalidParam->throw(error => 'newPending must get an assetId');
}
my $revisionDate = $session->db->quickScalar("SELECT revisionDate FROM assetData WHERE assetId = ? ORDER BY revisionDate DESC LIMIT 1", [ $assetId ]);
if ($revisionDate ne "") {
return WebGUI::Asset->newById($session, $assetId, $revisionDate);
}
else {
WebGUI::Error::InvalidParam->throw(error => "Couldn't lookup revisionDate", param => $assetId);
}
}
#-------------------------------------------------------------------
=head2 outputWidgetMarkup ( width, height, templateId, [styleTemplateId] )
Output the markup required for the widget view. Includes markup to handle the
widget macro in the iframe holding the widgetized asset. This does the following:
=over 4
=item *
retrieves the content for this asset using its L method
=item *
processes macros in that content
=item *
serializes the processed content in JSON
=item *
writes the JSON to a storage location
=item *
refers the user to download this JSON
=item *
references the appropriate JS files for the templating engine and the widget macro
=item *
invokes the templating engine on this JSON
=back
=head3 width
The width of the iframe. Required for making widget-in-widget function properly.
=head3 height
The height of the iframe. Required for making widget-in-widget function properly.
=head3 templateId
The templateId for this widgetized asset to use. Required for making
widget-in-widget function properly.
=cut
=head3 styleTemplateId
The style templateId for this widgetized asset to use. Not required for making
widget-in-widget function properly.
=cut
sub outputWidgetMarkup {
# get our parameters.
my $self = shift;
my $width = shift;
my $height = shift;
my $templateId = shift;
my $styleTemplateId = shift;
# construct / retrieve the values we'll use later.
my $session = $self->session;
my $assetId = $self->getId;
my $hexId = $session->id->toHex($assetId);
my $conf = $session->config;
my $extras = $conf->get('extrasURL');
# the widgetized version of content that has the widget macro in it is
# executing in an iframe. this iframe doesn't have a style object.
# therefore, the macro won't be able to output the stylesheet and JS
# information it needs to do its work. because of this, we need to output
# that content manually. construct the filesystem paths for those files.
my $containerCss = $extras . '/yui/build/container/assets/container.css';
my $containerJs = $extras . '/yui/build/container/container-min.js';
my $yahooDomJs = $extras . '/yui/build/yahoo-dom-event/yahoo-dom-event.js';
my $wgWidgetJs = $extras . '/wgwidget.js';
my $ttJs = $extras . '/tt.js';
# the templating engine requires its source data to be in json format.
# write this out to disk and then serve the URL to the user. in this case,
# we'll be serializing the content of the asset which is being widgetized.
my $storage = WebGUI::Storage->get($session, $assetId);
my $content = $self->view;
if($styleTemplateId ne '' && $styleTemplateId ne 'none'){
$content = $self->session->style->process($content,$styleTemplateId);
}
WebGUI::Macro::process($session, \$content);
my ($headTags, $body) = WebGUI::HTML::splitHeadBody($content);
$body = $content;
my $jsonContent = to_json( { "asset$hexId" => { content => $body } } );
$storage->addFileFromScalar("$assetId.js", "data = $jsonContent");
my $jsonUrl = $storage->getUrl("$assetId.js");
# WebGUI.widgetBox.initButton() needs the full URL of the asset being
# widgetized, and also the full URL of the JS file that does most of the
# work.
my $fullUrl = "http://" . $conf->get("sitename")->[0] . $self->getUrl;
my $wgWidgetPath = 'http://' . $conf->get('sitename')->[0] . $extras . '/wgwidget.js';
# finally, given all of the above, construct our output. WebGUI outputs
# fully valid XHTML 1.0 Strict, and there's no reason this should be any
# different.
my $output = <