diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index bd05b26ce..2071fcd67 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -5,6 +5,10 @@ macro can then format the epoch date. - fixed: actove admin console tab isn't highlighted - Added WebGUI::Crud API as a base for all database backed objects. + - Added Admin Console plugability. + - Reconfigured Asset management in config file. + - Rebuilt AdminBar. Now renders faster, and has categories in the new content + menu. - no longer preloads files that start with . - rfe: let package import inherit permissions - added fieldsets around form controls with multiple elements diff --git a/docs/gotcha.txt b/docs/gotcha.txt index 1eed21600..963ce2f0e 100644 --- a/docs/gotcha.txt +++ b/docs/gotcha.txt @@ -13,6 +13,10 @@ save you many hours of grief. * You must be fully upgraded to 7.5.24 before upgrading to 7.6.0 + * You can no longer template the AdminBar macro. Any custom template + id that you pass it will be ignored, and the original template will + be removed from your site. + 7.5.21 -------------------------------------------------------------------- diff --git a/docs/upgrades/upgrade_7.5.24-7.6.0.pl b/docs/upgrades/upgrade_7.5.24-7.6.0.pl index bc501ca80..660909c3a 100644 --- a/docs/upgrades/upgrade_7.5.24-7.6.0.pl +++ b/docs/upgrades/upgrade_7.5.24-7.6.0.pl @@ -39,9 +39,190 @@ badgePriceDates ($session); addIsDefaultTemplates( $session ); addAdHocMailGroups( $session ); makeAdminConsolePluggable( $session ); +migrateAssetsToNewConfigFormat($session); +deleteAdminBarTemplates($session); finish($session); # this line required + +#---------------------------------------------------------------------------- +sub deleteAdminBarTemplates { + my $session = shift; + print "\tDeleting AdminBar templates... " unless $quiet; + foreach my $id (qw(PBtmpl0000000000000090 Ov2ssJHwp_1eEWKlDyUKmg)) { + my $asset = WebGUI::Asset->newByDynamicClass($session, $id); + if (defined $asset) { + $asset->trash; + } + } + print "DONE!\n" unless $quiet; +} + +#---------------------------------------------------------------------------- +sub migrateAssetsToNewConfigFormat { + my $session = shift; + print "\tRestructuring asset configuration... " unless $quiet; + my $config = $session->config; + + # devs doing multiple upgrades + # the list has already been updated by a previous run + my $assetList = $config->get("assets"); + unless (ref $assetList eq "ARRAY") { + print "ERROR: Looks like you've already run this upgrade.\n"; + return undef; + } + + # add categories + $config->set('assetCategories', { + basic => { + title => "^International(basic,Macro_AdminBar);", + uiLevel => 1, + }, + intranet => { + title => "^International(intranet,Macro_AdminBar);", + uiLevel => 5, + }, + shop => { + title => "^International(shop,Shop);", + uiLevel => 5, + }, + utilities => { + title => "^International(utilities,Macro_AdminBar);", + uiLevel => 9, + }, + community => { + title => "^International(community,Macro_AdminBar);", + uiLevel => 5, + }, + }); + + # deal with the old asset list + my $assetContainers = $config->get("assetContainers"); + $assetContainers = [] unless (ref $assetContainers eq "ARRAY"); + my $utilityAssets = $config->get("utilityAssets"); + $utilityAssets = [] unless (ref $utilityAssets eq "ARRAY"); + my @oldAssetList = (@$assetList, @$utilityAssets, @$assetContainers); + my %assets = ( + 'WebGUI::Asset::Wobject::Collaboration::Newsletter' => { + category => "community", + } + ); + foreach my $class (@oldAssetList) { + my %properties; + if (isIn($class, qw( + WebGUI::Asset::Wobject::Article + WebGUI::Asset::Wobject::Layout + WebGUI::Asset::Wobject::Folder + WebGUI::Asset::Wobject::Calendar + WebGUI::Asset::Wobject::Poll + WebGUI::Asset::Wobject::Search + WebGUI::Asset::FilePile + WebGUI::Asset::Snippet + WebGUI::Asset::Wobject::DataForm + ))) { + $properties{category} = 'basic'; + } + elsif (isIn($class, qw( + WebGUI::Asset::Wobject::Collaboration::Newsletter + WebGUI::Asset::Wobject::WikiMaster + WebGUI::Asset::Wobject::Collaboration + WebGUI::Asset::Wobject::Survey + WebGUI::Asset::Wobject::Gallery + WebGUI::Asset::Wobject::MessageBoard + WebGUI::Asset::Wobject::Matrix + ))) { + $properties{category} = 'community'; + } + elsif (isIn($class, qw( + WebGUI::Asset::Wobject::StockData + WebGUI::Asset::Wobject::Dashboard + WebGUI::Asset::Wobject::InOutBoard + WebGUI::Asset::Wobject::MultiSearch + WebGUI::Asset::Wobject::ProjectManager + WebGUI::Asset::Wobject::TimeTracking + WebGUI::Asset::Wobject::UserList + WebGUI::Asset::Wobject::WeatherData + WebGUI::Asset::Wobject::Thingy + ))) { + $properties{category} = 'intranet'; + } + elsif (isIn($class, qw( + WebGUI::Asset::Wobject::Bazaar + WebGUI::Asset::Wobject::EventManagementSystem + WebGUI::Asset::Wobject::Shelf + WebGUI::Asset::Sku::Product + WebGUI::Asset::Sku::FlatDiscount + WebGUI::Asset::Sku::Donation + WebGUI::Asset::Sku::Subscription + ))) { + $properties{category} = 'shop'; + } + elsif (isIn($class, qw( + WebGUI::Asset::Wobject::WSClient + WebGUI::Asset::Wobject::SQLReport + WebGUI::Asset::Wobject::SyndicatedContent + WebGUI::Asset::Redirect + WebGUI::Asset::Template + WebGUI::Asset::Wobject::Navigation + WebGUI::Asset::File + WebGUI::Asset::Wobject::HttpProxy + WebGUI::Asset::File::Image + WebGUI::Asset::File::ZipArchive + WebGUI::Asset::RichEdit + ))) { + $properties{category} = 'utilities'; + } + else { + # other assets listed but not in the core + $properties{category} = 'utilities'; + } + $assets{$class} = \%properties; + } + + # deal with containers + foreach my $class (@$assetContainers) { + $assets{$class}{isContainer} = 1; + } + + # deal with custom add privileges + my $addGroups = $config->get("assetAddPrivilege"); + if (ref $addGroups eq "HASH") { + foreach my $class (keys %{$addGroups}) { + $assets{$class}{addGroup} = $addGroups->{$class}; + } + } + + # deal with custom ui levels + my $uiLevels = $config->get("assetUiLevel"); + if (ref $uiLevels eq "HASH") { + foreach my $class (keys %{$addGroups}) { + $assets{$class}{uiLevel} = $uiLevels->{$class}; + } + } + + # deal with custom field ui levels + foreach my $class (keys %assets) { + my $directive =~ s/::/_/g; + $directive .= '_uiLevel'; + my $value = $config->get($directive); + if (ref $value eq "HASH") { + foreach my $field (keys %{$value}) { + $assets{$class}{fields}{$field}{uiLevel} = $value->{$field}; + } + $config->delete($directive); + } + } + + # write the file + $config->delete('assetContainers'); + $config->delete('utilityAssets'); + $config->delete("assetUiLevel"); + $config->delete("assetAddPrivilege"); + $config->set("assets",\%assets); + + print "DONE!\n" unless $quiet; +} + #---------------------------------------------------------------------------- sub makeAdminConsolePluggable { my $session = shift; diff --git a/etc/WebGUI.conf.original b/etc/WebGUI.conf.original index b77a9f01f..feeeacc43 100644 --- a/etc/WebGUI.conf.original +++ b/etc/WebGUI.conf.original @@ -394,78 +394,221 @@ "maximumAssets" : 0, +# Specify the list of categories to display in the "New Content" +# menu. The category names should match those used in the "assets" +# hash later in this config. Each category can have three properties: +# +# title - The human readable name of the category. +# uiLevel - The minimum UI level the user must have to see the category. +# group - A group id the user must be in to see the category. + +"assetCategories" : { + "basic" : { + "uiLevel" : 1, + "title" : "^International(basic,Macro_AdminBar);" + }, + "shop" : { + "uiLevel" : 5, + "title" : "^International(shop,Shop);" + }, + "utilities" : { + "uiLevel" : 9, + "title" : "^International(utilities,Macro_AdminBar);" + }, + "community" : { + "uiLevel" : 5, + "title" : "^International(community,Macro_AdminBar);" + }, + "intranet" : { + "uiLevel" : 5, + "title" : "^International(intranet,Macro_AdminBar);" + } +}, + # Specify a the list of assets you want to appear in your -# Add Content menus. - -"assets" : [ - "WebGUI::Asset::FilePile", - "WebGUI::Asset::File::ZipArchive", - "WebGUI::Asset::Redirect", - "WebGUI::Asset::Sku::Donation", - "WebGUI::Asset::Sku::FlatDiscount", - "WebGUI::Asset::Sku::Product", - "WebGUI::Asset::Sku::Subscription", - "WebGUI::Asset::Snippet", - "WebGUI::Asset::Wobject::Article", - "WebGUI::Asset::Wobject::Calendar", - "WebGUI::Asset::Wobject::Collaboration", - "WebGUI::Asset::Wobject::DataForm", - "WebGUI::Asset::Wobject::EventManagementSystem", - "WebGUI::Asset::Wobject::Gallery", - "WebGUI::Asset::Wobject::HttpProxy", - "WebGUI::Asset::Wobject::InOutBoard", - "WebGUI::Asset::Wobject::Matrix", - "WebGUI::Asset::Wobject::MultiSearch", - "WebGUI::Asset::Wobject::Navigation", - "WebGUI::Asset::Wobject::Poll", - "WebGUI::Asset::Wobject::ProjectManager", - "WebGUI::Asset::Wobject::Search", - "WebGUI::Asset::Wobject::Shelf", - "WebGUI::Asset::Wobject::SQLReport", - "WebGUI::Asset::Wobject::StockData", - "WebGUI::Asset::Wobject::Survey", - "WebGUI::Asset::Wobject::SyndicatedContent", - "WebGUI::Asset::Wobject::Thingy", - "WebGUI::Asset::Wobject::TimeTracking", - "WebGUI::Asset::Wobject::UserList", - "WebGUI::Asset::Wobject::WeatherData", - "WebGUI::Asset::Wobject::WSClient" - ], - -# Specify the list assets that are used for utility purposes only -# and are not typically used as a normal part of content -# management. - -"utilityAssets" : [ - "WebGUI::Asset::File", - "WebGUI::Asset::File::Image", - "WebGUI::Asset::RichEdit", - "WebGUI::Asset::Template" - ], - -# Specify the list of assets you want to appear in your add -# content menus that should act as containers for other content. -# These items are typically not content themselves, but rather -# layout mechanisms. - -"assetContainers" : [ - "WebGUI::Asset::Sku::Product", - "WebGUI::Asset::Wobject::Dashboard", - "WebGUI::Asset::Wobject::Folder", - "WebGUI::Asset::Wobject::Layout", - "WebGUI::Asset::Wobject::MessageBoard", - "WebGUI::Asset::Wobject::WikiMaster" - ], - -# Optionally specify a group id for assets to tell WebGUI what -# group a user needs to be part of in order to add that type of -# asset. - -# "assetAddPrivilege" : { -# "WebGUI::Asset::Template" : 4 -# "WebGUI::Asset::Wobject::SQLReport" : 3, -# }, +# "New Content" menu categories. See "assetCategories" for details +# about categories. Each listing has a key of class name, and then +# has several properties, which are: +# +# category - The category the asset should appear in. +# isContainer - Whether or not the assets main purpose to display the data from other assets. +# addGroup - The group the user must be in to add this asset. +# uiLevel - The minimum UI level the user must have to add the asset. +# fields - Edit the properties of the asset. +# tabs - Edit the tabs on which the fields are displayed when editing the asset. +# +# The "fields" property above may override any property of any field in this +# asset class. Examples are label, tab, uiLevel. You must know what you're +# doing with this, because you could break an asset if you set something wrong +# with these properties. Here's an example of wha the fields poperty might look like: +# +# "fields" : { +# "title" : { +# "label" : "Name", +# "tab" : "basic" +# }, +# "synopsis" : { +# "label" : "Abstract", +# "uiLevel" : 3 +# } +# } +# +# The "tabs" property allows you to to create new, hide, and update existing tabs in +# the asset. Each tab has two properties: +# +# uiLevel - The minimum UI level the user must have to view the tab. +# label - The human readable label for the tab. +# +# Here's an example of what a tabls section might look like: +# +# "tabs" : { +# "basic" : { +# "label" : "Basic", +# "uiLevel" : 1 +# }, +# "meta" : { +# "uiLevel" : 99999 +# }, +# "security" : { +# "label" : "Protection" +# } +# } +"assets" : { + "WebGUI::Asset::Wobject::Shelf" : { + "category" : "shop" + }, + "WebGUI::Asset::Wobject::Layout" : { + "isContainer" : 1, + "category" : "basic" + }, + "WebGUI::Asset::Wobject::Gallery" : { + "category" : "community" + }, + "WebGUI::Asset::Wobject::DataForm" : { + "category" : "basic" + }, + "WebGUI::Asset::Sku::Donation" : { + "category" : "shop" + }, + "WebGUI::Asset::Wobject::UserList" : { + "category" : "intranet" + }, + "WebGUI::Asset::Wobject::EventManagementSystem" : { + "category" : "shop" + }, + "WebGUI::Asset::Sku::Subscription" : { + "category" : "shop" + }, + "WebGUI::Asset::Wobject::WikiMaster" : { + "isContainer" : 1, + "category" : "community" + }, + "WebGUI::Asset::Wobject::WSClient" : { + "category" : "utilities" + }, + "WebGUI::Asset::Wobject::StockData" : { + "category" : "intranet" + }, + "WebGUI::Asset::FilePile" : { + "category" : "basic" + }, + "WebGUI::Asset::Wobject::Collaboration" : { + "category" : "community" + }, + "WebGUI::Asset::Wobject::Survey" : { + "category" : "community" + }, + "WebGUI::Asset::File::ZipArchive" : { + "category" : "utilities" + }, + "WebGUI::Asset::RichEdit" : { + "category" : "utilities" + }, + "WebGUI::Asset::Wobject::SyndicatedContent" : { + "category" : "utilities" + }, + "WebGUI::Asset::Wobject::HttpProxy" : { + "category" : "utilities" + }, + "WebGUI::Asset::Wobject::MultiSearch" : { + "category" : "intranet" + }, + "WebGUI::Asset::File::Image" : { + "category" : "utilities" + }, + "WebGUI::Asset::Sku::Product" : { + "isContainer" : 1, + "category" : "shop" + }, + "WebGUI::Asset::Wobject::WeatherData" : { + "category" : "intranet" + }, + "WebGUI::Asset::Redirect" : { + "category" : "utilities" + }, + "WebGUI::Asset::Wobject::Article" : { + "category" : "basic" + }, + "WebGUI::Asset::Wobject::Search" : { + "category" : "basic" + }, + "WebGUI::Asset::Wobject::MessageBoard" : { + "isContainer" : 1, + "category" : "community" + }, + "WebGUI::Asset::Wobject::SQLReport" : { + "category" : "utilities" + }, + "WebGUI::Asset::Wobject::TimeTracking" : { + "category" : "intranet" + }, + "WebGUI::Asset::Wobject::Calendar" : { + "category" : "basic" + }, + "WebGUI::Asset::Wobject::Poll" : { + "category" : "basic" + }, + "WebGUI::Asset::Wobject::ProjectManager" : { + "category" : "intranet" + }, + "WebGUI::Asset::Wobject::Folder" : { + "isContainer" : 1, + "category" : "basic" + }, + "WebGUI::Asset::Wobject::Navigation" : { + "category" : "utilities" + }, + "WebGUI::Asset::Wobject::Matrix" : { + "category" : "community" + }, + "WebGUI::Asset::Sku::FlatDiscount" : { + "category" : "shop" + }, + "WebGUI::Asset::Wobject::Thingy" : { + "category" : "intranet" + }, + "WebGUI::Asset::File" : { + "category" : "utilities" + }, + "WebGUI::Asset::Wobject::Collaboration::Newsletter" : { + "category" : "community" + }, + "WebGUI::Asset::Snippet" : { + "category" : "basic" + }, + "WebGUI::Asset::Wobject::InOutBoard" : { + "category" : "intranet" + }, + "WebGUI::Asset::Wobject::Dashboard" : { + "isContainer" : 1, + "category" : "intranet" + }, + "WebGUI::Asset::Template" : { + "category" : "utilities" + } +}, + # Optionally add a "Save and Commit" button to assets so that you # don't have to hit "Commit My Changes" seperately. @@ -475,11 +618,6 @@ # determines whether the current user has the appropriate UI Level # to add assets of that type. -# "assetUiLevel" : { -# "WebGUI::Asset::RichEdit" : 4 -# "WebGUI::Asset::Wobject::WSClient" : 7, -# }, - # Configure the UI Levels of the asset toolbar links. "assetToolbarUiLevel" : { @@ -499,27 +637,12 @@ "export" : 9 }, -# You can override the UI Levels of any field in the edit form of -# any asset using the following variables. Basically just take the -# class name of the asset separated by underscores, and append -# _uiLevel to the end of it, then you can start specifying field -# names and associated UI Level. - -# "WebGUI_Asset_Wobject_Article_uiLevel" : { "menuTitle" : 9, "url" : 8 }, -# "WebGUI_Asset_RichEdit_uiLevel" : { "askAboutRichEdit" : 7, "preformatted" : 3 }, - # If exportPath is defined, an "Export" toolbar icon will appear # which allows you to export assets to static HTML. This folder # needs to be writable by your web server. # "exportPath" : "/path/to/export", -# If soapHttpHeaderOverride is set to 1 it will enable Web -# Service Client assets to override the default MIME types of -# SOAP/WDSL content - -"soapHttpHeaderOverride" : 0, - # Enable streaming Image and File assets thru mod_perl process instead of # simple redirect. WARNING has impact on performance. diff --git a/lib/WebGUI/Asset.pm b/lib/WebGUI/Asset.pm index c913efccf..6456b3477 100644 --- a/lib/WebGUI/Asset.pm +++ b/lib/WebGUI/Asset.pm @@ -217,7 +217,7 @@ sub canAdd { my $userId = shift || $session->user->userId; my $user = WebGUI::User->new($session, $userId); my $subclassGroupId = shift; - my $addPrivs = $session->config->get("assetAddPrivilege"); + my $addPrivs = $session->config->get("assets/".$className."/addGroup"); my $groupId = $addPrivs->{$className} || $subclassGroupId || '12'; return $user->isInGroup($groupId); } @@ -740,99 +740,6 @@ sub getAdminConsole { return $self->{_adminConsole}; } -#------------------------------------------------------------------- - -=head2 getAssetAdderLinks ( [addToUrl, type] ) - -Returns an arrayref that contains a label (name of the class of Asset) and url (url link to function to add the class). - -=head3 addToUrl - -Any text to append to the getAssetAdderLinks URL. Usually name/variable pairs to pass in the url. If addToURL is specified, the character ";" and the text in addToUrl is appended to the returned url. - -=head3 type - -A string indicating which type of adders to return. Defaults to "assets". Choose from "assets", "assetContainers", or "utilityAssets". - -=cut - -sub getAssetAdderLinks { - my $self = shift; - my $addToUrl = shift; - my $type = shift || "assets"; - my %links; - my $classesInType = $self->session->config->get($type); - if (ref $classesInType ne "ARRAY") { - $classesInType = []; - } - foreach my $class (@{$classesInType}) { - next unless $class; - my %properties = ( - className=>$class, - dummy=>1 - ); - my $newAsset = WebGUI::Asset->newByPropertyHashRef($self->session,\%properties); - next unless $newAsset; - my $uiLevel = eval{$newAsset->getUiLevel()}; - if ($@) { - $self->session->errorHandler->error("Couldn't get UI level of ".$class.". Root cause: ".$@); - next; - } - next if ($uiLevel > $self->session->user->profileField("uiLevel"));# && !$self->session->user->isAdmin); - my $canAdd = eval{$class->canAdd($self->session)}; - if ($@) { - $self->session->errorHandler->error("Couldn't determine if user can add ".$class." because ".$@); - next; - } - next unless ($canAdd); - my $label = eval{$newAsset->getName()}; - if ($@) { - $self->session->errorHandler->error("Couldn't get the name of ".$class."because ".$@); - next; - } - my $url = $self->getUrl("func=add;class=".$class); - $url = $self->session->url->append($url,$addToUrl) if ($addToUrl); - $links{$label}{url} = $url; - $links{$label}{icon} = $newAsset->getIcon; - $links{$label}{'icon.small'} = $newAsset->getIcon(1); - } - my $constraint; - if ($type eq "assetContainers") { - $constraint = $self->session->db->quoteAndJoin($self->session->config->get("assetContainers")); - } elsif ($type eq "utilityAssets") { - $constraint = $self->session->db->quoteAndJoin($self->session->config->get("utilityAssets")); - } else { - $constraint = $self->session->db->quoteAndJoin($self->session->config->get("assets")); - } - if ($constraint) { - my $sth = $self->session->db->read("select asset.className,asset.assetId,assetData.revisionDate from asset left join assetData on asset.assetId=assetData.assetId where assetData.isPrototype=1 and asset.state='published' and asset.className in ($constraint) and assetData.revisionDate=(SELECT max(revisionDate) from assetData where assetData.assetId=asset.assetId) group by assetData.assetId"); - while (my ($class,$id,$date) = $sth->array) { - my $asset = WebGUI::Asset->new($self->session,$id,$class,$date); - next unless ($asset->canView && $asset->canAdd($self->session) && $asset->getUiLevel <= $self->session->user->profileField("uiLevel")); - my $url = $self->getUrl("func=add;class=".$class.";prototype=".$id); - $url = $self->session->url->append($url,$addToUrl) if ($addToUrl); - $links{$asset->getTitle}{url} = $url; - $links{$asset->getTitle}{icon} = $asset->getIcon; - $links{$asset->getTitle}{'icon.small'} = $asset->getIcon(1); - $links{$asset->getTitle}{'isPrototype'} = 1; - $links{$asset->getTitle}{'asset'} = $asset; - } - $sth->finish; - } - my @sortedLinks; - foreach my $label (sort keys %links) { - push(@sortedLinks,{ - label=>$label, - url=>$links{$label}{url}, - icon=>$links{$label}{icon}, - 'icon.small'=>$links{$label}{'icon.small'}, - isPrototype=>$links{$label}{isPrototype}, - asset=>$links{$label}{asset} - }); - } - return \@sortedLinks; -} - #------------------------------------------------------------------- @@ -844,10 +751,10 @@ Returns a reference to the container asset. If this asset is a container it retu sub getContainer { my $self = shift; - if (WebGUI::Utility::isIn($self->get("className"), @{$self->session->config->get("assetContainers")})) { + if ($self->session->config->get("assets/".$self->get("className")."/isContainer")) { return $self; - } else { -# $self->session->asset($self->getParent); + } + else { return $self->getParent; } } @@ -870,6 +777,204 @@ sub getDefault { return $class->newByDynamicClass($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 $i18n = WebGUI::International->new($self->session, "Asset"); + my $ago = $i18n->get("ago"); + my $rs = $self->session->db->read("select revisionDate from assetData where assetId=? order by revisionDate desc limit 5", [$self->getId]); + my $uiLevelOverride = $self->get("className"); + $uiLevelOverride =~ s/\:\:/_/g; + my $tabform = WebGUI::TabForm->new($self->session,undef,undef,$self->getUrl(),$uiLevelOverride); + my $overrides = $self->session->config->get("assets/".$self->get("className")); + + # Set the appropriate URL + # If we're adding a new asset, don't set anything + if ( $self->session->form->get( "func" ) ne "add" ) { + $tabform->formHeader( { action => $self->getUrl, method => "POST" } ); + } + + if ($self->session->config->get("enableSaveAndCommit")) { + $tabform->submitAppend(WebGUI::Form::submit($self->session, { + name => "saveAndCommit", + value => $i18n->get("save and commit"), + })); + } + $tabform->hidden({ + name=>"func", + value=>"editSave" + }); + if ($self->getId eq "new") { + $tabform->hidden({ + name=>"assetId", + value=>"new" + }); + $tabform->hidden({ + name=>"class", + value=>$self->session->form->process("class","className") + }); + } + else { + my $ac = $self->getAdminConsole; + $ac->addSubmenuItem($self->getUrl("func=manageRevisions"),$i18n->get("revisions").":"); + while (my ($version) = $rs->array) { + my ($interval, $units) = $self->session->datetime->secondsToInterval(time() - $version); + $ac->addSubmenuItem($self->getUrl("func=edit;revision=".$version), $interval." ".$units." ".$ago); + } + } + if ($self->session->form->process("proceed")) { + $tabform->hidden({ + name=>"proceed", + value=>$self->session->form->process("proceed") + }); + } + + # 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 = $self->session->stow->get('editFormErrors'); + if ($errors) { + $tabform->getTab("properties")->readOnly( + -value=>"

Some error(s) occurred:

', + ); + } + + # build the definition to the generate form + my @definitions = reverse @{$self->definition($self->session)}; + tie my %baseProperties, 'Tie::IxHash'; + %baseProperties = ( + assetId => { + fieldType => "readOnly", + label => $i18n->get("asset id"), + value => $self->get("assetId"), + hoverHelp => $i18n->get('asset id description'), + tab => "properties", + }, + keywords => { + label => $i18n->get('keywords'), + hoverHelp => $i18n->get('keywords help'), + value => $self->get('keywords'), + fieldType => 'text', + tab => 'meta', + } + ); + unshift @definitions, { + autoGenerateForms => 1, + properties => \%baseProperties + }; + + # extend the definition with metadata + tie my %extendedProperties, 'Tie::IxHash'; + if ($self->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; + } + $extendedProperties{"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 ($self->session->user->isAdmin) { + $extendedProperties{_metadatamanagement} = { + tab => "meta", + fieldType => "readOnly", + value => '

'.$i18n->get('Add new field').'

', + hoverHelp => $i18n->get('Add new field description'), + }; + } + } + push @definitions, { + autoGenerateForms => 1, + properties => \%extendedProperties + }; + + # generate the form + foreach my $definition (@definitions) { + my $properties = $definition->{properties}; + + # depricated...by WebGUI 8 they all must autogen forms + next unless ($definition->{autoGenerateForms}); + + foreach my $fieldName (keys %{$properties}) { + my %fieldHash = %{$properties->{$fieldName}}; + my %params = (name => $fieldName, value => $self->getValue($fieldName)); + next if exists $fieldHash{autoGenerate} and not $fieldHash{autoGenerate}; + + # 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}]; + } + + if (exists $fieldHash{visible} and not $fieldHash{visible}) { + $params{fieldType} = 'hidden'; + } + else { + %params = (%params, %fieldHash); + delete $params{tab}; + } + + # if there isnt a tab specified lets define one + my $tab = $fieldHash{tab} || "properties"; + + # use a custom draw method + my $drawMethod = $properties->{$fieldName}{customDrawMethod}; + if ($drawMethod) { + $params{value} = $self->$drawMethod(\%params); + $params{fieldType} = "readOnly"; + } + + #draw the field + $tabform->getTab($tab)->dynamicField(%params); + } + } + + # send back the rendered form + return $tabform; +} + + #------------------------------------------------------------------- =head2 getEditTabs () @@ -908,170 +1013,15 @@ Please see the example below for adding 1 tab. =cut sub getEditTabs { - my $self = shift; - return (); -} - -#------------------------------------------------------------------- - -=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 $i18n = WebGUI::International->new($self->session, "Asset"); - my $ago = $i18n->get("ago"); - my $rs = $self->session->db->read("select revisionDate from assetData where assetId=? order by revisionDate desc limit 5", [$self->getId]); - my $uiLevelOverride = $self->get("className"); - $uiLevelOverride =~ s/\:\:/_/g; - my $tabform = WebGUI::TabForm->new($self->session,undef,undef,$self->getUrl(),$uiLevelOverride); - - # Set the appropriate URL - # If we're adding a new asset, don't set anything - if ( $self->session->form->get( "func" ) ne "add" ) { - $tabform->formHeader( { action => $self->getUrl, method => "POST" } ); - } - - if ($self->session->config->get("enableSaveAndCommit")) { - $tabform->submitAppend(WebGUI::Form::submit($self->session, { - name => "saveAndCommit", - value => $i18n->get("save and commit"), - })); - } - $tabform->hidden({ - name=>"func", - value=>"editSave" - }); - if ($self->getId eq "new") { - $tabform->hidden({ - name=>"assetId", - value=>"new" - }); - $tabform->hidden({ - name=>"class", - value=>$self->session->form->process("class","className") - }); - } else { - my $ac = $self->getAdminConsole; - $ac->addSubmenuItem($self->getUrl("func=manageRevisions"),$i18n->get("revisions").":"); - while (my ($version) = $rs->array) { - my ($interval, $units) = $self->session->datetime->secondsToInterval(time() - $version); - $ac->addSubmenuItem($self->getUrl("func=edit;revision=".$version), $interval." ".$units." ".$ago); - } - } - if ($self->session->form->process("proceed")) { - $tabform->hidden({ - name=>"proceed", - value=>$self->session->form->process("proceed") - }); - } - # create tabs - $tabform->addTab("properties",$i18n->get("properties")); - $tabform->addTab("display",$i18n->get(105),5); - $tabform->addTab("security",$i18n->get(107),6); - $tabform->addTab("meta",$i18n->get("Metadata"),3); - # process errors - my $errors = $self->session->stow->get('editFormErrors'); - if ($errors) { - $tabform->getTab("properties")->readOnly( - -value=>"

Some error(s) occurred:

', - ) - } - $tabform->getTab("properties")->readOnly( - -label=>$i18n->get("asset id"), - -value=>$self->get("assetId"), - -hoverHelp=>$i18n->get('asset id description'), - ); - - foreach my $tabspec ($self->getEditTabs) { - $tabform->addTab(@$tabspec); - } - - foreach my $definition (reverse @{$self->definition($self->session)}) { - my $properties = $definition->{properties}; - next unless ($definition->{autoGenerateForms}); - - foreach my $fieldName (keys %{$properties}) { - my %fieldHash = %{$properties->{$fieldName}}; - my %params = (name => $fieldName, - value => $self->getValue($fieldName)); - next if exists $fieldHash{autoGenerate} and not $fieldHash{autoGenerate}; - - # Kludge. - if (isIn($fieldHash{fieldType}, 'selectBox', 'workflow') and ref $params{value} ne 'ARRAY') { - $params{value} = [$params{value}]; - } - - if (exists $fieldHash{visible} and not $fieldHash{visible}) { - $params{fieldType} = 'hidden'; - } else { - %params = (%params, %fieldHash); - delete $params{tab}; - } - - my $tab = $fieldHash{tab} || "properties"; - - # use a custom draw method - my $drawMethod = $properties->{$fieldName}{customDrawMethod}; - if ($drawMethod) { - $params{value} = $self->$drawMethod(\%params); - $params{fieldType} = "readOnly"; - } - - #draw the field - $tabform->getTab($tab)->dynamicField(%params); - } - } - - # display keywords field - $tabform->getTab('meta')->text( - name => 'keywords', - label => $i18n->get('keywords'), - hoverHelp => $i18n->get('keywords help'), - value => $self->get('keywords'), - ); - - # metadata / content profiling - if ($self->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; - } - $tabform->getTab("meta")->dynamicField( - name => "metadata_".$meta->{$field}{fieldId}, - label => $meta->{$field}{fieldName}, - uiLevel => 5, - value => $meta->{$field}{value}, - extras => qq/title="$meta->{$field}{description}"/, - options => $options, - defaultValue => $meta->{$field}{defaultValue}, - fieldType=>$fieldType - ); - } - if ($self->session->user->isAdmin) { - # Add a quick link to add field - $tabform->getTab("meta")->readOnly( - -value=>'

'. - $i18n->get('Add new field'). - '

', - -hoverHelp=>$i18n->get('Add new field description'), - ); - } - } - return $tabform; + return ["properties", $i18n->get("properties"), 1], + ["display", $i18n->get(105), 5], + ["security", $i18n->get(107), 6], + ["meta", $i18n->get("Metadata"), 3]; } - #------------------------------------------------------------------- =head2 getExtraHeadTags ( ) @@ -1436,13 +1386,12 @@ Returns the UI Level specified in the asset definition or from the config file i sub getUiLevel { my $self = shift; - my $definition = $self->get("className")->definition($self->session); - my $uiLevel = $self->session->config->get("assetUiLevel"); - if ($uiLevel && ref $uiLevel eq 'HASH') { - return $uiLevel->{$definition->[0]{className}} || $definition->[0]{uiLevel} || 1 ; - } else { - return $definition->[0]{uiLevel} || 1 ; - } + my $uiLevel = shift; + my $className = $self->get("className"); + return $uiLevel # passed in + || $self->session->config->get("assets/".$className."/uiLevel") # from config + || $self->definition($self->session)->[0]{uiLevel} # from definition + || 1; # if all else fails } diff --git a/lib/WebGUI/Help/Macro_AdminBar.pm b/lib/WebGUI/Help/Macro_AdminBar.pm deleted file mode 100644 index 04299b3b3..000000000 --- a/lib/WebGUI/Help/Macro_AdminBar.pm +++ /dev/null @@ -1,26 +0,0 @@ -package WebGUI::Help::Macro_AdminBar; -use strict; - -our $HELP = { - - 'admin bar' => { - title => 'admin bar title', - body => '', - fields => [], - variables => [ - { 'name' => 'adminbar_loop', - 'variables' => [ - { 'name' => 'label' }, - { 'name' => 'name' }, - { 'name' => 'items', - 'variables' => [ { 'name' => 'title' }, { 'name' => 'url' }, { 'name' => 'icon' } ] - } - ] - } - ], - related => [] - }, - -}; - -1; diff --git a/lib/WebGUI/Macro/AdminBar.pm b/lib/WebGUI/Macro/AdminBar.pm index 55f4f2e10..955b456c7 100644 --- a/lib/WebGUI/Macro/AdminBar.pm +++ b/lib/WebGUI/Macro/AdminBar.pm @@ -13,8 +13,8 @@ package WebGUI::Macro::AdminBar; use strict qw(refs vars); use WebGUI::AdminConsole; use WebGUI::Asset; -use WebGUI::Asset::Template; use WebGUI::International; +use WebGUI::Macro; use WebGUI::Utility; use WebGUI::VersionTag; @@ -26,18 +26,268 @@ Package WebGUI::Macro::AdminBar Macro for displaying administrative functions to a user with Admin turned on. -=head2 process ( [templateId ] ) +=head2 process ( ) process takes one optional parameters for customizing the layout of the Admin bar. -=head3 templateId +=cut -The ID for a template to use for formatting the link. The default template creates the sliding Admin bar to the left of the screen. + +sub process { + my $session = shift; + return undef unless $session->var->isAdminOn; + my $i18n = WebGUI::International->new($session,'Macro_AdminBar'); + my ($url, $style, $asset, $user, $config) = $session->quick(qw(url style asset user config)); + $style->setScript($url->extras('yui/build/utilities/utilities.js'), {type=>'text/javascript'}); + $style->setScript($url->extras('accordion/accordion.js'), {type=>'text/javascript'}); +# $style->setLink($url->extras('accordion/accordion.css'), {type=>'text/css', rel=>'stylesheet'}); + $style->setLink($url->extras('slidePanel/slidePanel.css'), {type=>'text/css', rel=>'stylesheet'}); +# $style->setRawHeadTags(); + + my $out = q{
}; + + # admin console + my $ac = WebGUI::AdminConsole->new($session); + $out .= q{
}.$i18n->get("admin console","AdminConsole").q{
}; + foreach my $item (@{$ac->getAdminFunction}) { + next unless $item->{canUse}; + $out .= q{} + .q{icon } + .$item->{title}.q{}; + } + $out .= qq{
\n}; + + # version tags + my $versionTags = WebGUI::VersionTag->getOpenTags($session); + if (scalar(@$versionTags)) { + $out .= q{
}.$i18n->get("version tags","VersionTag").q{
}; + my $working = WebGUI::VersionTag->getWorking($session, 1); + my $workingId = ""; + if ($working) { + $workingId = $working->getId; + my $commitUrl = ""; + if ($session->setting->get("skipCommitComments")) { + $commitUrl = $url->page("op=commitVersionTagConfirm;tagId=".$workingId); + } + else { + $commitUrl = $url->page("op=commitVersionTag;tagId=".$workingId); + } + $out .= q{} + .q{icon } + .$i18n->get("commit my changes").q{}; + } + foreach my $tag (@{$versionTags}) { + next unless $user->isInGroup($tag->get("groupToUse")); + my $switchUrl = $url->page("op=" . ($tag->getId eq $workingId ? "editVersionTag" : "setWorkingVersionTag") . ";backToSite=1;tagId=".$tag->getId); + my $title = ($tag->getId eq $workingId) ? '* '.$tag->get("name").'' : $tag->get("name"); + $out .= q{}.$title.q{}; + } + $out .= qq{
\n}; + } + + + # stuff to do if we're on a page with an asset + if ($asset) { + + # clipboard + my $clipboardItems = $session->asset->getAssetsInClipboard(1); + if (scalar (@$clipboardItems)) { + $out .= q{
}.$i18n->get("1082").q{
}; + foreach my $item (@{$clipboardItems}) { + my $title = $asset->getTitle; + $out .= q{getId).q{">} + .q{icon } + .$item->getTitle.q{}; + } + $out .= qq{
\n}; + } + + ### new content menu + + # determine new content categories + my %rawCategories = %{$config->get('assetCategories')}; + my %categories; + my %categoryTitles; + my $userUiLevel = $user->profileField('uiLevel'); + foreach my $category (keys %rawCategories) { + next if $rawCategories{$category}{uiLevel} > $userUiLevel; + next if (exists $rawCategories{$category}{group} && !$user->isInGroup($rawCategories{$category}{group})); + my $title = $rawCategories{$category}{title}; + WebGUI::Macro::process($session, \$title); + $categories{$category}{title} = $title; + $categoryTitles{$title} = $category; + } + + # assets + my %assetList = %{$config->get('assets')}; + foreach my $assetClass (keys %assetList) { + my $dummy = WebGUI::Asset->newByPropertyHashRef($session,{dummy=>1, className=>$assetClass}); + next if $dummy->getUiLevel($assetList{$assetClass}{uiLevel}) > $userUiLevel; + next unless ($dummy->canAdd($session)); + next unless exists $categories{$assetList{$assetClass}{category}}; + $categories{$assetList{$assetClass}{category}}{items}{$dummy->getTitle} = { + icon => $dummy->getIcon(1), + url => $asset->getUrl("func=add;class=".$dummy->get('className')), + }; + } + + # packages + foreach my $package (@{$session->asset->getPackageList}) { + next unless ($package->canView && $package->canAdd($session) && $package->getUiLevel <= $userUiLevel); + $categories{packages}{items}{$package->getTitle} = { + url => $asset->getUrl("func=deployPackage;assetId=".$package->getId), + icon => $package->getIcon(1), + }; + } + if (scalar keys %{$categories{packages}{items}}) { + $categories{packages}{title} = $i18n->get('packages'); + $categoryTitles{$i18n->get('packages')} = "packages"; + } + + # prototypes + my $sth = $session->db->read("select asset.className,asset.assetId,assetData.revisionDate from asset + left join assetData on asset.assetId=assetData.assetId + where assetData.isPrototype=1 and asset.state='published' and assetData.revisionDate=(SELECT max(revisionDate) from assetData where assetData.assetId=asset.assetId) + group by assetData.assetId"); + while (my ($class, $id, $date) = $sth->array) { + my $prototype = WebGUI::Asset->new($session,$id,$class,$date); + next unless ($prototype->canView && $prototype->canAdd($session) && $prototype->getUiLevel <= $userUiLevel); + $categories{prototypes}{items}{$prototype->getTitle} = { + url => $asset->getUrl("func=add;class=".$class.";prototype=".$prototype->getId), + icon => $prototype->getIcon(1), + }; + } + if (scalar keys %{$categories{prototypes}{items}}) { + $categories{prototypes}{title} = $i18n->get('prototypes'); + $categoryTitles{$i18n->get('prototypes')} = "prototypes"; + } + + # render new content menu + $out .= q{
}.$i18n->get("1083").q{
}; + foreach my $categoryTitle (sort keys %categoryTitles) { + $out .= '
'.$categoryTitle.'
'; + my $items = $categories{$categoryTitles{$categoryTitle}}{items}; + next unless (ref $items eq 'HASH'); # in case the category is empty + foreach my $title (sort keys %{$items}) { + $out .= q{} + .q{icon } + .$title.q{}; + } + $out .= '
'; + } + $out .= qq{
\n}; + } + + $out .= q{
+