diff options
Diffstat (limited to 'rt/lib/RT/CustomField_Overlay.pm')
-rw-r--r-- | rt/lib/RT/CustomField_Overlay.pm | 232 |
1 files changed, 213 insertions, 19 deletions
diff --git a/rt/lib/RT/CustomField_Overlay.pm b/rt/lib/RT/CustomField_Overlay.pm index 07a953c79..5a4535ebf 100644 --- a/rt/lib/RT/CustomField_Overlay.pm +++ b/rt/lib/RT/CustomField_Overlay.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -22,7 +22,9 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/copyleft/gpl.html. # # # CONTRIBUTION SUBMISSION POLICY: @@ -85,6 +87,11 @@ use RT::ObjectCustomFieldValues; 'Upload one file', # loc 'Upload up to [_1] files', # loc ], + Combobox => [ + 'Combobox: Select or enter multiple values', # loc + 'Combobox: Select or enter one value', # loc + 'Combobox: Select or enter up to [_1] values', # loc + ], ); @@ -194,8 +201,15 @@ sub Create { unless ( $queue->CurrentUserHasRight('AssignCustomFields') ) { return ( 0, $self->loc('Permission Denied') ); } - $args{'LookupType'} = 'RT::Queue-RT::Ticket'; + $args{'LookupType'} = 'RT::Queue-RT::Ticket'; + $args{'Queue'} = $queue->Id; + } + + my ($ok, $msg) = $self->_IsValidRegex($args{'Pattern'}); + if (!$ok) { + return (0, $self->loc("Invalid pattern: [_1]", $msg)); } + my $rv = $self->SUPER::Create( Name => $args{'Name'}, Type => $args{'Type'}, @@ -278,7 +292,7 @@ sub LoadByName { my $CFs = RT::CustomFields->new($self->CurrentUser); - $CFs->Limit( FIELD => 'Name', VALUE => $args{'Name'} ); + $CFs->Limit( FIELD => 'Name', VALUE => $args{'Name'}, CASESENSITIVE => 0); # Don't limit to queue if queue is 0. Trying to do so breaks # RT::Group type CFs. if (defined $args{'Queue'}) { @@ -356,11 +370,8 @@ ok ($delval,"Deleting a cf value: $delmsg"); =cut sub AddValue { - my $self = shift; - my %args = ( Name => undef, - Description => undef, - SortOrder => undef, - @_ ); + my $self = shift; + my %args = @_; unless ($self->CurrentUserHasRight('AdminCustomField')) { return (0, $self->loc('Permission Denied')); @@ -370,13 +381,9 @@ sub AddValue { if ( !defined $args{'Name'} || $args{'Name'} eq '' ) { return(0, $self->loc("Can't add a custom field value without a name")); } - my $newval = RT::CustomFieldValue->new($self->CurrentUser); - return($newval->Create( - CustomField => $self->Id, - Name =>$args{'Name'}, - Description => ($args{'Description'} || ''), - SortOrder => ($args{'SortOrder'} || '0') - )); + + my $newval = RT::CustomFieldValue->new($self->CurrentUser); + return($newval->Create(%args, CustomField => $self->Id)); } @@ -566,6 +573,22 @@ sub Types { # }}} +# {{{ IsSelectionType + +=head2 IsSelectionType + +Retuns a boolean value indicating whether the C<Values> method makes sense +to this Custom Field. + +=cut + +sub IsSelectionType { + my $self = shift; + $self->Type =~ /(?:Select|Combobox)/; +} + +# }}} + =head2 FriendlyType [TYPE, MAX_VALUES] @@ -638,6 +661,51 @@ sub SetType { $self->SUPER::SetType($type); } +=head2 SetPattern STRING + +Takes a single string representing a regular expression. Performs basic +validation on that regex, and sets the C<Pattern> field for the CF if it +is valid. + +=cut + +sub SetPattern { + my $self = shift; + my $regex = shift; + + my ($ok, $msg) = $self->_IsValidRegex($regex); + if ($ok) { + return $self->SUPER::SetPattern($regex); + } + else { + return (0, $self->loc("Invalid pattern: [_1]", $msg)); + } +} + +=head2 _IsValidRegex(Str $regex) returns (Bool $success, Str $msg) + +Tests if the string contains an invalid regex. + +=cut + +sub _IsValidRegex { + my $self = shift; + my $regex = shift or return (1, 'valid'); + + local $^W; local $@; + $SIG{__DIE__} = sub { 1 }; + $SIG{__WARN__} = sub { 1 }; + + if (eval { qr/$regex/; 1 }) { + return (1, 'valid'); + } + + my $err = $@; + $err =~ s{[,;].*}{}; # strip debug info from error + chomp $err; + return (0, $err); +} + # {{{ SingleValue =head2 SingleValue @@ -809,7 +877,7 @@ Returns an array of all possible composite values for custom fields. sub TypeComposites { my $self = shift; - return grep !/Text-0/, map { ("$_-1", "$_-0") } $self->Types; + return grep !/(?:[Tt]ext|Combobox)-0/, map { ("$_-1", "$_-0") } $self->Types; } =head2 LookupTypes @@ -952,6 +1020,10 @@ sub AddValueForObject { return ( 0, $self->loc('Permission Denied') ); } + unless ( $self->MatchPattern($args{Content}) ) { + return ( 0, $self->loc('Input must match [_1]', $self->FriendlyPattern) ); + } + $RT::Handle->BeginTransaction; my $current_values = $self->ValuesForObject($obj); @@ -1002,6 +1074,51 @@ sub AddValueForObject { # }}} +# {{{ MatchPattern + +=head2 MatchPattern STRING + +Tests the incoming string against the Pattern of this custom field object +and returns a boolean; returns true if the Pattern is empty. + +=cut + +sub MatchPattern { + my $self = shift; + my $regex = $self->Pattern; + + return 1 if !length($regex); + return ($_[0] =~ $regex); +} + + +# }}} + +# {{{ FriendlyPattern + +=head2 FriendlyPattern + +Prettify the pattern of this custom field, by taking the text in C<(?#text)> +and localizing it. + +=cut + +sub FriendlyPattern { + my $self = shift; + my $regex = $self->Pattern; + + return '' if !length($regex); + if ($regex =~ /\(\?#([^)]*)\)/) { + return '[' . $self->loc($1) . ']'; + } + else { + return $regex; + } +} + + +# }}} + # {{{ DeleteValueForObject =head2 DeleteValueForObject HASH @@ -1038,10 +1155,16 @@ sub DeleteValueForObject { } - # check ot make sure we found it + # check to make sure we found it unless ($oldval->Id) { return(0, $self->loc("Custom field value [_1] could not be found for custom field [_2]", $args{'Content'}, $self->Name)); } + + # for single-value fields, we need to validate that empty string is a valid value for it + if ( $self->SingleValue and not $self->MatchPattern( '' ) ) { + return ( 0, $self->loc('Input must match [_1]', $self->FriendlyPattern) ); + } + # delete it my $ret = $oldval->Delete(); @@ -1101,6 +1224,77 @@ sub _ForObjectType { } -# }}} +=head2 IncludeContentForValue [VALUE] (and SetIncludeContentForValue) + +Gets or sets the C<IncludeContentForValue> for this custom field. RT +uses this field to automatically include content into the user's browser +as they display records with custom fields in RT. + +=cut + +sub SetIncludeContentForValue { + shift->IncludeContentForValue(@_); +} +sub IncludeContentForValue{ + my $self = shift; + $self->_URLTemplate('IncludeContentForValue', @_); +} + + + +=head2 LinkValueTo [VALUE] (and SetLinkValueTo) + +Gets or sets the C<LinkValueTo> for this custom field. RT +uses this field to make custom field values into hyperlinks in the user's +browser as they display records with custom fields in RT. + +=cut + + +sub SetLinkValueTo { + shift->LinkValueTo(@_); +} + +sub LinkValueTo { + my $self = shift; + $self->_URLTemplate('LinkValueTo', @_); + +} + + +=head2 _URLTemplate NAME [VALUE] + +With one argument, returns the _URLTemplate named C<NAME>, but only if +the current user has the right to see this custom field. + +With two arguments, attemptes to set the relevant template value. + +=cut + + + +sub _URLTemplate { + my $self = shift; + my $template_name = shift; + if (@_) { + + my $value = shift; + unless ( $self->CurrentUserHasRight('AdminCustomField') ) { + return ( 0, $self->loc('Permission Denied') ); + } + $self->SetAttribute( Name => $template_name, Content => $value ); + return ( 1, $self->loc('Updated') ); + } else { + unless ( $self->id && $self->CurrentUserHasRight('SeeCustomField') ) { + return (undef); + } + + my @attr = $self->Attributes->Named($template_name); + my $attr = shift @attr; + + if ($attr) { return $attr->Content } + + } +} 1; |