Skip to content

Commit

Permalink
Item11946:
Browse files Browse the repository at this point in the history
   * add a =filter= parameter using the QuerySearch language
   * rationalize use of =include= and =exclude= parameters in RENDERMETADATA
   * working around core bug caching half-way constructed Foswiki::Form objects
   * add flag to suppress error messages on the UI, e.g. when a meta data definition is not accessible
   * catch access control exception when constructing a form object



git-svn-id: http://svn.foswiki.org/trunk/MetaDataPlugin@14983 0b4bb1d4-4e5a-0410-9cc4-b2b747904278
  • Loading branch information
MichaelDaum authored and MichaelDaum committed Jun 14, 2012
1 parent 6252815 commit c7ecf38
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 22 deletions.
19 changes: 14 additions & 5 deletions data/System/MetaDataPlugin.txt
Expand Up @@ -57,15 +57,20 @@ topic edit screen.
| footer | footer string to apped to the output | |
| separator | string to be put between each formatted output per formfield | |
| valueseparator | | |
| include | regular expression fieldnames must match to be included in the output | |
| exclude | regular expression fieldnames must match to be excluded from the output | |
| includeattr | regular expression field attributes must match to be included in the output | |
| excludeattr | regular expression field attributes must match to be excluded from the output | |
| include | a comma separated list of record names to be included in the output, e.g. "id1, id2, id5" | |
| exclude | a comma separated list of record names to be excluded from the output | |
| includeattr | regular expression field attributes part of the !DataForm definition must match to be included in the output | |
| excludeattr | regular expression field attributes part of the !DataForm definition must match to be excluded from the output | |
| filter | a filter expression that records must match to be displayed. this overrides the =include= and =exclude= parameters. \
note that the given =filter= will be used to perform a [[%SYSTEMWEB%.QuerySearch][query search]] by constructing a query of the form ='topic'/key[filter].name'=\
where ='topic'= is the topic containing the meta data records, =key= is the name of the meta data. \
example: =filter="FirstName='Raffael' or !FirstName='Judith'"= | |
| sort | name of attribute used for sorting | name |
| reverse | boolean flag to reverse the sorting order | off |
| mandatory | string to be inserted when a field is mandatory | <span class='foswikiAlert'>**</span> |
| hiddenformat | format string to be used to render hidden formfields | |
| hideempty | boolean flag to hide/show empty formfields | off |
| hideerror | boolean flag to suppress error messages | off |
| autolink | boolean flag to enable/prevent !WikiWord linking | on |
| fieldformat | format string for a single formfield value in a row | |
| &lt;field_name>_attributes, %BR% \
Expand Down Expand Up @@ -117,6 +122,7 @@ render a modal edit dialog according to the associated !DataForm definition.
| format | format string to render the button | defined in the =metadataplugin.tmpl= template |
| template | name of the TMPL:DEF to render the button | metadata::new |
| title | display title for the button | |
| hideempty | boolean flag to hide/show empty formfields | off |

---++ Registering !MetaData

Expand Down Expand Up @@ -183,8 +189,11 @@ have a database of efforts recorded on that tracker.
| Release: | %$RELEASE% |
| Version: | %$VERSION% |
| Change History: | <!-- versions below in reverse order -->&nbsp; |
| 14 Jun 2012: | rationalized =include= and =exclude= parameters;\
and =filter= parameter to RENDERMETADATA;\
added work-around for bug in =Foswiki::Form= caching half-constructed form objects |
| 10 May 2012: | fixed error when meta data definition is read-protected; \
implemented a way to store meta data in a distant / hidden topic;
implemented a way to store meta data in a distant / hidden topic; \
added =$origvalue= for field-specific format strings |
| 08 May 2012: | added =sort= and =reverse= parameters to RENDERMETADATA |
| 27 Apr 2012: | fixed access to the original value of +values formfields |
Expand Down
32 changes: 22 additions & 10 deletions lib/Foswiki/Plugins/MetaDataPlugin.pm
Expand Up @@ -25,7 +25,7 @@ use Foswiki::Plugins::MetaDataPlugin::Core();
use Error qw( :try );

our $VERSION = '$Rev$';
our $RELEASE = '1.40';
our $RELEASE = '2.00';
our $SHORTDESCRIPTION = 'Bring custom meta data to wiki apps';
our $NO_PREFS_IN_TOPIC = 1;
our $core;
Expand Down Expand Up @@ -107,6 +107,7 @@ sub registerMetaData {
foreach my $item (split(/\s*,\s*/, $topics)) {
my ($web, $topic) = Foswiki::Func::normalizeWebTopicName($baseWeb, $item);
my $metaDef = getMetaDataDefinition($web, $topic);
next unless defined $metaDef;
my ($key) = topicName2MetaData($topic);
#print STDERR "meta data key = $key\n";
Foswiki::Meta::registerMETA($key, %$metaDef);
Expand Down Expand Up @@ -143,31 +144,42 @@ sub getMetaDataDefinition {
return unless Foswiki::Func::topicExists($web, $topic);

my $formDef;
my $session = $Foswiki::Plugins::SESSION;

try {
$formDef = new Foswiki::Form($Foswiki::Plugins::SESSION, $web, $topic);
$formDef = new Foswiki::Form($session, $web, $topic);
} catch Error::Simple with {

# just in case, cus when this fails it takes down more of foswiki
Foswiki::Func::writeWarning("MetaDataPlugin::getMetaDataDefinition() failed for $web.$topic:".shift);
Foswiki::Func::writeWarning("MetaDataPlugin::getMetaDataDefinition() failed for $web.$topic: ".shift);

} catch Foswiki::AccessControlException with {
# catch but simply bail out
#print STDERR "can't access form at $web.$topic in getMetaDataDefinition()\n";

# SMELL: manually invalidate the forms cache for a partially build form object
if (exists $session->{forms}{"$web.$topic"}) {
#print STDERR "WARNING: bug present in Foswiki::Form - invalid form object found in cache - deleting it manually\n";
delete $session->{forms}{"$web.$topic"};
}

};

return unless defined $formDef;
return unless defined $formDef; # Hm, or do we create an empty record?

my @other = ();
my @require = ();

push @require, 'name'; # is always required

foreach my $field (@{$formDef->getFields}) {
my $name = $field->{name};
if ($field->isMandatory) {
push @require, $name;
} else {
push @other, $name;
if (defined $formDef) {
foreach my $field (@{$formDef->getFields}) {
my $name = $field->{name};
if ($field->isMandatory) {
push @require, $name;
} else {
push @other, $name;
}
}
}

Expand Down
107 changes: 100 additions & 7 deletions lib/Foswiki/Plugins/MetaDataPlugin/Core.pm
Expand Up @@ -56,6 +56,18 @@ sub init {
Foswiki::Func::expandCommonVariables($result);
}

##############################################################################
sub getQueryParser {
my $this = shift;

unless (defined $this->{_queryParser}) {
require Foswiki::Query::Parser;
$this->{_queryParser} = new Foswiki::Query::Parser();
}

return $this->{_queryParser};
}

##############################################################################
sub registerDeleteHandler {
my ($this, $metaData, $function, $options) = @_;
Expand All @@ -72,6 +84,12 @@ sub NEWMETADATA {
my ($this, $params) = @_;

my $theMetaData = lc($params->{_DEFAULT} || $params->{meta} || '');
my $theHideError = Foswiki::Func::isTrue($params->{hideerror}, 0);

my $metaDataKey = uc($theMetaData);
my $metaDataDef = $Foswiki::Meta::VALIDATE{$metaDataKey};
return $theHideError?'':inlineError("can't find meta data definition for $metaDataKey") unless defined $metaDataDef;

my $theTitle = $params->{title};
my $theFormat = $params->{format};
my $theTemplate = $params->{template} || 'metadata::new';
Expand All @@ -80,6 +98,7 @@ sub NEWMETADATA {
my ($web, $topic) = Foswiki::Func::normalizeWebTopicName($this->{baseWeb}, $theTopic);
$theTopic = "$web.$topic";


$theTitle = "New ".ucfirst($theMetaData) unless defined $theTitle;

$theFormat = Foswiki::Func::expandTemplate($theTemplate) unless defined $theFormat;
Expand All @@ -99,8 +118,21 @@ sub RENDERMETADATA {
my $metaData = $params->{_DEFAULT};
my $topic = $params->{topic} || $this->{baseTopic};
my $web = $params->{web} || $this->{baseWeb};
my $hideError = Foswiki::Func::isTrue($params->{hideerror}, 0);

($web, $topic) = Foswiki::Func::normalizeWebTopicName($web, $topic);

my $action = $params->{action} || 'view';
my $wikiName = Foswiki::Func::getWikiName();

return $hideError?'':inlineError("Error: access denied to view $web.$topic")
if $action eq 'view' && ! Foswiki::Func::checkAccessPermission("VIEW", $wikiName, undef, $web, $topic);

return $hideError?'':inlineError("Error: access denied to change $web.$topic")
if $action eq 'edit' && ! Foswiki::Func::checkAccessPermission("CHANGE", $wikiName, undef, $web, $topic);

return $hideError?'':inlineError("Error: unknown action '$action'") unless $action =~ /^(view|edit)$/;

my $topicObj = getTopicObject($this, $web, $topic);


Expand Down Expand Up @@ -141,6 +173,46 @@ sub renderMetaData {
my $theReverse = Foswiki::Func::isTrue($params->{reverse});
my $theAutolink = Foswiki::Func::isTrue($params->{autolink}, 1);
my $theFieldFormat = $params->{fieldformat};
my $theFilter = $params->{filter};
my $theHideError = Foswiki::Func::isTrue($params->{hideerror}, 0);

my %includeMap = ();
if (defined $theInclude) {
foreach my $item (split(/\s*,\s*/, $theInclude)) {
$includeMap{$item} = 1;
}
}

my %excludeMap = ();
if (defined $theExclude) {
foreach my $item (split(/\s*,\s*/, $theExclude)) {
$excludeMap{$item} = 1;
}
}

if (defined $theFilter) {
%excludeMap = ();
%includeMap = ();
my $queryParser = $this->getQueryParser();
my $error;
my $query = "'".$topicObj->getPath()."'/".$metaData."[".$theFilter."].name";
try {
my $node = $queryParser->parse($query);
my $result = $node->evaluate(tom => $topicObj, data => $topicObj);
if (defined $result) {
if (ref($result) ne 'ARRAY') {
$result = [$result];
}
$theInclude = ''; # dummy
%includeMap = map {$_ => 1} @$result;
}
}
catch Foswiki::Infix::Error with {
$error = $theHideError?'':inlineError("Error: " . shift);
};
return $error if defined $error;
}


$theMandatory = " <span class='foswikiAlert'>**</span> " unless defined $theMandatory;
$theHiddenFormat = '<input type="hidden" name="$name" value="$value" />' unless defined $theHiddenFormat;
Expand All @@ -150,7 +222,7 @@ sub renderMetaData {

my $metaDataKey = uc($metaData);
my $metaDataDef = $Foswiki::Meta::VALIDATE{$metaDataKey};
return inlineError("meta data $metaDataKey not found") unless defined $metaDataDef;
return $theHideError?'':inlineError("can't find meta data definition for $metaDataKey") unless defined $metaDataDef;

my $formWeb = $this->{baseWeb};
my $formTopic = $metaDataDef->{form};
Expand All @@ -160,20 +232,41 @@ sub renderMetaData {

# unless (defined $formTopic) {
# print STDERR "error: no form definition found for metadata $metaDataKey\n";
# return inlineError("no form definition found for metadata $metaDataKey");
# return $theHideError?'':inlineError("no form definition found for metadata $metaDataKey");
# }

($formWeb, $formTopic) = Foswiki::Func::normalizeWebTopicName($formWeb, $formTopic);

#writeDebug("formWeb=$formWeb, formTopic=$formTopic");
my $wikiName = Foswiki::Func::getWikiName();
unless (Foswiki::Func::checkAccessPermission("VIEW", $wikiName, undef, $formWeb, $formTopic)) {
return $theHideError?'':inlineError("access denied to form definition for <nop>$metaDataKey");
}

unless (Foswiki::Func::topicExists($formWeb, $formTopic)) {
return inlineError("form definition for <nop>$metaDataKey not found");
return $theHideError?'':inlineError("form definition for <nop>$metaDataKey not found");
}

my $formDef = new Foswiki::Form($this->{session}, $formWeb, $formTopic);
my $formDef;
try {
$formDef = new Foswiki::Form($this->{session}, $formWeb, $formTopic);
} catch Error::Simple with {

# just in case, cus when this fails it takes down more of foswiki
Foswiki::Func::writeWarning("MetaDataPlugin::Core::renderMetaData() failed for $formWeb.$formTopic: ".shift);
} catch Foswiki::AccessControlException with {
# catch but simply bail out
#print STDERR "can't access form at $formWeb.$formTopic in renderMetaData()\n";

# SMELL: manually invalidate the forms cache for a partially build form object
if (exists $this->{session}{forms}{"$formWeb.$formTopic"}) {
#print STDERR "WARNING: bug present in Foswiki::Form - invalid form object found in cache - deleting it manually\n";
delete $this->{session}{forms}{"$formWeb.$formTopic"};
}
};

unless (defined $formDef) {
return inlineError("can't parse form definition at $formWeb.$formTopic");
return $theHideError?'':inlineError("can't parse form definition at $formWeb.$formTopic");
}

my @selectedFields = ();
Expand Down Expand Up @@ -296,8 +389,8 @@ sub renderMetaData {
my $name = $record->{name};
my $title = $name;

next if $theInclude && $name !~ /^($theInclude)$/;
next if $theExclude && $name =~ /^($theExclude)$/;
next if defined $theInclude && !defined($includeMap{$name});
next if defined $theExclude && $excludeMap{$name};

# loop over all fields of a record
foreach my $field (@selectedFields) {
Expand Down

0 comments on commit c7ecf38

Please sign in to comment.